4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
622 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623 * you may want to set this to true.
626 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631 * Selects a single element as a Roo Element
632 * This is about as close as you can get to jQuery's $('do crazy stuff')
633 * @param {String} selector The selector/xpath query
634 * @param {Node} root (optional) The start of the query (defaults to document).
635 * @return {Roo.Element}
637 selectNode : function(selector, root)
639 var node = Roo.DomQuery.selectNode(selector,root);
640 return node ? Roo.get(node) : new Roo.Element(false);
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
652 * Ext JS Library 1.1.1
653 * Copyright(c) 2006-2007, Ext JS, LLC.
655 * Originally Released Under LGPL - original licence link has changed is not relivant.
658 * <script type="text/javascript">
662 // wrappedn so fnCleanup is not in global scope...
664 function fnCleanUp() {
665 var p = Function.prototype;
666 delete p.createSequence;
668 delete p.createDelegate;
669 delete p.createCallback;
670 delete p.createInterceptor;
672 window.detachEvent("onunload", fnCleanUp);
674 window.attachEvent("onunload", fnCleanUp);
681 * These functions are available on every Function object (any JavaScript function).
683 Roo.apply(Function.prototype, {
685 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687 * Will create a function that is bound to those 2 args.
688 * @return {Function} The new function
690 createCallback : function(/*args...*/){
691 // make args available, in function below
692 var args = arguments;
695 return method.apply(window, args);
700 * Creates a delegate (callback) that sets the scope to obj.
701 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702 * Will create a function that is automatically scoped to this.
703 * @param {Object} obj (optional) The object for which the scope is set
704 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706 * if a number the args are inserted at the specified position
707 * @return {Function} The new function
709 createDelegate : function(obj, args, appendArgs){
712 var callArgs = args || arguments;
713 if(appendArgs === true){
714 callArgs = Array.prototype.slice.call(arguments, 0);
715 callArgs = callArgs.concat(args);
716 }else if(typeof appendArgs == "number"){
717 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
721 return method.apply(obj || window, callArgs);
726 * Calls this function after the number of millseconds specified.
727 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728 * @param {Object} obj (optional) The object for which the scope is set
729 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731 * if a number the args are inserted at the specified position
732 * @return {Number} The timeout id that can be used with clearTimeout
734 defer : function(millis, obj, args, appendArgs){
735 var fn = this.createDelegate(obj, args, appendArgs);
737 return setTimeout(fn, millis);
743 * Create a combined function call sequence of the original function + the passed function.
744 * The resulting function returns the results of the original function.
745 * The passed fcn is called with the parameters of the original function
746 * @param {Function} fcn The function to sequence
747 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748 * @return {Function} The new function
750 createSequence : function(fcn, scope){
751 if(typeof fcn != "function"){
756 var retval = method.apply(this || window, arguments);
757 fcn.apply(scope || this || window, arguments);
763 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function.
767 * @param {Function} fcn The function to call before the original
768 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769 * @return {Function} The new function
771 createInterceptor : function(fcn, scope){
772 if(typeof fcn != "function"){
779 if(fcn.apply(scope || this || window, arguments) === false){
782 return method.apply(this || window, arguments);
788 * Ext JS Library 1.1.1
789 * Copyright(c) 2006-2007, Ext JS, LLC.
791 * Originally Released Under LGPL - original licence link has changed is not relivant.
794 * <script type="text/javascript">
797 Roo.applyIf(String, {
802 * Escapes the passed string for ' and \
803 * @param {String} string The string to escape
804 * @return {String} The escaped string
807 escape : function(string) {
808 return string.replace(/('|\\)/g, "\\$1");
812 * Pads the left side of a string with a specified character. This is especially useful
813 * for normalizing number and date strings. Example usage:
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
818 * @param {String} string The original string
819 * @param {Number} size The total length of the output string
820 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821 * @return {String} The padded string
824 leftPad : function (val, size, ch) {
825 var result = new String(val);
826 if(ch === null || ch === undefined || ch === '') {
829 while (result.length < size) {
830 result = ch + result;
836 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
837 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
843 * @param {String} string The tokenized string to be formatted
844 * @param {String} value1 The value to replace token {0}
845 * @param {String} value2 Etc...
846 * @return {String} The formatted string
849 format : function(format){
850 var args = Array.prototype.slice.call(arguments, 1);
851 return format.replace(/\{(\d+)\}/g, function(m, i){
852 return Roo.util.Format.htmlEncode(args[i]);
858 * Utility function that allows you to easily switch a string between two alternating values. The passed value
859 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
860 * they are already different, the first value passed in is returned. Note that this method returns the new value
861 * but does not change the current string.
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
869 * @param {String} value The value to compare to the current string
870 * @param {String} other The new value to use if the string already equals the first value passed in
871 * @return {String} The new value
874 String.prototype.toggle = function(value, other){
875 return this == value ? other : value;
878 * Ext JS Library 1.1.1
879 * Copyright(c) 2006-2007, Ext JS, LLC.
881 * Originally Released Under LGPL - original licence link has changed is not relivant.
884 * <script type="text/javascript">
890 Roo.applyIf(Number.prototype, {
892 * Checks whether or not the current number is within a desired range. If the number is already within the
893 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894 * exceeded. Note that this method returns the constrained value but does not change the current number.
895 * @param {Number} min The minimum number in the range
896 * @param {Number} max The maximum number in the range
897 * @return {Number} The constrained value if outside the range, otherwise the current value
899 constrain : function(min, max){
900 return Math.min(Math.max(this, min), max);
904 * Ext JS Library 1.1.1
905 * Copyright(c) 2006-2007, Ext JS, LLC.
907 * Originally Released Under LGPL - original licence link has changed is not relivant.
910 * <script type="text/javascript">
915 Roo.applyIf(Array.prototype, {
917 * Checks whether or not the specified object exists in the array.
918 * @param {Object} o The object to check for
919 * @return {Number} The index of o in the array (or -1 if it is not found)
921 indexOf : function(o){
922 for (var i = 0, len = this.length; i < len; i++){
923 if(this[i] == o) return i;
929 * Removes the specified object from the array. If the object is not found nothing happens.
930 * @param {Object} o The object to remove
932 remove : function(o){
933 var index = this.indexOf(o);
935 this.splice(index, 1);
939 * Map (JS 1.6 compatibility)
940 * @param {Function} function to call
944 var len = this.length >>> 0;
945 if (typeof fun != "function")
946 throw new TypeError();
948 var res = new Array(len);
949 var thisp = arguments[1];
950 for (var i = 0; i < len; i++)
953 res[i] = fun.call(thisp, this[i], i, this);
964 * Ext JS Library 1.1.1
965 * Copyright(c) 2006-2007, Ext JS, LLC.
967 * Originally Released Under LGPL - original licence link has changed is not relivant.
970 * <script type="text/javascript">
976 * The date parsing and format syntax is a subset of
977 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978 * supported will provide results equivalent to their PHP versions.
980 * Following is the list of all currently supported formats:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
985 Format Output Description
986 ------ ---------- --------------------------------------------------------------
987 d 10 Day of the month, 2 digits with leading zeros
988 D Wed A textual representation of a day, three letters
989 j 10 Day of the month without leading zeros
990 l Wednesday A full textual representation of the day of the week
991 S th English ordinal day of month suffix, 2 chars (use with j)
992 w 3 Numeric representation of the day of the week
993 z 9 The julian date, or day of the year (0-365)
994 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995 F January A full textual representation of the month
996 m 01 Numeric representation of a month, with leading zeros
997 M Jan Month name abbreviation, three letters
998 n 1 Numeric representation of a month, without leading zeros
999 t 31 Number of days in the given month
1000 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1001 Y 2007 A full numeric representation of a year, 4 digits
1002 y 07 A two digit representation of a year
1003 a pm Lowercase Ante meridiem and Post meridiem
1004 A PM Uppercase Ante meridiem and Post meridiem
1005 g 3 12-hour format of an hour without leading zeros
1006 G 15 24-hour format of an hour without leading zeros
1007 h 03 12-hour format of an hour with leading zeros
1008 H 15 24-hour format of an hour with leading zeros
1009 i 05 Minutes with leading zeros
1010 s 01 Seconds, with leading zeros
1011 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1013 T CST Timezone setting of the machine running the code
1014 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1017 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d')); //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1025 * Here are some standard date/time patterns that you might find helpful. They
1026 * are not part of the source of Date.js, but to use them you can simply copy this
1027 * block of code into any script that is included after Date.js and they will also become
1028 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1031 ISO8601Long:"Y-m-d H:i:s",
1032 ISO8601Short:"Y-m-d",
1034 LongDate: "l, F d, Y",
1035 FullDateTime: "l, F d, Y g:i:s A",
1038 LongTime: "g:i:s A",
1039 SortableDateTime: "Y-m-d\\TH:i:s",
1040 UniversalSortableDateTime: "Y-m-d H:i:sO",
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1053 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054 * They generate precompiled functions from date formats instead of parsing and
1055 * processing the pattern every time you format a date. These functions are available
1056 * on every Date object (any javascript function).
1058 * The original article and download are here:
1059 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1066 Returns the number of milliseconds between this date and date
1067 @param {Date} date (optional) Defaults to now
1068 @return {Number} The diff in milliseconds
1069 @member Date getElapsed
1071 Date.prototype.getElapsed = function(date) {
1072 return Math.abs((date || new Date()).getTime()-this.getTime());
1074 // was in date file..
1078 Date.parseFunctions = {count:0};
1080 Date.parseRegexes = [];
1082 Date.formatFunctions = {count:0};
1085 Date.prototype.dateFormat = function(format) {
1086 if (Date.formatFunctions[format] == null) {
1087 Date.createNewFormat(format);
1089 var func = Date.formatFunctions[format];
1090 return this[func]();
1095 * Formats a date given the supplied format string
1096 * @param {String} format The format string
1097 * @return {String} The formatted date
1100 Date.prototype.format = Date.prototype.dateFormat;
1103 Date.createNewFormat = function(format) {
1104 var funcName = "format" + Date.formatFunctions.count++;
1105 Date.formatFunctions[format] = funcName;
1106 var code = "Date.prototype." + funcName + " = function(){return ";
1107 var special = false;
1109 for (var i = 0; i < format.length; ++i) {
1110 ch = format.charAt(i);
1111 if (!special && ch == "\\") {
1116 code += "'" + String.escape(ch) + "' + ";
1119 code += Date.getFormatCode(ch);
1122 /** eval:var:zzzzzzzzzzzzz */
1123 eval(code.substring(0, code.length - 3) + ";}");
1127 Date.getFormatCode = function(character) {
1128 switch (character) {
1130 return "String.leftPad(this.getDate(), 2, '0') + ";
1132 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1134 return "this.getDate() + ";
1136 return "Date.dayNames[this.getDay()] + ";
1138 return "this.getSuffix() + ";
1140 return "this.getDay() + ";
1142 return "this.getDayOfYear() + ";
1144 return "this.getWeekOfYear() + ";
1146 return "Date.monthNames[this.getMonth()] + ";
1148 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1150 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1152 return "(this.getMonth() + 1) + ";
1154 return "this.getDaysInMonth() + ";
1156 return "(this.isLeapYear() ? 1 : 0) + ";
1158 return "this.getFullYear() + ";
1160 return "('' + this.getFullYear()).substring(2, 4) + ";
1162 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1164 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1166 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1168 return "this.getHours() + ";
1170 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1172 return "String.leftPad(this.getHours(), 2, '0') + ";
1174 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1176 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1178 return "this.getGMTOffset() + ";
1180 return "this.getGMTColonOffset() + ";
1182 return "this.getTimezone() + ";
1184 return "(this.getTimezoneOffset() * -60) + ";
1186 return "'" + String.escape(character) + "' + ";
1191 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1193 * the date format that is not specified will default to the current date value for that part. Time parts can also
1194 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1195 * string or the parse operation will fail.
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1210 * @param {String} input The unparsed date as a string
1211 * @param {String} format The format the date is in
1212 * @return {Date} The parsed date
1215 Date.parseDate = function(input, format) {
1216 if (Date.parseFunctions[format] == null) {
1217 Date.createParser(format);
1219 var func = Date.parseFunctions[format];
1220 return Date[func](input);
1225 Date.createParser = function(format) {
1226 var funcName = "parse" + Date.parseFunctions.count++;
1227 var regexNum = Date.parseRegexes.length;
1228 var currentGroup = 1;
1229 Date.parseFunctions[format] = funcName;
1231 var code = "Date." + funcName + " = function(input){\n"
1232 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233 + "var d = new Date();\n"
1234 + "y = d.getFullYear();\n"
1235 + "m = d.getMonth();\n"
1236 + "d = d.getDate();\n"
1237 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238 + "if (results && results.length > 0) {";
1241 var special = false;
1243 for (var i = 0; i < format.length; ++i) {
1244 ch = format.charAt(i);
1245 if (!special && ch == "\\") {
1250 regex += String.escape(ch);
1253 var obj = Date.formatCodeToRegex(ch, currentGroup);
1254 currentGroup += obj.g;
1256 if (obj.g && obj.c) {
1262 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i, s);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267 + "{v = new Date(y, m, d, h);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269 + "{v = new Date(y, m, d);}\n"
1270 + "else if (y >= 0 && m >= 0)\n"
1271 + "{v = new Date(y, m);}\n"
1272 + "else if (y >= 0)\n"
1273 + "{v = new Date(y);}\n"
1274 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280 /** eval:var:zzzzzzzzzzzzz */
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286 switch (character) {
1290 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294 s:"(\\d{1,2})"}; // day of month without leading zeroes
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // day of month with leading zeroes
1302 s:"(?:" + Date.dayNames.join("|") + ")"};
1306 s:"(?:st|nd|rd|th)"};
1321 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322 s:"(" + Date.monthNames.join("|") + ")"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1345 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354 c:"if (results[" + currentGroup + "] == 'am') {\n"
1355 + "if (h == 12) { h = 0; }\n"
1356 + "} else { if (h < 12) { h += 12; }}",
1360 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361 + "if (h == 12) { h = 0; }\n"
1362 + "} else { if (h < 12) { h += 12; }}",
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1372 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1376 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385 "o = results[", currentGroup, "];\n",
1386 "var sn = o.substring(0,1);\n", // get + / - sign
1387 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1392 s:"([+\-]\\d{2,4})"};
1398 "o = results[", currentGroup, "];\n",
1399 "var sn = o.substring(0,1);\n",
1400 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401 "var mn = o.substring(4,6) % 60;\n",
1402 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418 s:String.escape(character)};
1423 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424 * @return {String} The abbreviated timezone name (e.g. 'CST')
1426 Date.prototype.getTimezone = function() {
1427 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1434 Date.prototype.getGMTOffset = function() {
1435 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442 * @return {String} 2-characters representing hours and 2-characters representing minutes
1443 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1445 Date.prototype.getGMTColonOffset = function() {
1446 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 * Get the numeric day number of the year, adjusted for leap year.
1454 * @return {Number} 0 through 364 (365 in leap years)
1456 Date.prototype.getDayOfYear = function() {
1458 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459 for (var i = 0; i < this.getMonth(); ++i) {
1460 num += Date.daysInMonth[i];
1462 return num + this.getDate() - 1;
1466 * Get the string representation of the numeric week number of the year
1467 * (equivalent to the format specifier 'W').
1468 * @return {String} '00' through '52'
1470 Date.prototype.getWeekOfYear = function() {
1471 // Skip to Thursday of this week
1472 var now = this.getDayOfYear() + (4 - this.getDay());
1473 // Find the first Thursday of the year
1474 var jan1 = new Date(this.getFullYear(), 0, 1);
1475 var then = (7 - jan1.getDay() + 4);
1476 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 * Whether or not the current date is in a leap year.
1481 * @return {Boolean} True if the current date is in a leap year, else false
1483 Date.prototype.isLeapYear = function() {
1484 var year = this.getFullYear();
1485 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 * Get the first day of the current month, adjusted for leap year. The returned value
1490 * is the numeric day index within the week (0-6) which can be used in conjunction with
1491 * the {@link #monthNames} array to retrieve the textual day name.
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1497 * @return {Number} The day number (0-6)
1499 Date.prototype.getFirstDayOfMonth = function() {
1500 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501 return (day < 0) ? (day + 7) : day;
1505 * Get the last day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getLastDayOfMonth = function() {
1516 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517 return (day < 0) ? (day + 7) : day;
1522 * Get the first date of this date's month
1525 Date.prototype.getFirstDateOfMonth = function() {
1526 return new Date(this.getFullYear(), this.getMonth(), 1);
1530 * Get the last date of this date's month
1533 Date.prototype.getLastDateOfMonth = function() {
1534 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 * Get the number of days in the current month, adjusted for leap year.
1538 * @return {Number} The number of days in the month
1540 Date.prototype.getDaysInMonth = function() {
1541 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542 return Date.daysInMonth[this.getMonth()];
1546 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547 * @return {String} 'st, 'nd', 'rd' or 'th'
1549 Date.prototype.getSuffix = function() {
1550 switch (this.getDate()) {
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570 * An array of textual month names.
1571 * Override these values for international dates, for example...
1572 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1591 * An array of textual day names.
1592 * Override these values for international dates, for example...
1593 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1609 Date.monthNumbers = {
1624 * Creates and returns a new Date instance with the exact same date value as the called instance.
1625 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626 * variable will also be changed. When the intention is to create a new variable that will not
1627 * modify the original instance, you should create a clone.
1629 * Example of correctly cloning a date:
1632 var orig = new Date('10/1/2006');
1635 document.write(orig); //returns 'Thu Oct 05 2006'!
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1641 document.write(orig); //returns 'Thu Oct 01 2006'
1643 * @return {Date} The new Date instance
1645 Date.prototype.clone = function() {
1646 return new Date(this.getTime());
1650 * Clears any time information from this date
1651 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652 @return {Date} this or the clone
1654 Date.prototype.clearTime = function(clone){
1656 return this.clone().clearTime();
1661 this.setMilliseconds(0);
1666 // safari setMonth is broken
1668 Date.brokenSetMonth = Date.prototype.setMonth;
1669 Date.prototype.setMonth = function(num){
1671 var n = Math.ceil(-num);
1672 var back_year = Math.ceil(n/12);
1673 var month = (n % 12) ? 12 - n % 12 : 0 ;
1674 this.setFullYear(this.getFullYear() - back_year);
1675 return Date.brokenSetMonth.call(this, month);
1677 return Date.brokenSetMonth.apply(this, arguments);
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1712 * Provides a convenient method of performing basic date arithmetic. This method
1713 * does not modify the Date instance being called - it creates and returns
1714 * a new Date instance containing the resulting date value.
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731 * @param {String} interval A valid date interval enum value
1732 * @param {Number} value The amount to add to the current date
1733 * @return {Date} The new Date instance
1735 Date.prototype.add = function(interval, value){
1736 var d = this.clone();
1737 if (!interval || value === 0) return d;
1738 switch(interval.toLowerCase()){
1740 d.setMilliseconds(this.getMilliseconds() + value);
1743 d.setSeconds(this.getSeconds() + value);
1746 d.setMinutes(this.getMinutes() + value);
1749 d.setHours(this.getHours() + value);
1752 d.setDate(this.getDate() + value);
1755 var day = this.getDate();
1757 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760 d.setMonth(this.getMonth() + value);
1763 d.setFullYear(this.getFullYear() + value);
1770 * Ext JS Library 1.1.1
1771 * Copyright(c) 2006-2007, Ext JS, LLC.
1773 * Originally Released Under LGPL - original licence link has changed is not relivant.
1776 * <script type="text/javascript">
1780 * @class Roo.lib.Dom
1783 * Dom utils (from YIU afaik)
1788 * Get the view width
1789 * @param {Boolean} full True will get the full document, otherwise it's the view width
1790 * @return {Number} The width
1793 getViewWidth : function(full) {
1794 return full ? this.getDocumentWidth() : this.getViewportWidth();
1797 * Get the view height
1798 * @param {Boolean} full True will get the full document, otherwise it's the view height
1799 * @return {Number} The height
1801 getViewHeight : function(full) {
1802 return full ? this.getDocumentHeight() : this.getViewportHeight();
1805 getDocumentHeight: function() {
1806 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807 return Math.max(scrollHeight, this.getViewportHeight());
1810 getDocumentWidth: function() {
1811 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812 return Math.max(scrollWidth, this.getViewportWidth());
1815 getViewportHeight: function() {
1816 var height = self.innerHeight;
1817 var mode = document.compatMode;
1819 if ((mode || Roo.isIE) && !Roo.isOpera) {
1820 height = (mode == "CSS1Compat") ?
1821 document.documentElement.clientHeight :
1822 document.body.clientHeight;
1828 getViewportWidth: function() {
1829 var width = self.innerWidth;
1830 var mode = document.compatMode;
1832 if (mode || Roo.isIE) {
1833 width = (mode == "CSS1Compat") ?
1834 document.documentElement.clientWidth :
1835 document.body.clientWidth;
1840 isAncestor : function(p, c) {
1847 if (p.contains && !Roo.isSafari) {
1848 return p.contains(c);
1849 } else if (p.compareDocumentPosition) {
1850 return !!(p.compareDocumentPosition(c) & 16);
1852 var parent = c.parentNode;
1857 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860 parent = parent.parentNode;
1866 getRegion : function(el) {
1867 return Roo.lib.Region.getRegion(el);
1870 getY : function(el) {
1871 return this.getXY(el)[1];
1874 getX : function(el) {
1875 return this.getXY(el)[0];
1878 getXY : function(el) {
1879 var p, pe, b, scroll, bd = document.body;
1880 el = Roo.getDom(el);
1881 var fly = Roo.lib.AnimBase.fly;
1882 if (el.getBoundingClientRect) {
1883 b = el.getBoundingClientRect();
1884 scroll = fly(document).getScroll();
1885 return [b.left + scroll.left, b.top + scroll.top];
1891 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1898 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1905 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1913 if (p != el && pe.getStyle('overflow') != 'visible') {
1921 if (Roo.isSafari && hasAbsolute) {
1926 if (Roo.isGecko && !hasAbsolute) {
1928 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933 while (p && p != bd) {
1934 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1946 setXY : function(el, xy) {
1947 el = Roo.fly(el, '_setXY');
1949 var pts = el.translatePoints(xy);
1950 if (xy[0] !== false) {
1951 el.dom.style.left = pts.left + "px";
1953 if (xy[1] !== false) {
1954 el.dom.style.top = pts.top + "px";
1958 setX : function(el, x) {
1959 this.setXY(el, [x, false]);
1962 setY : function(el, y) {
1963 this.setXY(el, [false, y]);
1967 * Portions of this file are based on pieces of Yahoo User Interface Library
1968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969 * YUI licensed under the BSD License:
1970 * http://developer.yahoo.net/yui/license.txt
1971 * <script type="text/javascript">
1975 Roo.lib.Event = function() {
1976 var loadComplete = false;
1978 var unloadListeners = [];
1980 var onAvailStack = [];
1982 var lastError = null;
1995 startInterval: function() {
1996 if (!this._interval) {
1998 var callback = function() {
1999 self._tryPreloadAttach();
2001 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007 onAvailStack.push({ id: p_id,
2010 override: p_override,
2011 checkReady: false });
2013 retryCount = this.POLL_RETRYS;
2014 this.startInterval();
2018 addListener: function(el, eventName, fn) {
2019 el = Roo.getDom(el);
2024 if ("unload" == eventName) {
2025 unloadListeners[unloadListeners.length] =
2026 [el, eventName, fn];
2030 var wrappedFn = function(e) {
2031 return fn(Roo.lib.Event.getEvent(e));
2034 var li = [el, eventName, fn, wrappedFn];
2036 var index = listeners.length;
2037 listeners[index] = li;
2039 this.doAdd(el, eventName, wrappedFn, false);
2045 removeListener: function(el, eventName, fn) {
2048 el = Roo.getDom(el);
2051 return this.purgeElement(el, false, eventName);
2055 if ("unload" == eventName) {
2057 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058 var li = unloadListeners[i];
2061 li[1] == eventName &&
2063 unloadListeners.splice(i, 1);
2071 var cacheItem = null;
2074 var index = arguments[3];
2076 if ("undefined" == typeof index) {
2077 index = this._getCacheIndex(el, eventName, fn);
2081 cacheItem = listeners[index];
2084 if (!el || !cacheItem) {
2088 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2090 delete listeners[index][this.WFN];
2091 delete listeners[index][this.FN];
2092 listeners.splice(index, 1);
2099 getTarget: function(ev, resolveTextNode) {
2100 ev = ev.browserEvent || ev;
2101 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2102 var t = ev.target || ev.srcElement;
2103 return this.resolveTextNode(t);
2107 resolveTextNode: function(node) {
2108 if (Roo.isSafari && node && 3 == node.nodeType) {
2109 return node.parentNode;
2116 getPageX: function(ev) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2120 if (!x && 0 !== x) {
2121 x = ev.clientX || 0;
2124 x += this.getScroll()[1];
2132 getPageY: function(ev) {
2133 ev = ev.browserEvent || ev;
2134 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2136 if (!y && 0 !== y) {
2137 y = ev.clientY || 0;
2140 y += this.getScroll()[0];
2149 getXY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 return [this.getPageX(ev), this.getPageY(ev)];
2156 getRelatedTarget: function(ev) {
2157 ev = ev.browserEvent || ev;
2158 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 var t = ev.relatedTarget;
2161 if (ev.type == "mouseout") {
2163 } else if (ev.type == "mouseover") {
2168 return this.resolveTextNode(t);
2172 getTime: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = new Date().getTime();
2180 this.lastError = ex;
2189 stopEvent: function(ev) {
2190 this.stopPropagation(ev);
2191 this.preventDefault(ev);
2195 stopPropagation: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 if (ev.stopPropagation) {
2198 ev.stopPropagation();
2200 ev.cancelBubble = true;
2205 preventDefault: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if(ev.preventDefault) {
2208 ev.preventDefault();
2210 ev.returnValue = false;
2215 getEvent: function(e) {
2216 var ev = e || window.event;
2218 var c = this.getEvent.caller;
2220 ev = c.arguments[0];
2221 if (ev && Event == ev.constructor) {
2231 getCharCode: function(ev) {
2232 ev = ev.browserEvent || ev;
2233 return ev.charCode || ev.keyCode || 0;
2237 _getCacheIndex: function(el, eventName, fn) {
2238 for (var i = 0,len = listeners.length; i < len; ++i) {
2239 var li = listeners[i];
2241 li[this.FN] == fn &&
2242 li[this.EL] == el &&
2243 li[this.TYPE] == eventName) {
2255 getEl: function(id) {
2256 return document.getElementById(id);
2260 clearCache: function() {
2264 _load: function(e) {
2265 loadComplete = true;
2266 var EU = Roo.lib.Event;
2270 EU.doRemove(window, "load", EU._load);
2275 _tryPreloadAttach: function() {
2284 var tryAgain = !loadComplete;
2286 tryAgain = (retryCount > 0);
2291 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292 var item = onAvailStack[i];
2294 var el = this.getEl(item.id);
2297 if (!item.checkReady ||
2300 (document && document.body)) {
2303 if (item.override) {
2304 if (item.override === true) {
2307 scope = item.override;
2310 item.fn.call(scope, item.obj);
2311 onAvailStack[i] = null;
2314 notAvail.push(item);
2319 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323 this.startInterval();
2325 clearInterval(this._interval);
2326 this._interval = null;
2329 this.locked = false;
2336 purgeElement: function(el, recurse, eventName) {
2337 var elListeners = this.getListeners(el, eventName);
2339 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340 var l = elListeners[i];
2341 this.removeListener(el, l.type, l.fn);
2345 if (recurse && el && el.childNodes) {
2346 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347 this.purgeElement(el.childNodes[i], recurse, eventName);
2353 getListeners: function(el, eventName) {
2354 var results = [], searchLists;
2356 searchLists = [listeners, unloadListeners];
2357 } else if (eventName == "unload") {
2358 searchLists = [unloadListeners];
2360 searchLists = [listeners];
2363 for (var j = 0; j < searchLists.length; ++j) {
2364 var searchList = searchLists[j];
2365 if (searchList && searchList.length > 0) {
2366 for (var i = 0,len = searchList.length; i < len; ++i) {
2367 var l = searchList[i];
2368 if (l && l[this.EL] === el &&
2369 (!eventName || eventName === l[this.TYPE])) {
2374 adjust: l[this.ADJ_SCOPE],
2382 return (results.length) ? results : null;
2386 _unload: function(e) {
2388 var EU = Roo.lib.Event, i, j, l, len, index;
2390 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391 l = unloadListeners[i];
2394 if (l[EU.ADJ_SCOPE]) {
2395 if (l[EU.ADJ_SCOPE] === true) {
2398 scope = l[EU.ADJ_SCOPE];
2401 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402 unloadListeners[i] = null;
2408 unloadListeners = null;
2410 if (listeners && listeners.length > 0) {
2411 j = listeners.length;
2414 l = listeners[index];
2416 EU.removeListener(l[EU.EL], l[EU.TYPE],
2426 EU.doRemove(window, "unload", EU._unload);
2431 getScroll: function() {
2432 var dd = document.documentElement, db = document.body;
2433 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434 return [dd.scrollTop, dd.scrollLeft];
2436 return [db.scrollTop, db.scrollLeft];
2443 doAdd: function () {
2444 if (window.addEventListener) {
2445 return function(el, eventName, fn, capture) {
2446 el.addEventListener(eventName, fn, (capture));
2448 } else if (window.attachEvent) {
2449 return function(el, eventName, fn, capture) {
2450 el.attachEvent("on" + eventName, fn);
2459 doRemove: function() {
2460 if (window.removeEventListener) {
2461 return function (el, eventName, fn, capture) {
2462 el.removeEventListener(eventName, fn, (capture));
2464 } else if (window.detachEvent) {
2465 return function (el, eventName, fn) {
2466 el.detachEvent("on" + eventName, fn);
2478 var E = Roo.lib.Event;
2479 E.on = E.addListener;
2480 E.un = E.removeListener;
2482 if (document && document.body) {
2485 E.doAdd(window, "load", E._load);
2487 E.doAdd(window, "unload", E._unload);
2488 E._tryPreloadAttach();
2492 * Portions of this file are based on pieces of Yahoo User Interface Library
2493 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494 * YUI licensed under the BSD License:
2495 * http://developer.yahoo.net/yui/license.txt
2496 * <script type="text/javascript">
2502 * @class Roo.lib.Ajax
2509 request : function(method, uri, cb, data, options) {
2511 var hs = options.headers;
2514 if(hs.hasOwnProperty(h)){
2515 this.initHeader(h, hs[h], false);
2519 if(options.xmlData){
2520 this.initHeader('Content-Type', 'text/xml', false);
2522 data = options.xmlData;
2526 return this.asyncRequest(method, uri, cb, data);
2529 serializeForm : function(form) {
2530 if(typeof form == 'string') {
2531 form = (document.getElementById(form) || document.forms[form]);
2534 var el, name, val, disabled, data = '', hasSubmit = false;
2535 for (var i = 0; i < form.elements.length; i++) {
2536 el = form.elements[i];
2537 disabled = form.elements[i].disabled;
2538 name = form.elements[i].name;
2539 val = form.elements[i].value;
2541 if (!disabled && name){
2545 case 'select-multiple':
2546 for (var j = 0; j < el.options.length; j++) {
2547 if (el.options[j].selected) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2560 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573 if(hasSubmit == false) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584 data = data.substr(0, data.length - 1);
2592 useDefaultHeader:true,
2594 defaultPostHeader:'application/x-www-form-urlencoded',
2596 useDefaultXhrHeader:true,
2598 defaultXhrHeader:'XMLHttpRequest',
2600 hasDefaultHeaders:true,
2612 setProgId:function(id)
2614 this.activeX.unshift(id);
2617 setDefaultPostHeader:function(b)
2619 this.useDefaultHeader = b;
2622 setDefaultXhrHeader:function(b)
2624 this.useDefaultXhrHeader = b;
2627 setPollingInterval:function(i)
2629 if (typeof i == 'number' && isFinite(i)) {
2630 this.pollInterval = i;
2634 createXhrObject:function(transactionId)
2640 http = new XMLHttpRequest();
2642 obj = { conn:http, tId:transactionId };
2646 for (var i = 0; i < this.activeX.length; ++i) {
2650 http = new ActiveXObject(this.activeX[i]);
2652 obj = { conn:http, tId:transactionId };
2665 getConnectionObject:function()
2668 var tId = this.transactionId;
2672 o = this.createXhrObject(tId);
2674 this.transactionId++;
2685 asyncRequest:function(method, uri, callback, postData)
2687 var o = this.getConnectionObject();
2693 o.conn.open(method, uri, true);
2695 if (this.useDefaultXhrHeader) {
2696 if (!this.defaultHeaders['X-Requested-With']) {
2697 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701 if(postData && this.useDefaultHeader){
2702 this.initHeader('Content-Type', this.defaultPostHeader);
2705 if (this.hasDefaultHeaders || this.hasHeaders) {
2709 this.handleReadyState(o, callback);
2710 o.conn.send(postData || null);
2716 handleReadyState:function(o, callback)
2720 if (callback && callback.timeout) {
2722 this.timeout[o.tId] = window.setTimeout(function() {
2723 oConn.abort(o, callback, true);
2724 }, callback.timeout);
2727 this.poll[o.tId] = window.setInterval(
2729 if (o.conn && o.conn.readyState == 4) {
2730 window.clearInterval(oConn.poll[o.tId]);
2731 delete oConn.poll[o.tId];
2733 if(callback && callback.timeout) {
2734 window.clearTimeout(oConn.timeout[o.tId]);
2735 delete oConn.timeout[o.tId];
2738 oConn.handleTransactionResponse(o, callback);
2741 , this.pollInterval);
2744 handleTransactionResponse:function(o, callback, isAbort)
2748 this.releaseObject(o);
2752 var httpStatus, responseObject;
2756 if (o.conn.status !== undefined && o.conn.status != 0) {
2757 httpStatus = o.conn.status;
2769 if (httpStatus >= 200 && httpStatus < 300) {
2770 responseObject = this.createResponseObject(o, callback.argument);
2771 if (callback.success) {
2772 if (!callback.scope) {
2773 callback.success(responseObject);
2778 callback.success.apply(callback.scope, [responseObject]);
2783 switch (httpStatus) {
2791 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792 if (callback.failure) {
2793 if (!callback.scope) {
2794 callback.failure(responseObject);
2797 callback.failure.apply(callback.scope, [responseObject]);
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.failure) {
2804 if (!callback.scope) {
2805 callback.failure(responseObject);
2808 callback.failure.apply(callback.scope, [responseObject]);
2814 this.releaseObject(o);
2815 responseObject = null;
2818 createResponseObject:function(o, callbackArg)
2825 var headerStr = o.conn.getAllResponseHeaders();
2826 var header = headerStr.split('\n');
2827 for (var i = 0; i < header.length; i++) {
2828 var delimitPos = header[i].indexOf(':');
2829 if (delimitPos != -1) {
2830 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2838 obj.status = o.conn.status;
2839 obj.statusText = o.conn.statusText;
2840 obj.getResponseHeader = headerObj;
2841 obj.getAllResponseHeaders = headerStr;
2842 obj.responseText = o.conn.responseText;
2843 obj.responseXML = o.conn.responseXML;
2845 if (typeof callbackArg !== undefined) {
2846 obj.argument = callbackArg;
2852 createExceptionObject:function(tId, callbackArg, isAbort)
2855 var COMM_ERROR = 'communication failure';
2856 var ABORT_CODE = -1;
2857 var ABORT_ERROR = 'transaction aborted';
2863 obj.status = ABORT_CODE;
2864 obj.statusText = ABORT_ERROR;
2867 obj.status = COMM_CODE;
2868 obj.statusText = COMM_ERROR;
2872 obj.argument = callbackArg;
2878 initHeader:function(label, value, isDefault)
2880 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2882 if (headerObj[label] === undefined) {
2883 headerObj[label] = value;
2888 headerObj[label] = value + "," + headerObj[label];
2892 this.hasDefaultHeaders = true;
2895 this.hasHeaders = true;
2900 setHeader:function(o)
2902 if (this.hasDefaultHeaders) {
2903 for (var prop in this.defaultHeaders) {
2904 if (this.defaultHeaders.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910 if (this.hasHeaders) {
2911 for (var prop in this.headers) {
2912 if (this.headers.hasOwnProperty(prop)) {
2913 o.conn.setRequestHeader(prop, this.headers[prop]);
2917 this.hasHeaders = false;
2921 resetDefaultHeaders:function() {
2922 delete this.defaultHeaders;
2923 this.defaultHeaders = {};
2924 this.hasDefaultHeaders = false;
2927 abort:function(o, callback, isTimeout)
2929 if(this.isCallInProgress(o)) {
2931 window.clearInterval(this.poll[o.tId]);
2932 delete this.poll[o.tId];
2934 delete this.timeout[o.tId];
2937 this.handleTransactionResponse(o, callback, true);
2947 isCallInProgress:function(o)
2950 return o.conn.readyState != 4 && o.conn.readyState != 0;
2959 releaseObject:function(o)
2968 'MSXML2.XMLHTTP.3.0',
2976 * Portions of this file are based on pieces of Yahoo User Interface Library
2977 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978 * YUI licensed under the BSD License:
2979 * http://developer.yahoo.net/yui/license.txt
2980 * <script type="text/javascript">
2984 Roo.lib.Region = function(t, r, b, l) {
2994 Roo.lib.Region.prototype = {
2995 contains : function(region) {
2996 return ( region.left >= this.left &&
2997 region.right <= this.right &&
2998 region.top >= this.top &&
2999 region.bottom <= this.bottom );
3003 getArea : function() {
3004 return ( (this.bottom - this.top) * (this.right - this.left) );
3007 intersect : function(region) {
3008 var t = Math.max(this.top, region.top);
3009 var r = Math.min(this.right, region.right);
3010 var b = Math.min(this.bottom, region.bottom);
3011 var l = Math.max(this.left, region.left);
3013 if (b >= t && r >= l) {
3014 return new Roo.lib.Region(t, r, b, l);
3019 union : function(region) {
3020 var t = Math.min(this.top, region.top);
3021 var r = Math.max(this.right, region.right);
3022 var b = Math.max(this.bottom, region.bottom);
3023 var l = Math.min(this.left, region.left);
3025 return new Roo.lib.Region(t, r, b, l);
3028 adjust : function(t, l, b, r) {
3037 Roo.lib.Region.getRegion = function(el) {
3038 var p = Roo.lib.Dom.getXY(el);
3041 var r = p[0] + el.offsetWidth;
3042 var b = p[1] + el.offsetHeight;
3045 return new Roo.lib.Region(t, r, b, l);
3048 * Portions of this file are based on pieces of Yahoo User Interface Library
3049 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050 * YUI licensed under the BSD License:
3051 * http://developer.yahoo.net/yui/license.txt
3052 * <script type="text/javascript">
3055 //@@dep Roo.lib.Region
3058 Roo.lib.Point = function(x, y) {
3059 if (x instanceof Array) {
3063 this.x = this.right = this.left = this[0] = x;
3064 this.y = this.top = this.bottom = this[1] = y;
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3069 * Portions of this file are based on pieces of Yahoo User Interface Library
3070 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071 * YUI licensed under the BSD License:
3072 * http://developer.yahoo.net/yui/license.txt
3073 * <script type="text/javascript">
3080 scroll : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084 motion : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088 color : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092 run : function(el, args, duration, easing, cb, scope, type) {
3093 type = type || Roo.lib.AnimBase;
3094 if (typeof easing == "string") {
3095 easing = Roo.lib.Easing[easing];
3097 var anim = new type(el, args, duration, easing);
3098 anim.animateX(function() {
3099 Roo.callback(cb, scope);
3105 * Portions of this file are based on pieces of Yahoo User Interface Library
3106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107 * YUI licensed under the BSD License:
3108 * http://developer.yahoo.net/yui/license.txt
3109 * <script type="text/javascript">
3117 if (!libFlyweight) {
3118 libFlyweight = new Roo.Element.Flyweight();
3120 libFlyweight.dom = el;
3121 return libFlyweight;
3124 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3130 this.init(el, attributes, duration, method);
3134 Roo.lib.AnimBase.fly = fly;
3138 Roo.lib.AnimBase.prototype = {
3140 toString: function() {
3141 var el = this.getEl();
3142 var id = el.id || el.tagName;
3143 return ("Anim " + id);
3147 noNegatives: /width|height|opacity|padding/i,
3148 offsetAttribute: /^((width|height)|(top|left))$/,
3149 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3150 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154 doMethod: function(attr, start, end) {
3155 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159 setAttribute: function(attr, val, unit) {
3160 if (this.patterns.noNegatives.test(attr)) {
3161 val = (val > 0) ? val : 0;
3164 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168 getAttribute: function(attr) {
3169 var el = this.getEl();
3170 var val = fly(el).getStyle(attr);
3172 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173 return parseFloat(val);
3176 var a = this.patterns.offsetAttribute.exec(attr) || [];
3177 var pos = !!( a[3] );
3178 var box = !!( a[2] );
3181 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3191 getDefaultUnit: function(attr) {
3192 if (this.patterns.defaultUnit.test(attr)) {
3199 animateX : function(callback, scope) {
3200 var f = function() {
3201 this.onComplete.removeListener(f);
3202 if (typeof callback == "function") {
3203 callback.call(scope || this, this);
3206 this.onComplete.addListener(f, this);
3211 setRuntimeAttribute: function(attr) {
3214 var attributes = this.attributes;
3216 this.runtimeAttributes[attr] = {};
3218 var isset = function(prop) {
3219 return (typeof prop !== 'undefined');
3222 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229 if (isset(attributes[attr]['to'])) {
3230 end = attributes[attr]['to'];
3231 } else if (isset(attributes[attr]['by'])) {
3232 if (start.constructor == Array) {
3234 for (var i = 0, len = start.length; i < len; ++i) {
3235 end[i] = start[i] + attributes[attr]['by'][i];
3238 end = start + attributes[attr]['by'];
3242 this.runtimeAttributes[attr].start = start;
3243 this.runtimeAttributes[attr].end = end;
3246 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250 init: function(el, attributes, duration, method) {
3252 var isAnimated = false;
3255 var startTime = null;
3258 var actualFrames = 0;
3261 el = Roo.getDom(el);
3264 this.attributes = attributes || {};
3267 this.duration = duration || 1;
3270 this.method = method || Roo.lib.Easing.easeNone;
3273 this.useSeconds = true;
3276 this.currentFrame = 0;
3279 this.totalFrames = Roo.lib.AnimMgr.fps;
3282 this.getEl = function() {
3287 this.isAnimated = function() {
3292 this.getStartTime = function() {
3296 this.runtimeAttributes = {};
3299 this.animate = function() {
3300 if (this.isAnimated()) {
3304 this.currentFrame = 0;
3306 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3308 Roo.lib.AnimMgr.registerElement(this);
3312 this.stop = function(finish) {
3314 this.currentFrame = this.totalFrames;
3315 this._onTween.fire();
3317 Roo.lib.AnimMgr.stop(this);
3320 var onStart = function() {
3321 this.onStart.fire();
3323 this.runtimeAttributes = {};
3324 for (var attr in this.attributes) {
3325 this.setRuntimeAttribute(attr);
3330 startTime = new Date();
3334 var onTween = function() {
3336 duration: new Date() - this.getStartTime(),
3337 currentFrame: this.currentFrame
3340 data.toString = function() {
3342 'duration: ' + data.duration +
3343 ', currentFrame: ' + data.currentFrame
3347 this.onTween.fire(data);
3349 var runtimeAttributes = this.runtimeAttributes;
3351 for (var attr in runtimeAttributes) {
3352 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3358 var onComplete = function() {
3359 var actual_duration = (new Date() - startTime) / 1000 ;
3362 duration: actual_duration,
3363 frames: actualFrames,
3364 fps: actualFrames / actual_duration
3367 data.toString = function() {
3369 'duration: ' + data.duration +
3370 ', frames: ' + data.frames +
3371 ', fps: ' + data.fps
3377 this.onComplete.fire(data);
3381 this._onStart = new Roo.util.Event(this);
3382 this.onStart = new Roo.util.Event(this);
3383 this.onTween = new Roo.util.Event(this);
3384 this._onTween = new Roo.util.Event(this);
3385 this.onComplete = new Roo.util.Event(this);
3386 this._onComplete = new Roo.util.Event(this);
3387 this._onStart.addListener(onStart);
3388 this._onTween.addListener(onTween);
3389 this._onComplete.addListener(onComplete);
3394 * Portions of this file are based on pieces of Yahoo User Interface Library
3395 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396 * YUI licensed under the BSD License:
3397 * http://developer.yahoo.net/yui/license.txt
3398 * <script type="text/javascript">
3402 Roo.lib.AnimMgr = new function() {
3419 this.registerElement = function(tween) {
3420 queue[queue.length] = tween;
3422 tween._onStart.fire();
3427 this.unRegister = function(tween, index) {
3428 tween._onComplete.fire();
3429 index = index || getIndex(tween);
3431 queue.splice(index, 1);
3435 if (tweenCount <= 0) {
3441 this.start = function() {
3442 if (thread === null) {
3443 thread = setInterval(this.run, this.delay);
3448 this.stop = function(tween) {
3450 clearInterval(thread);
3452 for (var i = 0, len = queue.length; i < len; ++i) {
3453 if (queue[0].isAnimated()) {
3454 this.unRegister(queue[0], 0);
3463 this.unRegister(tween);
3468 this.run = function() {
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 var tween = queue[i];
3471 if (!tween || !tween.isAnimated()) {
3475 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3477 tween.currentFrame += 1;
3479 if (tween.useSeconds) {
3480 correctFrame(tween);
3482 tween._onTween.fire();
3485 Roo.lib.AnimMgr.stop(tween, i);
3490 var getIndex = function(anim) {
3491 for (var i = 0, len = queue.length; i < len; ++i) {
3492 if (queue[i] == anim) {
3500 var correctFrame = function(tween) {
3501 var frames = tween.totalFrames;
3502 var frame = tween.currentFrame;
3503 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504 var elapsed = (new Date() - tween.getStartTime());
3507 if (elapsed < tween.duration * 1000) {
3508 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3510 tweak = frames - (frame + 1);
3512 if (tweak > 0 && isFinite(tweak)) {
3513 if (tween.currentFrame + tweak >= frames) {
3514 tweak = frames - (frame + 1);
3517 tween.currentFrame += tweak;
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3530 Roo.lib.Bezier = new function() {
3532 this.getPosition = function(points, t) {
3533 var n = points.length;
3536 for (var i = 0; i < n; ++i) {
3537 tmp[i] = [points[i][0], points[i][1]];
3540 for (var j = 1; j < n; ++j) {
3541 for (i = 0; i < n - j; ++i) {
3542 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547 return [ tmp[0][0], tmp[0][1] ];
3551 * Portions of this file are based on pieces of Yahoo User Interface Library
3552 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553 * YUI licensed under the BSD License:
3554 * http://developer.yahoo.net/yui/license.txt
3555 * <script type="text/javascript">
3560 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3566 var fly = Roo.lib.AnimBase.fly;
3568 var superclass = Y.ColorAnim.superclass;
3569 var proto = Y.ColorAnim.prototype;
3571 proto.toString = function() {
3572 var el = this.getEl();
3573 var id = el.id || el.tagName;
3574 return ("ColorAnim " + id);
3577 proto.patterns.color = /color$/i;
3578 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584 proto.parseColor = function(s) {
3585 if (s.length == 3) {
3589 var c = this.patterns.hex.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594 c = this.patterns.rgb.exec(s);
3595 if (c && c.length == 4) {
3596 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599 c = this.patterns.hex3.exec(s);
3600 if (c && c.length == 4) {
3601 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607 proto.getAttribute = function(attr) {
3608 var el = this.getEl();
3609 if (this.patterns.color.test(attr)) {
3610 var val = fly(el).getStyle(attr);
3612 if (this.patterns.transparent.test(val)) {
3613 var parent = el.parentNode;
3614 val = fly(parent).getStyle(attr);
3616 while (parent && this.patterns.transparent.test(val)) {
3617 parent = parent.parentNode;
3618 val = fly(parent).getStyle(attr);
3619 if (parent.tagName.toUpperCase() == 'HTML') {
3625 val = superclass.getAttribute.call(this, attr);
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3654 proto.doMethod = function(attr, start, end) {
3657 if (this.patterns.color.test(attr)) {
3659 for (var i = 0, len = start.length; i < len; ++i) {
3660 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666 val = superclass.doMethod.call(this, attr, start, end);
3672 proto.setRuntimeAttribute = function(attr) {
3673 superclass.setRuntimeAttribute.call(this, attr);
3675 if (this.patterns.color.test(attr)) {
3676 var attributes = this.attributes;
3677 var start = this.parseColor(this.runtimeAttributes[attr].start);
3678 var end = this.parseColor(this.runtimeAttributes[attr].end);
3680 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681 end = this.parseColor(attributes[attr].by);
3683 for (var i = 0, len = start.length; i < len; ++i) {
3684 end[i] = start[i] + end[i];
3688 this.runtimeAttributes[attr].start = start;
3689 this.runtimeAttributes[attr].end = end;
3695 * Portions of this file are based on pieces of Yahoo User Interface Library
3696 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697 * YUI licensed under the BSD License:
3698 * http://developer.yahoo.net/yui/license.txt
3699 * <script type="text/javascript">
3705 easeNone: function (t, b, c, d) {
3706 return c * t / d + b;
3710 easeIn: function (t, b, c, d) {
3711 return c * (t /= d) * t + b;
3715 easeOut: function (t, b, c, d) {
3716 return -c * (t /= d) * (t - 2) + b;
3720 easeBoth: function (t, b, c, d) {
3721 if ((t /= d / 2) < 1) {
3722 return c / 2 * t * t + b;
3725 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729 easeInStrong: function (t, b, c, d) {
3730 return c * (t /= d) * t * t * t + b;
3734 easeOutStrong: function (t, b, c, d) {
3735 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739 easeBothStrong: function (t, b, c, d) {
3740 if ((t /= d / 2) < 1) {
3741 return c / 2 * t * t * t * t + b;
3744 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749 elasticIn: function (t, b, c, d, a, p) {
3753 if ((t /= d) == 1) {
3760 if (!a || a < Math.abs(c)) {
3765 var s = p / (2 * Math.PI) * Math.asin(c / a);
3768 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772 elasticOut: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795 elasticBoth: function (t, b, c, d, a, p) {
3800 if ((t /= d / 2) == 2) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3817 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3820 return a * Math.pow(2, -10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826 backIn: function (t, b, c, d, s) {
3827 if (typeof s == 'undefined') {
3830 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834 backOut: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842 backBoth: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3847 if ((t /= d / 2 ) < 1) {
3848 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3850 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854 bounceIn: function (t, b, c, d) {
3855 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859 bounceOut: function (t, b, c, d) {
3860 if ((t /= d) < (1 / 2.75)) {
3861 return c * (7.5625 * t * t) + b;
3862 } else if (t < (2 / 2.75)) {
3863 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864 } else if (t < (2.5 / 2.75)) {
3865 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3867 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871 bounceBoth: function (t, b, c, d) {
3873 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3875 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878 * Portions of this file are based on pieces of Yahoo User Interface Library
3879 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880 * YUI licensed under the BSD License:
3881 * http://developer.yahoo.net/yui/license.txt
3882 * <script type="text/javascript">
3886 Roo.lib.Motion = function(el, attributes, duration, method) {
3888 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896 var superclass = Y.Motion.superclass;
3897 var proto = Y.Motion.prototype;
3899 proto.toString = function() {
3900 var el = this.getEl();
3901 var id = el.id || el.tagName;
3902 return ("Motion " + id);
3905 proto.patterns.points = /^points$/i;
3907 proto.setAttribute = function(attr, val, unit) {
3908 if (this.patterns.points.test(attr)) {
3909 unit = unit || 'px';
3910 superclass.setAttribute.call(this, 'left', val[0], unit);
3911 superclass.setAttribute.call(this, 'top', val[1], unit);
3913 superclass.setAttribute.call(this, attr, val, unit);
3917 proto.getAttribute = function(attr) {
3918 if (this.patterns.points.test(attr)) {
3920 superclass.getAttribute.call(this, 'left'),
3921 superclass.getAttribute.call(this, 'top')
3924 val = superclass.getAttribute.call(this, attr);
3930 proto.doMethod = function(attr, start, end) {
3933 if (this.patterns.points.test(attr)) {
3934 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3937 val = superclass.doMethod.call(this, attr, start, end);
3942 proto.setRuntimeAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3944 var el = this.getEl();
3945 var attributes = this.attributes;
3947 var control = attributes['points']['control'] || [];
3951 if (control.length > 0 && !(control[0] instanceof Array)) {
3952 control = [control];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 tmp[i] = control[i];
3961 Roo.fly(el).position();
3963 if (isset(attributes['points']['from'])) {
3964 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970 start = this.getAttribute('points');
3973 if (isset(attributes['points']['to'])) {
3974 end = translateValues.call(this, attributes['points']['to'], start);
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 for (i = 0,len = control.length; i < len; ++i) {
3978 control[i] = translateValues.call(this, control[i], start);
3982 } else if (isset(attributes['points']['by'])) {
3983 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990 this.runtimeAttributes[attr] = [start];
3992 if (control.length > 0) {
3993 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999 superclass.setRuntimeAttribute.call(this, attr);
4003 var translateValues = function(val, start) {
4004 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010 var isset = function(prop) {
4011 return (typeof prop !== 'undefined');
4015 * Portions of this file are based on pieces of Yahoo User Interface Library
4016 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017 * YUI licensed under the BSD License:
4018 * http://developer.yahoo.net/yui/license.txt
4019 * <script type="text/javascript">
4023 Roo.lib.Scroll = function(el, attributes, duration, method) {
4025 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033 var superclass = Y.Scroll.superclass;
4034 var proto = Y.Scroll.prototype;
4036 proto.toString = function() {
4037 var el = this.getEl();
4038 var id = el.id || el.tagName;
4039 return ("Scroll " + id);
4042 proto.doMethod = function(attr, start, end) {
4045 if (attr == 'scroll') {
4047 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052 val = superclass.doMethod.call(this, attr, start, end);
4057 proto.getAttribute = function(attr) {
4059 var el = this.getEl();
4061 if (attr == 'scroll') {
4062 val = [ el.scrollLeft, el.scrollTop ];
4064 val = superclass.getAttribute.call(this, attr);
4070 proto.setAttribute = function(attr, val, unit) {
4071 var el = this.getEl();
4073 if (attr == 'scroll') {
4074 el.scrollLeft = val[0];
4075 el.scrollTop = val[1];
4077 superclass.setAttribute.call(this, attr, val, unit);
4083 * Ext JS Library 1.1.1
4084 * Copyright(c) 2006-2007, Ext JS, LLC.
4086 * Originally Released Under LGPL - original licence link has changed is not relivant.
4089 * <script type="text/javascript">
4093 // nasty IE9 hack - what a pile of crap that is..
4095 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096 Range.prototype.createContextualFragment = function (html) {
4097 var doc = window.document;
4098 var container = doc.createElement("div");
4099 container.innerHTML = html;
4100 var frag = doc.createDocumentFragment(), n;
4101 while ((n = container.firstChild)) {
4102 frag.appendChild(n);
4109 * @class Roo.DomHelper
4110 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4114 Roo.DomHelper = function(){
4115 var tempTableEl = null;
4116 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117 var tableRe = /^table|tbody|tr|td$/i;
4119 // build as innerHTML where available
4121 var createHtml = function(o){
4122 if(typeof o == 'string'){
4131 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132 if(attr == "style"){
4134 if(typeof s == "function"){
4137 if(typeof s == "string"){
4138 b += ' style="' + s + '"';
4139 }else if(typeof s == "object"){
4142 if(typeof s[key] != "function"){
4143 b += key + ":" + s[key] + ";";
4150 b += ' class="' + o["cls"] + '"';
4151 }else if(attr == "htmlFor"){
4152 b += ' for="' + o["htmlFor"] + '"';
4154 b += " " + attr + '="' + o[attr] + '"';
4158 if(emptyTags.test(o.tag)){
4162 var cn = o.children || o.cn;
4164 //http://bugs.kde.org/show_bug.cgi?id=71506
4165 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166 for(var i = 0, len = cn.length; i < len; i++) {
4167 b += createHtml(cn[i], b);
4170 b += createHtml(cn, b);
4176 b += "</" + o.tag + ">";
4183 var createDom = function(o, parentNode){
4185 // defininition craeted..
4187 if (o.ns && o.ns != 'html') {
4189 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190 xmlns[o.ns] = o.xmlns;
4193 if (typeof(xmlns[o.ns]) == 'undefined') {
4194 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4200 if (typeof(o) == 'string') {
4201 return parentNode.appendChild(document.createTextNode(o));
4203 o.tag = o.tag || div;
4204 if (o.ns && Roo.isIE) {
4206 o.tag = o.ns + ':' + o.tag;
4209 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4210 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4214 attr == "style" || typeof o[attr] == "function") continue;
4216 if(attr=="cls" && Roo.isIE){
4217 el.className = o["cls"];
4219 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220 else el[attr] = o[attr];
4223 Roo.DomHelper.applyStyles(el, o.style);
4224 var cn = o.children || o.cn;
4226 //http://bugs.kde.org/show_bug.cgi?id=71506
4227 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228 for(var i = 0, len = cn.length; i < len; i++) {
4229 createDom(cn[i], el);
4236 el.innerHTML = o.html;
4239 parentNode.appendChild(el);
4244 var ieTable = function(depth, s, h, e){
4245 tempTableEl.innerHTML = [s, h, e].join('');
4246 var i = -1, el = tempTableEl;
4253 // kill repeat to save bytes
4257 tbe = '</tbody>'+te,
4263 * Nasty code for IE's broken table implementation
4265 var insertIntoTable = function(tag, where, el, html){
4267 tempTableEl = document.createElement('div');
4272 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275 if(where == 'beforebegin'){
4279 before = el.nextSibling;
4282 node = ieTable(4, trs, html, tre);
4284 else if(tag == 'tr'){
4285 if(where == 'beforebegin'){
4288 node = ieTable(3, tbs, html, tbe);
4289 } else if(where == 'afterend'){
4290 before = el.nextSibling;
4292 node = ieTable(3, tbs, html, tbe);
4293 } else{ // INTO a TR
4294 if(where == 'afterbegin'){
4295 before = el.firstChild;
4297 node = ieTable(4, trs, html, tre);
4299 } else if(tag == 'tbody'){
4300 if(where == 'beforebegin'){
4303 node = ieTable(2, ts, html, te);
4304 } else if(where == 'afterend'){
4305 before = el.nextSibling;
4307 node = ieTable(2, ts, html, te);
4309 if(where == 'afterbegin'){
4310 before = el.firstChild;
4312 node = ieTable(3, tbs, html, tbe);
4315 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318 if(where == 'afterbegin'){
4319 before = el.firstChild;
4321 node = ieTable(2, ts, html, te);
4323 el.insertBefore(node, before);
4328 /** True to force the use of DOM instead of html fragments @type Boolean */
4332 * Returns the markup for the passed Element(s) config
4333 * @param {Object} o The Dom object spec (and children)
4336 markup : function(o){
4337 return createHtml(o);
4341 * Applies a style specification to an element
4342 * @param {String/HTMLElement} el The element to apply styles to
4343 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344 * a function which returns such a specification.
4346 applyStyles : function(el, styles){
4349 if(typeof styles == "string"){
4350 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4352 while ((matches = re.exec(styles)) != null){
4353 el.setStyle(matches[1], matches[2]);
4355 }else if (typeof styles == "object"){
4356 for (var style in styles){
4357 el.setStyle(style, styles[style]);
4359 }else if (typeof styles == "function"){
4360 Roo.DomHelper.applyStyles(el, styles.call());
4366 * Inserts an HTML fragment into the Dom
4367 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368 * @param {HTMLElement} el The context element
4369 * @param {String} html The HTML fragmenet
4370 * @return {HTMLElement} The new node
4372 insertHtml : function(where, el, html){
4373 where = where.toLowerCase();
4374 if(el.insertAdjacentHTML){
4375 if(tableRe.test(el.tagName)){
4377 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4383 el.insertAdjacentHTML('BeforeBegin', html);
4384 return el.previousSibling;
4386 el.insertAdjacentHTML('AfterBegin', html);
4387 return el.firstChild;
4389 el.insertAdjacentHTML('BeforeEnd', html);
4390 return el.lastChild;
4392 el.insertAdjacentHTML('AfterEnd', html);
4393 return el.nextSibling;
4395 throw 'Illegal insertion point -> "' + where + '"';
4397 var range = el.ownerDocument.createRange();
4401 range.setStartBefore(el);
4402 frag = range.createContextualFragment(html);
4403 el.parentNode.insertBefore(frag, el);
4404 return el.previousSibling;
4407 range.setStartBefore(el.firstChild);
4408 frag = range.createContextualFragment(html);
4409 el.insertBefore(frag, el.firstChild);
4410 return el.firstChild;
4412 el.innerHTML = html;
4413 return el.firstChild;
4417 range.setStartAfter(el.lastChild);
4418 frag = range.createContextualFragment(html);
4419 el.appendChild(frag);
4420 return el.lastChild;
4422 el.innerHTML = html;
4423 return el.lastChild;
4426 range.setStartAfter(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el.nextSibling);
4429 return el.nextSibling;
4431 throw 'Illegal insertion point -> "' + where + '"';
4435 * Creates new Dom element(s) and inserts them before el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertBefore : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "beforeBegin");
4446 * Creates new Dom element(s) and inserts them after el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object} o The Dom object spec (and children)
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertAfter : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457 * Creates new Dom element(s) and inserts them as the first child of el
4458 * @param {String/HTMLElement/Element} el The context element
4459 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461 * @return {HTMLElement/Roo.Element} The new node
4463 insertFirst : function(el, o, returnElement){
4464 return this.doInsert(el, o, returnElement, "afterBegin");
4468 doInsert : function(el, o, returnElement, pos, sibling){
4469 el = Roo.getDom(el);
4471 if(this.useDom || o.ns){
4472 newNode = createDom(o, null);
4473 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4475 var html = createHtml(o);
4476 newNode = this.insertHtml(pos, el, html);
4478 return returnElement ? Roo.get(newNode, true) : newNode;
4482 * Creates new Dom element(s) and appends them to el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 append : function(el, o, returnElement){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.appendChild(newNode);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml("beforeEnd", el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and overwrites the contents of el with them
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 overwrite : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4512 while (el.childNodes.length) {
4513 el.removeChild(el.firstChild);
4517 el.innerHTML = createHtml(o);
4520 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524 * Creates a new Roo.DomHelper.Template from the Dom object spec
4525 * @param {Object} o The Dom object spec (and children)
4526 * @return {Roo.DomHelper.Template} The new template
4528 createTemplate : function(o){
4529 var html = createHtml(o);
4530 return new Roo.Template(html);
4536 * Ext JS Library 1.1.1
4537 * Copyright(c) 2006-2007, Ext JS, LLC.
4539 * Originally Released Under LGPL - original licence link has changed is not relivant.
4542 * <script type="text/javascript">
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 var t = new Roo.Template({
4552 html : '<div name="{id}">' +
4553 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4555 myformat: function (value, allValues) {
4556 return 'XX' + value;
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4561 * For more information see this blog post with examples:
4562 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563 - Create Elements using DOM, HTML fragments and Templates</a>.
4565 * @param {Object} cfg - Configuration object.
4567 Roo.Template = function(cfg){
4569 if(cfg instanceof Array){
4571 }else if(arguments.length > 1){
4572 cfg = Array.prototype.join.call(arguments, "");
4576 if (typeof(cfg) == 'object') {
4587 Roo.Template.prototype = {
4590 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591 * it should be fixed so that template is observable...
4595 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599 * Returns an HTML fragment of this template with the specified values applied.
4600 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601 * @return {String} The HTML fragment
4603 applyTemplate : function(values){
4607 return this.compiled(values);
4609 var useF = this.disableFormats !== true;
4610 var fm = Roo.util.Format, tpl = this;
4611 var fn = function(m, name, format, args){
4613 if(format.substr(0, 5) == "this."){
4614 return tpl.call(format.substr(5), values[name], values);
4617 // quoted values are required for strings in compiled templates,
4618 // but for non compiled we need to strip them
4619 // quoted reversed for jsmin
4620 var re = /^\s*['"](.*)["']\s*$/;
4621 args = args.split(',');
4622 for(var i = 0, len = args.length; i < len; i++){
4623 args[i] = args[i].replace(re, "$1");
4625 args = [values[name]].concat(args);
4627 args = [values[name]];
4629 return fm[format].apply(fm, args);
4632 return values[name] !== undefined ? values[name] : "";
4635 return this.html.replace(this.re, fn);
4653 this.loading = true;
4654 this.compiled = false;
4656 var cx = new Roo.data.Connection();
4660 success : function (response) {
4662 _t.html = response.responseText;
4666 failure : function(response) {
4667 Roo.log("Template failed to load from " + _t.url);
4674 * Sets the HTML used as the template and optionally compiles it.
4675 * @param {String} html
4676 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677 * @return {Roo.Template} this
4679 set : function(html, compile){
4681 this.compiled = null;
4689 * True to disable format functions (defaults to false)
4692 disableFormats : false,
4695 * The regular expression used to match template variables
4699 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702 * Compiles the template into an internal function, eliminating the RegEx overhead.
4703 * @return {Roo.Template} this
4705 compile : function(){
4706 var fm = Roo.util.Format;
4707 var useF = this.disableFormats !== true;
4708 var sep = Roo.isGecko ? "+" : ",";
4709 var fn = function(m, name, format, args){
4711 args = args ? ',' + args : "";
4712 if(format.substr(0, 5) != "this."){
4713 format = "fm." + format + '(';
4715 format = 'this.call("'+ format.substr(5) + '", ';
4719 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4721 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724 // branched to use + in gecko and [].join() in others
4726 body = "this.compiled = function(values){ return '" +
4727 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730 body = ["this.compiled = function(values){ return ['"];
4731 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732 body.push("'].join('');};");
4733 body = body.join('');
4743 // private function used to call members
4744 call : function(fnName, value, allValues){
4745 return this[fnName](value, allValues);
4749 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertFirst: function(el, values, returnElement){
4756 return this.doInsert('afterBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) before el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertBefore: function(el, values, returnElement){
4767 return this.doInsert('beforeBegin', el, values, returnElement);
4771 * Applies the supplied values to the template and inserts the new node(s) after el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 insertAfter : function(el, values, returnElement){
4778 return this.doInsert('afterEnd', el, values, returnElement);
4782 * Applies the supplied values to the template and appends the new node(s) to el.
4783 * @param {String/HTMLElement/Roo.Element} el The context element
4784 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786 * @return {HTMLElement/Roo.Element} The new node or Element
4788 append : function(el, values, returnElement){
4789 return this.doInsert('beforeEnd', el, values, returnElement);
4792 doInsert : function(where, el, values, returnEl){
4793 el = Roo.getDom(el);
4794 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795 return returnEl ? Roo.get(newNode, true) : newNode;
4799 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800 * @param {String/HTMLElement/Roo.Element} el The context element
4801 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803 * @return {HTMLElement/Roo.Element} The new node or Element
4805 overwrite : function(el, values, returnElement){
4806 el = Roo.getDom(el);
4807 el.innerHTML = this.applyTemplate(values);
4808 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812 * Alias for {@link #applyTemplate}
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818 Roo.DomHelper.Template = Roo.Template;
4821 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822 * @param {String/HTMLElement} el A DOM element or its id
4823 * @returns {Roo.Template} The created template
4826 Roo.Template.from = function(el){
4827 el = Roo.getDom(el);
4828 return new Roo.Template(el.value || el.innerHTML);
4831 * Ext JS Library 1.1.1
4832 * Copyright(c) 2006-2007, Ext JS, LLC.
4834 * Originally Released Under LGPL - original licence link has changed is not relivant.
4837 * <script type="text/javascript">
4842 * This is code is also distributed under MIT license for use
4843 * with jQuery and prototype JavaScript libraries.
4846 * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4854 <h4>Element Selectors:</h4>
4856 <li> <b>*</b> any element</li>
4857 <li> <b>E</b> an element with the tag E</li>
4858 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4866 <li> <b>E[foo]</b> has an attribute "foo"</li>
4867 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4874 <h4>Pseudo Classes:</h4>
4876 <li> <b>E:first-child</b> E is the first child of its parent</li>
4877 <li> <b>E:last-child</b> E is the last child of its parent</li>
4878 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881 <li> <b>E:only-child</b> E is the only child of its parent</li>
4882 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883 <li> <b>E:first</b> the first E in the resultset</li>
4884 <li> <b>E:last</b> the last E in the resultset</li>
4885 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4895 <h4>CSS Value Selectors:</h4>
4897 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 Roo.DomQuery = function(){
4907 var cache = {}, simpleCache = {}, valueCache = {};
4908 var nonSpace = /\S/;
4909 var trimRe = /^\s+|\s+$/g;
4910 var tplRe = /\{(\d+)\}/g;
4911 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912 var tagTokenRe = /^(#)?([\w-\*]+)/;
4913 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4915 function child(p, index){
4917 var n = p.firstChild;
4919 if(n.nodeType == 1){
4930 while((n = n.nextSibling) && n.nodeType != 1);
4935 while((n = n.previousSibling) && n.nodeType != 1);
4939 function children(d){
4940 var n = d.firstChild, ni = -1;
4942 var nx = n.nextSibling;
4943 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4953 function byClassName(c, a, v){
4957 var r = [], ri = -1, cn;
4958 for(var i = 0, ci; ci = c[i]; i++){
4959 if((' '+ci.className+' ').indexOf(v) != -1){
4966 function attrValue(n, attr){
4967 if(!n.tagName && typeof n.length != "undefined"){
4976 if(attr == "class" || attr == "className"){
4979 return n.getAttribute(attr) || n[attr];
4983 function getNodes(ns, mode, tagName){
4984 var result = [], ri = -1, cs;
4988 tagName = tagName || "*";
4989 if(typeof ns.getElementsByTagName != "undefined"){
4993 for(var i = 0, ni; ni = ns[i]; i++){
4994 cs = ni.getElementsByTagName(tagName);
4995 for(var j = 0, ci; ci = cs[j]; j++){
4999 }else if(mode == "/" || mode == ">"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, ni, cn; ni = ns[i]; i++){
5002 cn = ni.children || ni.childNodes;
5003 for(var j = 0, cj; cj = cn[j]; j++){
5004 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5009 }else if(mode == "+"){
5010 var utag = tagName.toUpperCase();
5011 for(var i = 0, n; n = ns[i]; i++){
5012 while((n = n.nextSibling) && n.nodeType != 1);
5013 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017 }else if(mode == "~"){
5018 for(var i = 0, n; n = ns[i]; i++){
5019 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028 function concat(a, b){
5032 for(var i = 0, l = b.length; i < l; i++){
5038 function byTag(cs, tagName){
5039 if(cs.tagName || cs == document){
5045 var r = [], ri = -1;
5046 tagName = tagName.toLowerCase();
5047 for(var i = 0, ci; ci = cs[i]; i++){
5048 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5055 function byId(cs, attr, id){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 for(var i = 0,ci; ci = cs[i]; i++){
5064 if(ci && ci.id == id){
5072 function byAttribute(cs, attr, value, op, custom){
5073 var r = [], ri = -1, st = custom=="{";
5074 var f = Roo.DomQuery.operators[op];
5075 for(var i = 0, ci; ci = cs[i]; i++){
5078 a = Roo.DomQuery.getStyle(ci, attr);
5080 else if(attr == "class" || attr == "className"){
5082 }else if(attr == "for"){
5084 }else if(attr == "href"){
5085 a = ci.getAttribute("href", 2);
5087 a = ci.getAttribute(attr);
5089 if((f && f(a, value)) || (!f && a)){
5096 function byPseudo(cs, name, value){
5097 return Roo.DomQuery.pseudos[name](cs, value);
5100 // This is for IE MSXML which does not support expandos.
5101 // IE runs the same speed using setAttribute, however FF slows way down
5102 // and Safari completely fails so they need to continue to use expandos.
5103 var isIE = window.ActiveXObject ? true : false;
5105 // this eval is stop the compressor from
5106 // renaming the variable to something shorter
5108 /** eval:var:batch */
5113 function nodupIEXml(cs){
5115 cs[0].setAttribute("_nodup", d);
5117 for(var i = 1, len = cs.length; i < len; i++){
5119 if(!c.getAttribute("_nodup") != d){
5120 c.setAttribute("_nodup", d);
5124 for(var i = 0, len = cs.length; i < len; i++){
5125 cs[i].removeAttribute("_nodup");
5134 var len = cs.length, c, i, r = cs, cj, ri = -1;
5135 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139 return nodupIEXml(cs);
5143 for(i = 1; c = cs[i]; i++){
5148 for(var j = 0; j < i; j++){
5151 for(j = i+1; cj = cs[j]; j++){
5163 function quickDiffIEXml(c1, c2){
5165 for(var i = 0, len = c1.length; i < len; i++){
5166 c1[i].setAttribute("_qdiff", d);
5169 for(var i = 0, len = c2.length; i < len; i++){
5170 if(c2[i].getAttribute("_qdiff") != d){
5171 r[r.length] = c2[i];
5174 for(var i = 0, len = c1.length; i < len; i++){
5175 c1[i].removeAttribute("_qdiff");
5180 function quickDiff(c1, c2){
5181 var len1 = c1.length;
5185 if(isIE && c1[0].selectSingleNode){
5186 return quickDiffIEXml(c1, c2);
5189 for(var i = 0; i < len1; i++){
5193 for(var i = 0, len = c2.length; i < len; i++){
5194 if(c2[i]._qdiff != d){
5195 r[r.length] = c2[i];
5201 function quickId(ns, mode, root, id){
5203 var d = root.ownerDocument || root;
5204 return d.getElementById(id);
5206 ns = getNodes(ns, mode, "*");
5207 return byId(ns, null, id);
5211 getStyle : function(el, name){
5212 return Roo.fly(el).getStyle(name);
5215 * Compiles a selector/xpath query into a reusable function. The returned function
5216 * takes one parameter "root" (optional), which is the context node from where the query should start.
5217 * @param {String} selector The selector/xpath query
5218 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219 * @return {Function}
5221 compile : function(path, type){
5222 type = type || "select";
5224 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225 var q = path, mode, lq;
5226 var tk = Roo.DomQuery.matchers;
5227 var tklen = tk.length;
5230 // accept leading mode switch
5231 var lmode = q.match(modeRe);
5232 if(lmode && lmode[1]){
5233 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234 q = q.replace(lmode[1], "");
5236 // strip leading slashes
5237 while(path.substr(0, 1)=="/"){
5238 path = path.substr(1);
5241 while(q && lq != q){
5243 var tm = q.match(tagTokenRe);
5244 if(type == "select"){
5247 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5252 }else if(q.substr(0, 1) != '@'){
5253 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5260 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5262 q = q.replace(tm[0], "");
5265 while(!(mm = q.match(modeRe))){
5266 var matched = false;
5267 for(var j = 0; j < tklen; j++){
5269 var m = q.match(t.re);
5271 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274 q = q.replace(m[0], "");
5279 // prevent infinite loop on bad selector
5281 throw 'Error parsing selector, parsing failed at "' + q + '"';
5285 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286 q = q.replace(mm[1], "");
5289 fn[fn.length] = "return nodup(n);\n}";
5292 * list of variables that need from compression as they are used by eval.
5302 * eval:var:byClassName
5304 * eval:var:byAttribute
5305 * eval:var:attrValue
5313 * Selects a group of elements.
5314 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315 * @param {Node} root (optional) The start of the query (defaults to document).
5318 select : function(path, root, type){
5319 if(!root || root == document){
5322 if(typeof root == "string"){
5323 root = document.getElementById(root);
5325 var paths = path.split(",");
5327 for(var i = 0, len = paths.length; i < len; i++){
5328 var p = paths[i].replace(trimRe, "");
5330 cache[p] = Roo.DomQuery.compile(p);
5332 throw p + " is not a valid selector";
5335 var result = cache[p](root);
5336 if(result && result != document){
5337 results = results.concat(result);
5340 if(paths.length > 1){
5341 return nodup(results);
5347 * Selects a single element.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 selectNode : function(path, root){
5353 return Roo.DomQuery.select(path, root)[0];
5357 * Selects the value of a node, optionally replacing null with the defaultValue.
5358 * @param {String} selector The selector/xpath query
5359 * @param {Node} root (optional) The start of the query (defaults to document).
5360 * @param {String} defaultValue
5362 selectValue : function(path, root, defaultValue){
5363 path = path.replace(trimRe, "");
5364 if(!valueCache[path]){
5365 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367 var n = valueCache[path](root);
5368 n = n[0] ? n[0] : n;
5369 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5370 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374 * Selects the value of a node, parsing integers and floats.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {Number} defaultValue
5380 selectNumber : function(path, root, defaultValue){
5381 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5382 return parseFloat(v);
5386 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5387 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5388 * @param {String} selector The simple selector to test
5391 is : function(el, ss){
5392 if(typeof el == "string"){
5393 el = document.getElementById(el);
5395 var isArray = (el instanceof Array);
5396 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5397 return isArray ? (result.length == el.length) : (result.length > 0);
5401 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5402 * @param {Array} el An array of elements to filter
5403 * @param {String} selector The simple selector to test
5404 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5405 * the selector instead of the ones that match
5408 filter : function(els, ss, nonMatches){
5409 ss = ss.replace(trimRe, "");
5410 if(!simpleCache[ss]){
5411 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413 var result = simpleCache[ss](els);
5414 return nonMatches ? quickDiff(result, els) : result;
5418 * Collection of matching regular expressions and code snippets.
5422 select: 'n = byClassName(n, null, " {1} ");'
5424 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5425 select: 'n = byPseudo(n, "{1}", "{2}");'
5427 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5428 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431 select: 'n = byId(n, null, "{1}");'
5434 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5440 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5443 "=" : function(a, v){
5446 "!=" : function(a, v){
5449 "^=" : function(a, v){
5450 return a && a.substr(0, v.length) == v;
5452 "$=" : function(a, v){
5453 return a && a.substr(a.length-v.length) == v;
5455 "*=" : function(a, v){
5456 return a && a.indexOf(v) !== -1;
5458 "%=" : function(a, v){
5459 return (a % v) == 0;
5461 "|=" : function(a, v){
5462 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464 "~=" : function(a, v){
5465 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5471 * and the argument (if any) supplied in the selector.
5474 "first-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.previousSibling) && n.nodeType != 1);
5485 "last-child" : function(c){
5486 var r = [], ri = -1, n;
5487 for(var i = 0, ci; ci = n = c[i]; i++){
5488 while((n = n.nextSibling) && n.nodeType != 1);
5496 "nth-child" : function(c, a) {
5497 var r = [], ri = -1;
5498 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5499 var f = (m[1] || 1) - 0, l = m[2] - 0;
5500 for(var i = 0, n; n = c[i]; i++){
5501 var pn = n.parentNode;
5502 if (batch != pn._batch) {
5504 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5505 if(cn.nodeType == 1){
5512 if (l == 0 || n.nodeIndex == l){
5515 } else if ((n.nodeIndex + l) % f == 0){
5523 "only-child" : function(c){
5524 var r = [], ri = -1;;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if(!prev(ci) && !next(ci)){
5533 "empty" : function(c){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 var cns = ci.childNodes, j = 0, cn, empty = true;
5539 if(cn.nodeType == 1 || cn.nodeType == 3){
5551 "contains" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561 "nodeValue" : function(c, v){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.firstChild && ci.firstChild.nodeValue == v){
5571 "checked" : function(c){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if(ci.checked == true){
5581 "not" : function(c, ss){
5582 return Roo.DomQuery.filter(c, ss, true);
5585 "odd" : function(c){
5586 return this["nth-child"](c, "odd");
5589 "even" : function(c){
5590 return this["nth-child"](c, "even");
5593 "nth" : function(c, a){
5594 return c[a-1] || [];
5597 "first" : function(c){
5601 "last" : function(c){
5602 return c[c.length-1] || [];
5605 "has" : function(c, ss){
5606 var s = Roo.DomQuery.select;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5609 if(s(ss, ci).length > 0){
5616 "next" : function(c, ss){
5617 var is = Roo.DomQuery.is;
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5628 "prev" : function(c, ss){
5629 var is = Roo.DomQuery.is;
5630 var r = [], ri = -1;
5631 for(var i = 0, ci; ci = c[i]; i++){
5644 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5645 * @param {String} path The selector/xpath query
5646 * @param {Node} root (optional) The start of the query (defaults to document).
5651 Roo.query = Roo.DomQuery.select;
5654 * Ext JS Library 1.1.1
5655 * Copyright(c) 2006-2007, Ext JS, LLC.
5657 * Originally Released Under LGPL - original licence link has changed is not relivant.
5660 * <script type="text/javascript">
5664 * @class Roo.util.Observable
5665 * Base class that provides a common interface for publishing events. Subclasses are expected to
5666 * to have a property "events" with all the events defined.<br>
5669 Employee = function(name){
5676 Roo.extend(Employee, Roo.util.Observable);
5678 * @param {Object} config properties to use (incuding events / listeners)
5681 Roo.util.Observable = function(cfg){
5684 this.addEvents(cfg.events || {});
5686 delete cfg.events; // make sure
5689 Roo.apply(this, cfg);
5692 this.on(this.listeners);
5693 delete this.listeners;
5696 Roo.util.Observable.prototype = {
5698 * @cfg {Object} listeners list of events and functions to call for this object,
5702 'click' : function(e) {
5712 * Fires the specified event with the passed parameters (minus the event name).
5713 * @param {String} eventName
5714 * @param {Object...} args Variable number of parameters are passed to handlers
5715 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717 fireEvent : function(){
5718 var ce = this.events[arguments[0].toLowerCase()];
5719 if(typeof ce == "object"){
5720 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730 * Appends an event handler to this component
5731 * @param {String} eventName The type of event to listen for
5732 * @param {Function} handler The method the event invokes
5733 * @param {Object} scope (optional) The scope in which to execute the handler
5734 * function. The handler function's "this" context.
5735 * @param {Object} options (optional) An object containing handler configuration
5736 * properties. This may contain any of the following properties:<ul>
5737 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5738 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5739 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5740 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5741 * by the specified number of milliseconds. If the event fires again within that time, the original
5742 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745 * <b>Combining Options</b><br>
5746 * Using the options argument, it is possible to combine different types of listeners:<br>
5748 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750 el.on('click', this.onClick, this, {
5757 * <b>Attaching multiple handlers in 1 call</b><br>
5758 * The method also allows for a single argument to be passed which is a config object containing properties
5759 * which specify multiple handlers.
5768 fn: this.onMouseOver,
5772 fn: this.onMouseOut,
5778 * Or a shorthand syntax which passes the same scope object to all handlers:
5781 'click': this.onClick,
5782 'mouseover': this.onMouseOver,
5783 'mouseout': this.onMouseOut,
5788 addListener : function(eventName, fn, scope, o){
5789 if(typeof eventName == "object"){
5792 if(this.filterOptRe.test(e)){
5795 if(typeof o[e] == "function"){
5797 this.addListener(e, o[e], o.scope, o);
5799 // individual options
5800 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805 o = (!o || typeof o == "boolean") ? {} : o;
5806 eventName = eventName.toLowerCase();
5807 var ce = this.events[eventName] || true;
5808 if(typeof ce == "boolean"){
5809 ce = new Roo.util.Event(this, eventName);
5810 this.events[eventName] = ce;
5812 ce.addListener(fn, scope, o);
5816 * Removes a listener
5817 * @param {String} eventName The type of event to listen for
5818 * @param {Function} handler The handler to remove
5819 * @param {Object} scope (optional) The scope (this object) for the handler
5821 removeListener : function(eventName, fn, scope){
5822 var ce = this.events[eventName.toLowerCase()];
5823 if(typeof ce == "object"){
5824 ce.removeListener(fn, scope);
5829 * Removes all listeners for this object
5831 purgeListeners : function(){
5832 for(var evt in this.events){
5833 if(typeof this.events[evt] == "object"){
5834 this.events[evt].clearListeners();
5839 relayEvents : function(o, events){
5840 var createHandler = function(ename){
5842 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845 for(var i = 0, len = events.length; i < len; i++){
5846 var ename = events[i];
5847 if(!this.events[ename]){ this.events[ename] = true; };
5848 o.on(ename, createHandler(ename), this);
5853 * Used to define events on this Observable
5854 * @param {Object} object The object with the events defined
5856 addEvents : function(o){
5860 Roo.applyIf(this.events, o);
5864 * Checks to see if this object has any listeners for a specified event
5865 * @param {String} eventName The name of the event to check for
5866 * @return {Boolean} True if the event is being listened for, else false
5868 hasListener : function(eventName){
5869 var e = this.events[eventName];
5870 return typeof e == "object" && e.listeners.length > 0;
5874 * Appends an event handler to this element (shorthand for addListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The method the event invokes
5877 * @param {Object} scope (optional) The scope in which to execute the handler
5878 * function. The handler function's "this" context.
5879 * @param {Object} options (optional)
5882 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 * Removes a listener (shorthand for removeListener)
5885 * @param {String} eventName The type of event to listen for
5886 * @param {Function} handler The handler to remove
5887 * @param {Object} scope (optional) The scope (this object) for the handler
5890 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893 * Starts capture on the specified Observable. All events will be passed
5894 * to the supplied function with the event name + standard signature of the event
5895 * <b>before</b> the event is fired. If the supplied function returns false,
5896 * the event will not fire.
5897 * @param {Observable} o The Observable to capture
5898 * @param {Function} fn The function to call
5899 * @param {Object} scope (optional) The scope (this object) for the fn
5902 Roo.util.Observable.capture = function(o, fn, scope){
5903 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 * Removes <b>all</b> added captures from the Observable.
5908 * @param {Observable} o The Observable to release
5911 Roo.util.Observable.releaseCapture = function(o){
5912 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 var createBuffered = function(h, o, scope){
5918 var task = new Roo.util.DelayedTask();
5920 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924 var createSingle = function(h, e, fn, scope){
5926 e.removeListener(fn, scope);
5927 return h.apply(scope, arguments);
5931 var createDelayed = function(h, o, scope){
5933 var args = Array.prototype.slice.call(arguments, 0);
5934 setTimeout(function(){
5935 h.apply(scope, args);
5940 Roo.util.Event = function(obj, name){
5943 this.listeners = [];
5946 Roo.util.Event.prototype = {
5947 addListener : function(fn, scope, options){
5948 var o = options || {};
5949 scope = scope || this.obj;
5950 if(!this.isListening(fn, scope)){
5951 var l = {fn: fn, scope: scope, options: o};
5954 h = createDelayed(h, o, scope);
5957 h = createSingle(h, this, fn, scope);
5960 h = createBuffered(h, o, scope);
5963 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5964 this.listeners.push(l);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.push(l);
5972 findListener : function(fn, scope){
5973 scope = scope || this.obj;
5974 var ls = this.listeners;
5975 for(var i = 0, len = ls.length; i < len; i++){
5977 if(l.fn == fn && l.scope == scope){
5984 isListening : function(fn, scope){
5985 return this.findListener(fn, scope) != -1;
5988 removeListener : function(fn, scope){
5990 if((index = this.findListener(fn, scope)) != -1){
5992 this.listeners.splice(index, 1);
5994 this.listeners = this.listeners.slice(0);
5995 this.listeners.splice(index, 1);
6002 clearListeners : function(){
6003 this.listeners = [];
6007 var ls = this.listeners, scope, len = ls.length;
6010 var args = Array.prototype.slice.call(arguments, 0);
6011 for(var i = 0; i < len; i++){
6013 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6014 this.firing = false;
6018 this.firing = false;
6025 * Ext JS Library 1.1.1
6026 * Copyright(c) 2006-2007, Ext JS, LLC.
6028 * Originally Released Under LGPL - original licence link has changed is not relivant.
6031 * <script type="text/javascript">
6035 * @class Roo.EventManager
6036 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6037 * several useful events directly.
6038 * See {@link Roo.EventObject} for more details on normalized event objects.
6041 Roo.EventManager = function(){
6042 var docReadyEvent, docReadyProcId, docReadyState = false;
6043 var resizeEvent, resizeTask, textEvent, textSize;
6044 var E = Roo.lib.Event;
6045 var D = Roo.lib.Dom;
6048 var fireDocReady = function(){
6050 docReadyState = true;
6053 clearInterval(docReadyProcId);
6055 if(Roo.isGecko || Roo.isOpera) {
6056 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059 var defer = document.getElementById("ie-deferred-loader");
6061 defer.onreadystatechange = null;
6062 defer.parentNode.removeChild(defer);
6066 docReadyEvent.fire();
6067 docReadyEvent.clearListeners();
6072 var initDocReady = function(){
6073 docReadyEvent = new Roo.util.Event();
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6078 var defer = document.getElementById("ie-deferred-loader");
6079 defer.onreadystatechange = function(){
6080 if(this.readyState == "complete"){
6084 }else if(Roo.isSafari){
6085 docReadyProcId = setInterval(function(){
6086 var rs = document.readyState;
6087 if(rs == "complete") {
6092 // no matter what, make sure it fires on load
6093 E.on(window, "load", fireDocReady);
6096 var createBuffered = function(h, o){
6097 var task = new Roo.util.DelayedTask(h);
6099 // create new event object impl so new events don't wipe out properties
6100 e = new Roo.EventObjectImpl(e);
6101 task.delay(o.buffer, h, null, [e]);
6105 var createSingle = function(h, el, ename, fn){
6107 Roo.EventManager.removeListener(el, ename, fn);
6112 var createDelayed = function(h, o){
6114 // create new event object impl so new events don't wipe out properties
6115 e = new Roo.EventObjectImpl(e);
6116 setTimeout(function(){
6122 var listen = function(element, ename, opt, fn, scope){
6123 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6124 fn = fn || o.fn; scope = scope || o.scope;
6125 var el = Roo.getDom(element);
6127 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129 var h = function(e){
6130 e = Roo.EventObject.setEvent(e);
6133 t = e.getTarget(o.delegate, el);
6140 if(o.stopEvent === true){
6143 if(o.preventDefault === true){
6146 if(o.stopPropagation === true){
6147 e.stopPropagation();
6150 if(o.normalized === false){
6154 fn.call(scope || el, e, t, o);
6157 h = createDelayed(h, o);
6160 h = createSingle(h, el, ename, fn);
6163 h = createBuffered(h, o);
6165 fn._handlers = fn._handlers || [];
6166 fn._handlers.push([Roo.id(el), ename, h]);
6169 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6170 el.addEventListener("DOMMouseScroll", h, false);
6171 E.on(window, 'unload', function(){
6172 el.removeEventListener("DOMMouseScroll", h, false);
6175 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6176 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181 var stopListening = function(el, ename, fn){
6182 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184 for(var i = 0, len = hds.length; i < len; i++){
6186 if(h[0] == id && h[1] == ename){
6193 E.un(el, ename, hd);
6194 el = Roo.getDom(el);
6195 if(ename == "mousewheel" && el.addEventListener){
6196 el.removeEventListener("DOMMouseScroll", hd, false);
6198 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6199 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210 * @scope Roo.EventManager
6215 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6216 * object with a Roo.EventObject
6217 * @param {Function} fn The method the event invokes
6218 * @param {Object} scope An object that becomes the scope of the handler
6219 * @param {boolean} override If true, the obj passed in becomes
6220 * the execution scope of the listener
6221 * @return {Function} The wrapped function
6224 wrap : function(fn, scope, override){
6226 Roo.EventObject.setEvent(e);
6227 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232 * Appends an event handler to an element (shorthand for addListener)
6233 * @param {String/HTMLElement} element The html element or id to assign the
6234 * @param {String} eventName The type of event to listen for
6235 * @param {Function} handler The method the event invokes
6236 * @param {Object} scope (optional) The scope in which to execute the handler
6237 * function. The handler function's "this" context.
6238 * @param {Object} options (optional) An object containing handler configuration
6239 * properties. This may contain any of the following properties:<ul>
6240 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6241 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6242 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6243 * <li>preventDefault {Boolean} True to prevent the default action</li>
6244 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6245 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6246 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6247 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6248 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6249 * by the specified number of milliseconds. If the event fires again within that time, the original
6250 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253 * <b>Combining Options</b><br>
6254 * Using the options argument, it is possible to combine different types of listeners:<br>
6256 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258 el.on('click', this.onClick, this, {
6265 * <b>Attaching multiple handlers in 1 call</b><br>
6266 * The method also allows for a single argument to be passed which is a config object containing properties
6267 * which specify multiple handlers.
6277 fn: this.onMouseOver
6286 * Or a shorthand syntax:<br>
6289 'click' : this.onClick,
6290 'mouseover' : this.onMouseOver,
6291 'mouseout' : this.onMouseOut
6295 addListener : function(element, eventName, fn, scope, options){
6296 if(typeof eventName == "object"){
6302 if(typeof o[e] == "function"){
6304 listen(element, e, o, o[e], o.scope);
6306 // individual options
6307 listen(element, e, o[e]);
6312 return listen(element, eventName, options, fn, scope);
6316 * Removes an event handler
6318 * @param {String/HTMLElement} element The id or html element to remove the
6320 * @param {String} eventName The type of event
6321 * @param {Function} fn
6322 * @return {Boolean} True if a listener was actually removed
6324 removeListener : function(element, eventName, fn){
6325 return stopListening(element, eventName, fn);
6329 * Fires when the document is ready (before onload and before images are loaded). Can be
6330 * accessed shorthanded Roo.onReady().
6331 * @param {Function} fn The method the event invokes
6332 * @param {Object} scope An object that becomes the scope of the handler
6333 * @param {boolean} options
6335 onDocumentReady : function(fn, scope, options){
6336 if(docReadyState){ // if it already fired
6337 docReadyEvent.addListener(fn, scope, options);
6338 docReadyEvent.fire();
6339 docReadyEvent.clearListeners();
6345 docReadyEvent.addListener(fn, scope, options);
6349 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6350 * @param {Function} fn The method the event invokes
6351 * @param {Object} scope An object that becomes the scope of the handler
6352 * @param {boolean} options
6354 onWindowResize : function(fn, scope, options){
6356 resizeEvent = new Roo.util.Event();
6357 resizeTask = new Roo.util.DelayedTask(function(){
6358 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360 E.on(window, "resize", function(){
6362 resizeTask.delay(50);
6364 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 resizeEvent.addListener(fn, scope, options);
6372 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6373 * @param {Function} fn The method the event invokes
6374 * @param {Object} scope An object that becomes the scope of the handler
6375 * @param {boolean} options
6377 onTextResize : function(fn, scope, options){
6379 textEvent = new Roo.util.Event();
6380 var textEl = new Roo.Element(document.createElement('div'));
6381 textEl.dom.className = 'x-text-resize';
6382 textEl.dom.innerHTML = 'X';
6383 textEl.appendTo(document.body);
6384 textSize = textEl.dom.offsetHeight;
6385 setInterval(function(){
6386 if(textEl.dom.offsetHeight != textSize){
6387 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389 }, this.textResizeInterval);
6391 textEvent.addListener(fn, scope, options);
6395 * Removes the passed window resize listener.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope The scope of handler
6399 removeResizeListener : function(fn, scope){
6401 resizeEvent.removeListener(fn, scope);
6406 fireResize : function(){
6408 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418 textResizeInterval : 50
6423 * @scopeAlias pub=Roo.EventManager
6427 * Appends an event handler to an element (shorthand for addListener)
6428 * @param {String/HTMLElement} element The html element or id to assign the
6429 * @param {String} eventName The type of event to listen for
6430 * @param {Function} handler The method the event invokes
6431 * @param {Object} scope (optional) The scope in which to execute the handler
6432 * function. The handler function's "this" context.
6433 * @param {Object} options (optional) An object containing handler configuration
6434 * properties. This may contain any of the following properties:<ul>
6435 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6436 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6437 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6438 * <li>preventDefault {Boolean} True to prevent the default action</li>
6439 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6440 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6441 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6442 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6443 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6444 * by the specified number of milliseconds. If the event fires again within that time, the original
6445 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448 * <b>Combining Options</b><br>
6449 * Using the options argument, it is possible to combine different types of listeners:<br>
6451 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453 el.on('click', this.onClick, this, {
6460 * <b>Attaching multiple handlers in 1 call</b><br>
6461 * The method also allows for a single argument to be passed which is a config object containing properties
6462 * which specify multiple handlers.
6472 fn: this.onMouseOver
6481 * Or a shorthand syntax:<br>
6484 'click' : this.onClick,
6485 'mouseover' : this.onMouseOver,
6486 'mouseout' : this.onMouseOut
6490 pub.on = pub.addListener;
6491 pub.un = pub.removeListener;
6493 pub.stoppedMouseDownEvent = new Roo.util.Event();
6497 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} override If true, the obj passed in becomes
6501 * the execution scope of the listener
6505 Roo.onReady = Roo.EventManager.onDocumentReady;
6507 Roo.onReady(function(){
6508 var bd = Roo.get(document.body);
6513 : Roo.isGecko ? "roo-gecko"
6514 : Roo.isOpera ? "roo-opera"
6515 : Roo.isSafari ? "roo-safari" : ""];
6518 cls.push("roo-mac");
6521 cls.push("roo-linux");
6523 if(Roo.isBorderBox){
6524 cls.push('roo-border-box');
6526 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6527 var p = bd.dom.parentNode;
6529 p.className += ' roo-strict';
6532 bd.addClass(cls.join(' '));
6536 * @class Roo.EventObject
6537 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6538 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6541 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543 var target = e.getTarget();
6546 var myDiv = Roo.get("myDiv");
6547 myDiv.on("click", handleClick);
6549 Roo.EventManager.on("myDiv", 'click', handleClick);
6550 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554 Roo.EventObject = function(){
6556 var E = Roo.lib.Event;
6558 // safari keypress events for special keys return bad keycodes
6561 63235 : 39, // right
6564 63276 : 33, // page up
6565 63277 : 34, // page down
6566 63272 : 46, // delete
6571 // normalize button clicks
6572 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6573 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575 Roo.EventObjectImpl = function(e){
6577 this.setEvent(e.browserEvent || e);
6580 Roo.EventObjectImpl.prototype = {
6582 * Used to fix doc tools.
6583 * @scope Roo.EventObject.prototype
6589 /** The normal browser event */
6590 browserEvent : null,
6591 /** The button pressed in a mouse event */
6593 /** True if the shift key was down during the event */
6595 /** True if the control key was down during the event */
6597 /** True if the alt key was down during the event */
6656 setEvent : function(e){
6657 if(e == this || (e && e.browserEvent)){ // already wrapped
6660 this.browserEvent = e;
6662 // normalize buttons
6663 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6664 if(e.type == 'click' && this.button == -1){
6668 this.shiftKey = e.shiftKey;
6669 // mac metaKey behaves like ctrlKey
6670 this.ctrlKey = e.ctrlKey || e.metaKey;
6671 this.altKey = e.altKey;
6672 // in getKey these will be normalized for the mac
6673 this.keyCode = e.keyCode;
6674 // keyup warnings on firefox.
6675 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6676 // cache the target for the delayed and or buffered events
6677 this.target = E.getTarget(e);
6679 this.xy = E.getXY(e);
6682 this.shiftKey = false;
6683 this.ctrlKey = false;
6684 this.altKey = false;
6694 * Stop the event (preventDefault and stopPropagation)
6696 stopEvent : function(){
6697 if(this.browserEvent){
6698 if(this.browserEvent.type == 'mousedown'){
6699 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701 E.stopEvent(this.browserEvent);
6706 * Prevents the browsers default handling of the event.
6708 preventDefault : function(){
6709 if(this.browserEvent){
6710 E.preventDefault(this.browserEvent);
6715 isNavKeyPress : function(){
6716 var k = this.keyCode;
6717 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6718 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721 isSpecialKey : function(){
6722 var k = this.keyCode;
6723 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6724 (k == 16) || (k == 17) ||
6725 (k >= 18 && k <= 20) ||
6726 (k >= 33 && k <= 35) ||
6727 (k >= 36 && k <= 39) ||
6728 (k >= 44 && k <= 45);
6731 * Cancels bubbling of the event.
6733 stopPropagation : function(){
6734 if(this.browserEvent){
6735 if(this.type == 'mousedown'){
6736 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738 E.stopPropagation(this.browserEvent);
6743 * Gets the key code for the event.
6746 getCharCode : function(){
6747 return this.charCode || this.keyCode;
6751 * Returns a normalized keyCode for the event.
6752 * @return {Number} The key code
6754 getKey : function(){
6755 var k = this.keyCode || this.charCode;
6756 return Roo.isSafari ? (safariKeys[k] || k) : k;
6760 * Gets the x coordinate of the event.
6763 getPageX : function(){
6768 * Gets the y coordinate of the event.
6771 getPageY : function(){
6776 * Gets the time of the event.
6779 getTime : function(){
6780 if(this.browserEvent){
6781 return E.getTime(this.browserEvent);
6787 * Gets the page coordinates of the event.
6788 * @return {Array} The xy values like [x, y]
6795 * Gets the target for the event.
6796 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6797 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6798 search as a number or element (defaults to 10 || document.body)
6799 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6800 * @return {HTMLelement}
6802 getTarget : function(selector, maxDepth, returnEl){
6803 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806 * Gets the related target.
6807 * @return {HTMLElement}
6809 getRelatedTarget : function(){
6810 if(this.browserEvent){
6811 return E.getRelatedTarget(this.browserEvent);
6817 * Normalizes mouse wheel delta across browsers
6818 * @return {Number} The delta
6820 getWheelDelta : function(){
6821 var e = this.browserEvent;
6823 if(e.wheelDelta){ /* IE/Opera. */
6824 delta = e.wheelDelta/120;
6825 }else if(e.detail){ /* Mozilla case. */
6826 delta = -e.detail/3;
6832 * Returns true if the control, meta, shift or alt key was pressed during this event.
6835 hasModifier : function(){
6836 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840 * Returns true if the target of this event equals el or is a child of el
6841 * @param {String/HTMLElement/Element} el
6842 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845 within : function(el, related){
6846 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6847 return t && Roo.fly(el).contains(t);
6850 getPoint : function(){
6851 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855 return new Roo.EventObjectImpl();
6860 * Ext JS Library 1.1.1
6861 * Copyright(c) 2006-2007, Ext JS, LLC.
6863 * Originally Released Under LGPL - original licence link has changed is not relivant.
6866 * <script type="text/javascript">
6870 // was in Composite Element!??!?!
6873 var D = Roo.lib.Dom;
6874 var E = Roo.lib.Event;
6875 var A = Roo.lib.Anim;
6877 // local style camelizing for speed
6879 var camelRe = /(-[a-z])/gi;
6880 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6881 var view = document.defaultView;
6884 * @class Roo.Element
6885 * Represents an Element in the DOM.<br><br>
6888 var el = Roo.get("my-div");
6891 var el = getEl("my-div");
6893 // or with a DOM element
6894 var el = Roo.get(myDivElement);
6896 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6897 * each call instead of constructing a new one.<br><br>
6898 * <b>Animations</b><br />
6899 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6900 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 Option Default Description
6903 --------- -------- ---------------------------------------------
6904 duration .35 The duration of the animation in seconds
6905 easing easeOut The YUI easing method
6906 callback none A function to execute when the anim completes
6907 scope this The scope (this) of the callback function
6909 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6910 * manipulate the animation. Here's an example:
6912 var el = Roo.get("my-div");
6917 // default animation
6918 el.setWidth(100, true);
6920 // animation with some options set
6927 // using the "anim" property to get the Anim object
6933 el.setWidth(100, opt);
6935 if(opt.anim.isAnimated()){
6939 * <b> Composite (Collections of) Elements</b><br />
6940 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6941 * @constructor Create a new Element directly.
6942 * @param {String/HTMLElement} element
6943 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6945 Roo.Element = function(element, forceNew){
6946 var dom = typeof element == "string" ?
6947 document.getElementById(element) : element;
6948 if(!dom){ // invalid id/element
6952 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6953 return Roo.Element.cache[id];
6963 * The DOM element ID
6966 this.id = id || Roo.id(dom);
6969 var El = Roo.Element;
6973 * The element's default display mode (defaults to "")
6976 originalDisplay : "",
6980 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985 * Sets the element's visibility mode. When setVisible() is called it
6986 * will use this to determine whether to set the visibility or the display property.
6987 * @param visMode Element.VISIBILITY or Element.DISPLAY
6988 * @return {Roo.Element} this
6990 setVisibilityMode : function(visMode){
6991 this.visibilityMode = visMode;
6995 * Convenience method for setVisibilityMode(Element.DISPLAY)
6996 * @param {String} display (optional) What to set display to when visible
6997 * @return {Roo.Element} this
6999 enableDisplayMode : function(display){
7000 this.setVisibilityMode(El.DISPLAY);
7001 if(typeof display != "undefined") this.originalDisplay = display;
7006 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7007 * @param {String} selector The simple selector to test
7008 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7009 search as a number or element (defaults to 10 || document.body)
7010 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7011 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013 findParent : function(simpleSelector, maxDepth, returnEl){
7014 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7015 maxDepth = maxDepth || 50;
7016 if(typeof maxDepth != "number"){
7017 stopEl = Roo.getDom(maxDepth);
7020 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7021 if(dq.is(p, simpleSelector)){
7022 return returnEl ? Roo.get(p) : p;
7032 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7033 * @param {String} selector The simple selector to test
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039 findParentNode : function(simpleSelector, maxDepth, returnEl){
7040 var p = Roo.fly(this.dom.parentNode, '_internal');
7041 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7046 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7047 * @param {String} selector The simple selector to test
7048 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049 search as a number or element (defaults to 10 || document.body)
7050 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052 up : function(simpleSelector, maxDepth){
7053 return this.findParentNode(simpleSelector, maxDepth, true);
7059 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7060 * @param {String} selector The simple selector to test
7061 * @return {Boolean} True if this element matches the selector, else false
7063 is : function(simpleSelector){
7064 return Roo.DomQuery.is(this.dom, simpleSelector);
7068 * Perform animation on this element.
7069 * @param {Object} args The YUI animation control args
7070 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7071 * @param {Function} onComplete (optional) Function to call when animation completes
7072 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7073 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7074 * @return {Roo.Element} this
7076 animate : function(args, duration, onComplete, easing, animType){
7077 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082 * @private Internal animation call
7084 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7085 animType = animType || 'run';
7087 var anim = Roo.lib.Anim[animType](
7089 (opt.duration || defaultDur) || .35,
7090 (opt.easing || defaultEase) || 'easeOut',
7092 Roo.callback(cb, this);
7093 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101 // private legacy anim prep
7102 preanim : function(a, i){
7103 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107 * Removes worthless text nodes
7108 * @param {Boolean} forceReclean (optional) By default the element
7109 * keeps track if it has been cleaned already so
7110 * you can call this over and over. However, if you update the element and
7111 * need to force a reclean, you can pass true.
7113 clean : function(forceReclean){
7114 if(this.isCleaned && forceReclean !== true){
7118 var d = this.dom, n = d.firstChild, ni = -1;
7120 var nx = n.nextSibling;
7121 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128 this.isCleaned = true;
7133 calcOffsetsTo : function(el){
7136 var restorePos = false;
7137 if(el.getStyle('position') == 'static'){
7138 el.position('relative');
7143 while(op && op != d && op.tagName != 'HTML'){
7146 op = op.offsetParent;
7149 el.position('static');
7155 * Scrolls this element into view within the passed container.
7156 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7157 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7158 * @return {Roo.Element} this
7160 scrollIntoView : function(container, hscroll){
7161 var c = Roo.getDom(container) || document.body;
7164 var o = this.calcOffsetsTo(c),
7167 b = t+el.offsetHeight,
7168 r = l+el.offsetWidth;
7170 var ch = c.clientHeight;
7171 var ct = parseInt(c.scrollTop, 10);
7172 var cl = parseInt(c.scrollLeft, 10);
7174 var cr = cl + c.clientWidth;
7182 if(hscroll !== false){
7186 c.scrollLeft = r-c.clientWidth;
7193 scrollChildIntoView : function(child, hscroll){
7194 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7199 * the new height may not be available immediately.
7200 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7201 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7202 * @param {Function} onComplete (optional) Function to call when animation completes
7203 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7204 * @return {Roo.Element} this
7206 autoHeight : function(animate, duration, onComplete, easing){
7207 var oldHeight = this.getHeight();
7209 this.setHeight(1); // force clipping
7210 setTimeout(function(){
7211 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213 this.setHeight(height);
7215 if(typeof onComplete == "function"){
7219 this.setHeight(oldHeight); // restore original height
7220 this.setHeight(height, animate, duration, function(){
7222 if(typeof onComplete == "function") onComplete();
7223 }.createDelegate(this), easing);
7225 }.createDelegate(this), 0);
7230 * Returns true if this element is an ancestor of the passed element
7231 * @param {HTMLElement/String} el The element to check
7232 * @return {Boolean} True if this element is an ancestor of el, else false
7234 contains : function(el){
7235 if(!el){return false;}
7236 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240 * Checks whether the element is currently visible using both visibility and display properties.
7241 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7242 * @return {Boolean} True if the element is currently visible, else false
7244 isVisible : function(deep) {
7245 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7246 if(deep !== true || !vis){
7249 var p = this.dom.parentNode;
7250 while(p && p.tagName.toLowerCase() != "body"){
7251 if(!Roo.fly(p, '_isVisible').isVisible()){
7260 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7263 * @return {CompositeElement/CompositeElementLite} The composite element
7265 select : function(selector, unique){
7266 return El.select(selector, unique, this.dom);
7270 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7271 * @param {String} selector The CSS selector
7272 * @return {Array} An array of the matched nodes
7274 query : function(selector, unique){
7275 return Roo.DomQuery.select(selector, this.dom);
7279 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 child : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7291 * @param {String} selector The CSS selector
7292 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7293 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295 down : function(selector, returnDom){
7296 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7297 return returnDom ? n : Roo.get(n);
7301 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7302 * @param {String} group The group the DD object is member of
7303 * @param {Object} config The DD config object
7304 * @param {Object} overrides An object containing methods to override/implement on the DD object
7305 * @return {Roo.dd.DD} The DD object
7307 initDD : function(group, config, overrides){
7308 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7309 return Roo.apply(dd, overrides);
7313 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7314 * @param {String} group The group the DDProxy object is member of
7315 * @param {Object} config The DDProxy config object
7316 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7317 * @return {Roo.dd.DDProxy} The DDProxy object
7319 initDDProxy : function(group, config, overrides){
7320 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7321 return Roo.apply(dd, overrides);
7325 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7326 * @param {String} group The group the DDTarget object is member of
7327 * @param {Object} config The DDTarget config object
7328 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7329 * @return {Roo.dd.DDTarget} The DDTarget object
7331 initDDTarget : function(group, config, overrides){
7332 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7333 return Roo.apply(dd, overrides);
7337 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7338 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7339 * @param {Boolean} visible Whether the element is visible
7340 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7341 * @return {Roo.Element} this
7343 setVisible : function(visible, animate){
7345 if(this.visibilityMode == El.DISPLAY){
7346 this.setDisplayed(visible);
7349 this.dom.style.visibility = visible ? "visible" : "hidden";
7352 // closure for composites
7354 var visMode = this.visibilityMode;
7356 this.setOpacity(.01);
7357 this.setVisible(true);
7359 this.anim({opacity: { to: (visible?1:0) }},
7360 this.preanim(arguments, 1),
7361 null, .35, 'easeIn', function(){
7363 if(visMode == El.DISPLAY){
7364 dom.style.display = "none";
7366 dom.style.visibility = "hidden";
7368 Roo.get(dom).setOpacity(1);
7376 * Returns true if display is not "none"
7379 isDisplayed : function() {
7380 return this.getStyle("display") != "none";
7384 * Toggles the element's visibility or display, depending on visibility mode.
7385 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7386 * @return {Roo.Element} this
7388 toggle : function(animate){
7389 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7395 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7396 * @return {Roo.Element} this
7398 setDisplayed : function(value) {
7399 if(typeof value == "boolean"){
7400 value = value ? this.originalDisplay : "none";
7402 this.setStyle("display", value);
7407 * Tries to focus the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7410 focus : function() {
7418 * Tries to blur the element. Any exceptions are caught and ignored.
7419 * @return {Roo.Element} this
7429 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7430 * @param {String/Array} className The CSS class to add, or an array of classes
7431 * @return {Roo.Element} this
7433 addClass : function(className){
7434 if(className instanceof Array){
7435 for(var i = 0, len = className.length; i < len; i++) {
7436 this.addClass(className[i]);
7439 if(className && !this.hasClass(className)){
7440 this.dom.className = this.dom.className + " " + className;
7447 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7448 * @param {String/Array} className The CSS class to add, or an array of classes
7449 * @return {Roo.Element} this
7451 radioClass : function(className){
7452 var siblings = this.dom.parentNode.childNodes;
7453 for(var i = 0; i < siblings.length; i++) {
7454 var s = siblings[i];
7455 if(s.nodeType == 1){
7456 Roo.get(s).removeClass(className);
7459 this.addClass(className);
7464 * Removes one or more CSS classes from the element.
7465 * @param {String/Array} className The CSS class to remove, or an array of classes
7466 * @return {Roo.Element} this
7468 removeClass : function(className){
7469 if(!className || !this.dom.className){
7472 if(className instanceof Array){
7473 for(var i = 0, len = className.length; i < len; i++) {
7474 this.removeClass(className[i]);
7477 if(this.hasClass(className)){
7478 var re = this.classReCache[className];
7480 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7481 this.classReCache[className] = re;
7483 this.dom.className =
7484 this.dom.className.replace(re, " ");
7494 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7495 * @param {String} className The CSS class to toggle
7496 * @return {Roo.Element} this
7498 toggleClass : function(className){
7499 if(this.hasClass(className)){
7500 this.removeClass(className);
7502 this.addClass(className);
7508 * Checks if the specified CSS class exists on this element's DOM node.
7509 * @param {String} className The CSS class to check for
7510 * @return {Boolean} True if the class exists, else false
7512 hasClass : function(className){
7513 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7518 * @param {String} oldClassName The CSS class to replace
7519 * @param {String} newClassName The replacement CSS class
7520 * @return {Roo.Element} this
7522 replaceClass : function(oldClassName, newClassName){
7523 this.removeClass(oldClassName);
7524 this.addClass(newClassName);
7529 * Returns an object with properties matching the styles requested.
7530 * For example, el.getStyles('color', 'font-size', 'width') might return
7531 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7532 * @param {String} style1 A style name
7533 * @param {String} style2 A style name
7534 * @param {String} etc.
7535 * @return {Object} The style object
7537 getStyles : function(){
7538 var a = arguments, len = a.length, r = {};
7539 for(var i = 0; i < len; i++){
7540 r[a[i]] = this.getStyle(a[i]);
7546 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7547 * @param {String} property The style property whose value is returned.
7548 * @return {String} The current value of the style property for this element.
7550 getStyle : function(){
7551 return view && view.getComputedStyle ?
7553 var el = this.dom, v, cs, camel;
7554 if(prop == 'float'){
7557 if(el.style && (v = el.style[prop])){
7560 if(cs = view.getComputedStyle(el, "")){
7561 if(!(camel = propCache[prop])){
7562 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569 var el = this.dom, v, cs, camel;
7570 if(prop == 'opacity'){
7571 if(typeof el.style.filter == 'string'){
7572 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574 var fv = parseFloat(m[1]);
7576 return fv ? fv / 100 : 0;
7581 }else if(prop == 'float'){
7582 prop = "styleFloat";
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587 if(v = el.style[camel]){
7590 if(cs = el.currentStyle){
7598 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7599 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7600 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7601 * @return {Roo.Element} this
7603 setStyle : function(prop, value){
7604 if(typeof prop == "string"){
7606 if (prop == 'float') {
7607 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7612 if(!(camel = propCache[prop])){
7613 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616 if(camel == 'opacity') {
7617 this.setOpacity(value);
7619 this.dom.style[camel] = value;
7622 for(var style in prop){
7623 if(typeof prop[style] != "function"){
7624 this.setStyle(style, prop[style]);
7632 * More flexible version of {@link #setStyle} for setting style properties.
7633 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7634 * a function which returns such a specification.
7635 * @return {Roo.Element} this
7637 applyStyles : function(style){
7638 Roo.DomHelper.applyStyles(this.dom, style);
7643 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7644 * @return {Number} The X position of the element
7647 return D.getX(this.dom);
7651 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7652 * @return {Number} The Y position of the element
7655 return D.getY(this.dom);
7659 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7660 * @return {Array} The XY position of the element
7663 return D.getXY(this.dom);
7667 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7668 * @param {Number} The X position of the element
7669 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7670 * @return {Roo.Element} this
7672 setX : function(x, animate){
7674 D.setX(this.dom, x);
7676 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7682 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7683 * @param {Number} The Y position of the element
7684 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setY : function(y, animate){
7689 D.setY(this.dom, y);
7691 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7697 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7698 * @param {String} left The left CSS property value
7699 * @return {Roo.Element} this
7701 setLeft : function(left){
7702 this.setStyle("left", this.addUnits(left));
7707 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7708 * @param {String} top The top CSS property value
7709 * @return {Roo.Element} this
7711 setTop : function(top){
7712 this.setStyle("top", this.addUnits(top));
7717 * Sets the element's CSS right style.
7718 * @param {String} right The right CSS property value
7719 * @return {Roo.Element} this
7721 setRight : function(right){
7722 this.setStyle("right", this.addUnits(right));
7727 * Sets the element's CSS bottom style.
7728 * @param {String} bottom The bottom CSS property value
7729 * @return {Roo.Element} this
7731 setBottom : function(bottom){
7732 this.setStyle("bottom", this.addUnits(bottom));
7737 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7738 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setXY : function(pos, animate){
7745 D.setXY(this.dom, pos);
7747 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7753 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7754 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7755 * @param {Number} x X value for new position (coordinates are page-based)
7756 * @param {Number} y Y value for new position (coordinates are page-based)
7757 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setLocation : function(x, y, animate){
7761 this.setXY([x, y], this.preanim(arguments, 2));
7766 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768 * @param {Number} x X value for new position (coordinates are page-based)
7769 * @param {Number} y Y value for new position (coordinates are page-based)
7770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771 * @return {Roo.Element} this
7773 moveTo : function(x, y, animate){
7774 this.setXY([x, y], this.preanim(arguments, 2));
7779 * Returns the region of the given element.
7780 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7781 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783 getRegion : function(){
7784 return D.getRegion(this.dom);
7788 * Returns the offset height of the element
7789 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7790 * @return {Number} The element's height
7792 getHeight : function(contentHeight){
7793 var h = this.dom.offsetHeight || 0;
7794 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798 * Returns the offset width of the element
7799 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7800 * @return {Number} The element's width
7802 getWidth : function(contentWidth){
7803 var w = this.dom.offsetWidth || 0;
7804 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7809 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7810 * if a height has not been set using CSS.
7813 getComputedHeight : function(){
7814 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816 h = parseInt(this.getStyle('height'), 10) || 0;
7817 if(!this.isBorderBox()){
7818 h += this.getFrameWidth('tb');
7825 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7826 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7827 * if a width has not been set using CSS.
7830 getComputedWidth : function(){
7831 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833 w = parseInt(this.getStyle('width'), 10) || 0;
7834 if(!this.isBorderBox()){
7835 w += this.getFrameWidth('lr');
7842 * Returns the size of the element.
7843 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7844 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846 getSize : function(contentSize){
7847 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851 * Returns the width and height of the viewport.
7852 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854 getViewSize : function(){
7855 var d = this.dom, doc = document, aw = 0, ah = 0;
7856 if(d == doc || d == doc.body){
7857 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860 width : d.clientWidth,
7861 height: d.clientHeight
7867 * Returns the value of the "value" attribute
7868 * @param {Boolean} asNumber true to parse the value as a number
7869 * @return {String/Number}
7871 getValue : function(asNumber){
7872 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876 adjustWidth : function(width){
7877 if(typeof width == "number"){
7878 if(this.autoBoxAdjust && !this.isBorderBox()){
7879 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7889 adjustHeight : function(height){
7890 if(typeof height == "number"){
7891 if(this.autoBoxAdjust && !this.isBorderBox()){
7892 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7902 * Set the width of the element
7903 * @param {Number} width The new width
7904 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7905 * @return {Roo.Element} this
7907 setWidth : function(width, animate){
7908 width = this.adjustWidth(width);
7910 this.dom.style.width = this.addUnits(width);
7912 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7918 * Set the height of the element
7919 * @param {Number} height The new height
7920 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7921 * @return {Roo.Element} this
7923 setHeight : function(height, animate){
7924 height = this.adjustHeight(height);
7926 this.dom.style.height = this.addUnits(height);
7928 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7934 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7935 * @param {Number} width The new width
7936 * @param {Number} height The new height
7937 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 setSize : function(width, height, animate){
7941 if(typeof width == "object"){ // in case of object from getSize()
7942 height = width.height; width = width.width;
7944 width = this.adjustWidth(width); height = this.adjustHeight(height);
7946 this.dom.style.width = this.addUnits(width);
7947 this.dom.style.height = this.addUnits(height);
7949 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7955 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Number} width The new width
7959 * @param {Number} height The new height
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setBounds : function(x, y, width, height, animate){
7965 this.setSize(width, height);
7966 this.setLocation(x, y);
7968 width = this.adjustWidth(width); height = this.adjustHeight(height);
7969 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7970 this.preanim(arguments, 4), 'motion');
7976 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7977 * @param {Roo.lib.Region} region The region to fill
7978 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setRegion : function(region, animate){
7982 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987 * Appends an event handler
7989 * @param {String} eventName The type of event to append
7990 * @param {Function} fn The method the event invokes
7991 * @param {Object} scope (optional) The scope (this object) of the fn
7992 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7994 addListener : function(eventName, fn, scope, options){
7996 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8001 * Removes an event handler from this element
8002 * @param {String} eventName the type of event to remove
8003 * @param {Function} fn the method the event invokes
8004 * @return {Roo.Element} this
8006 removeListener : function(eventName, fn){
8007 Roo.EventManager.removeListener(this.dom, eventName, fn);
8012 * Removes all previous added listeners from this element
8013 * @return {Roo.Element} this
8015 removeAllListeners : function(){
8016 E.purgeElement(this.dom);
8020 relayEvent : function(eventName, observable){
8021 this.on(eventName, function(e){
8022 observable.fireEvent(eventName, e);
8027 * Set the opacity of the element
8028 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setOpacity : function(opacity, animate){
8034 var s = this.dom.style;
8037 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8038 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040 s.opacity = opacity;
8043 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8049 * Gets the left X coordinate
8050 * @param {Boolean} local True to get the local css position instead of page coordinate
8053 getLeft : function(local){
8057 return parseInt(this.getStyle("left"), 10) || 0;
8062 * Gets the right X coordinate of the element (element X position + element width)
8063 * @param {Boolean} local True to get the local css position instead of page coordinate
8066 getRight : function(local){
8068 return this.getX() + this.getWidth();
8070 return (this.getLeft(true) + this.getWidth()) || 0;
8075 * Gets the top Y coordinate
8076 * @param {Boolean} local True to get the local css position instead of page coordinate
8079 getTop : function(local) {
8083 return parseInt(this.getStyle("top"), 10) || 0;
8088 * Gets the bottom Y coordinate of the element (element Y position + element height)
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getBottom : function(local){
8094 return this.getY() + this.getHeight();
8096 return (this.getTop(true) + this.getHeight()) || 0;
8101 * Initializes positioning on this element. If a desired position is not passed, it will make the
8102 * the element positioned relative IF it is not already positioned.
8103 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8104 * @param {Number} zIndex (optional) The zIndex to apply
8105 * @param {Number} x (optional) Set the page X position
8106 * @param {Number} y (optional) Set the page Y position
8108 position : function(pos, zIndex, x, y){
8110 if(this.getStyle('position') == 'static'){
8111 this.setStyle('position', 'relative');
8114 this.setStyle("position", pos);
8117 this.setStyle("z-index", zIndex);
8119 if(x !== undefined && y !== undefined){
8121 }else if(x !== undefined){
8123 }else if(y !== undefined){
8129 * Clear positioning back to the default when the document was loaded
8130 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8131 * @return {Roo.Element} this
8133 clearPositioning : function(value){
8141 "position" : "static"
8147 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8148 * snapshot before performing an update and then restoring the element.
8151 getPositioning : function(){
8152 var l = this.getStyle("left");
8153 var t = this.getStyle("top");
8155 "position" : this.getStyle("position"),
8157 "right" : l ? "" : this.getStyle("right"),
8159 "bottom" : t ? "" : this.getStyle("bottom"),
8160 "z-index" : this.getStyle("z-index")
8165 * Gets the width of the border(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the border (l)eft width + the border (r)ight width.
8168 * @return {Number} The width of the sides passed added together
8170 getBorderWidth : function(side){
8171 return this.addStyles(side, El.borders);
8175 * Gets the width of the padding(s) for the specified side(s)
8176 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8177 * passing lr would get the padding (l)eft + the padding (r)ight.
8178 * @return {Number} The padding of the sides passed added together
8180 getPadding : function(side){
8181 return this.addStyles(side, El.paddings);
8185 * Set positioning with an object returned by getPositioning().
8186 * @param {Object} posCfg
8187 * @return {Roo.Element} this
8189 setPositioning : function(pc){
8190 this.applyStyles(pc);
8191 if(pc.right == "auto"){
8192 this.dom.style.right = "";
8194 if(pc.bottom == "auto"){
8195 this.dom.style.bottom = "";
8201 fixDisplay : function(){
8202 if(this.getStyle("display") == "none"){
8203 this.setStyle("visibility", "hidden");
8204 this.setStyle("display", this.originalDisplay); // first try reverting to default
8205 if(this.getStyle("display") == "none"){ // if that fails, default to block
8206 this.setStyle("display", "block");
8212 * Quick set left and top adding default units
8213 * @param {String} left The left CSS property value
8214 * @param {String} top The top CSS property value
8215 * @return {Roo.Element} this
8217 setLeftTop : function(left, top){
8218 this.dom.style.left = this.addUnits(left);
8219 this.dom.style.top = this.addUnits(top);
8224 * Move this element relative to its current position.
8225 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8226 * @param {Number} distance How far to move the element in pixels
8227 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8228 * @return {Roo.Element} this
8230 move : function(direction, distance, animate){
8231 var xy = this.getXY();
8232 direction = direction.toLowerCase();
8236 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8258 * @return {Roo.Element} this
8261 if(!this.isClipped){
8262 this.isClipped = true;
8263 this.originalClip = {
8264 "o": this.getStyle("overflow"),
8265 "x": this.getStyle("overflow-x"),
8266 "y": this.getStyle("overflow-y")
8268 this.setStyle("overflow", "hidden");
8269 this.setStyle("overflow-x", "hidden");
8270 this.setStyle("overflow-y", "hidden");
8276 * Return clipping (overflow) to original clipping before clip() was called
8277 * @return {Roo.Element} this
8279 unclip : function(){
8281 this.isClipped = false;
8282 var o = this.originalClip;
8283 if(o.o){this.setStyle("overflow", o.o);}
8284 if(o.x){this.setStyle("overflow-x", o.x);}
8285 if(o.y){this.setStyle("overflow-y", o.y);}
8292 * Gets the x,y coordinates specified by the anchor position on the element.
8293 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8294 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8295 * {width: (target width), height: (target height)} (defaults to the element's current size)
8296 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8297 * @return {Array} [x, y] An array containing the element's x and y coordinates
8299 getAnchorXY : function(anchor, local, s){
8300 //Passing a different size is useful for pre-calculating anchors,
8301 //especially for anchored animations that change the el size.
8303 var w, h, vp = false;
8306 if(d == document.body || d == document){
8308 w = D.getViewWidth(); h = D.getViewHeight();
8310 w = this.getWidth(); h = this.getHeight();
8313 w = s.width; h = s.height;
8315 var x = 0, y = 0, r = Math.round;
8316 switch((anchor || "tl").toLowerCase()){
8358 var sc = this.getScroll();
8359 return [x + sc.left, y + sc.top];
8361 //Add the element's offset xy
8362 var o = this.getXY();
8363 return [x+o[0], y+o[1]];
8367 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8368 * supported position values.
8369 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8370 * @param {String} position The position to align to.
8371 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8372 * @return {Array} [x, y]
8374 getAlignToXY : function(el, p, o){
8378 throw "Element.alignTo with an element that doesn't exist";
8380 var c = false; //constrain to viewport
8381 var p1 = "", p2 = "";
8388 }else if(p.indexOf("-") == -1){
8391 p = p.toLowerCase();
8392 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394 throw "Element.alignTo with an invalid alignment " + p;
8396 p1 = m[1]; p2 = m[2]; c = !!m[3];
8398 //Subtract the aligned el's internal xy from the target's offset xy
8399 //plus custom offset to get the aligned el's new offset xy
8400 var a1 = this.getAnchorXY(p1, true);
8401 var a2 = el.getAnchorXY(p2, false);
8402 var x = a2[0] - a1[0] + o[0];
8403 var y = a2[1] - a1[1] + o[1];
8405 //constrain the aligned el to viewport if necessary
8406 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8407 // 5px of margin for ie
8408 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8411 //perpendicular to the vp border, allow the aligned el to slide on that border,
8412 //otherwise swap the aligned el to the opposite border of the target.
8413 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8414 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8415 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8416 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8420 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422 if((x+w) > dw + scrollX){
8423 x = swapX ? r.left-w : dw+scrollX-w;
8426 x = swapX ? r.right : scrollX;
8428 if((y+h) > dh + scrollY){
8429 y = swapY ? r.top-h : dh+scrollY-h;
8432 y = swapY ? r.bottom : scrollY;
8439 getConstrainToXY : function(){
8440 var os = {top:0, left:0, bottom:0, right: 0};
8442 return function(el, local, offsets, proposedXY){
8444 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446 var vw, vh, vx = 0, vy = 0;
8447 if(el.dom == document.body || el.dom == document){
8448 vw = Roo.lib.Dom.getViewWidth();
8449 vh = Roo.lib.Dom.getViewHeight();
8451 vw = el.dom.clientWidth;
8452 vh = el.dom.clientHeight;
8454 var vxy = el.getXY();
8460 var s = el.getScroll();
8462 vx += offsets.left + s.left;
8463 vy += offsets.top + s.top;
8465 vw -= offsets.right;
8466 vh -= offsets.bottom;
8471 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8472 var x = xy[0], y = xy[1];
8473 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475 // only move it if it needs it
8478 // first validate right/bottom
8487 // then make sure top/left isn't negative
8496 return moved ? [x, y] : false;
8501 adjustForConstraints : function(xy, parent, offsets){
8502 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8506 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8507 * document it aligns it to the viewport.
8508 * The position parameter is optional, and can be specified in any one of the following formats:
8510 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8511 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8512 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8513 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8514 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8515 * element's anchor point, and the second value is used as the target's anchor point.</li>
8517 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8518 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8519 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8520 * that specified in order to enforce the viewport constraints.
8521 * Following are all of the supported anchor positions:
8524 ----- -----------------------------
8525 tl The top left corner (default)
8526 t The center of the top edge
8527 tr The top right corner
8528 l The center of the left edge
8529 c In the center of the element
8530 r The center of the right edge
8531 bl The bottom left corner
8532 b The center of the bottom edge
8533 br The bottom right corner
8537 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8538 el.alignTo("other-el");
8540 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8541 el.alignTo("other-el", "tr?");
8543 // align the bottom right corner of el with the center left edge of other-el
8544 el.alignTo("other-el", "br-l?");
8546 // align the center of el with the bottom left corner of other-el and
8547 // adjust the x position by -6 pixels (and the y position by 0)
8548 el.alignTo("other-el", "c-bl", [-6, 0]);
8550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8551 * @param {String} position The position to align to.
8552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8553 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8554 * @return {Roo.Element} this
8556 alignTo : function(element, position, offsets, animate){
8557 var xy = this.getAlignToXY(element, position, offsets);
8558 this.setXY(xy, this.preanim(arguments, 3));
8563 * Anchors an element to another element and realigns it when the window is resized.
8564 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565 * @param {String} position The position to align to.
8566 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8568 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8569 * is a number, it is used as the buffer delay (defaults to 50ms).
8570 * @param {Function} callback The function to call after the animation finishes
8571 * @return {Roo.Element} this
8573 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 var action = function(){
8575 this.alignTo(el, alignment, offsets, animate);
8576 Roo.callback(callback, this);
8578 Roo.EventManager.onWindowResize(action, this);
8579 var tm = typeof monitorScroll;
8580 if(tm != 'undefined'){
8581 Roo.EventManager.on(window, 'scroll', action, this,
8582 {buffer: tm == 'number' ? monitorScroll : 50});
8584 action.call(this); // align immediately
8588 * Clears any opacity settings from this element. Required in some cases for IE.
8589 * @return {Roo.Element} this
8591 clearOpacity : function(){
8592 if (window.ActiveXObject) {
8593 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8594 this.dom.style.filter = "";
8597 this.dom.style.opacity = "";
8598 this.dom.style["-moz-opacity"] = "";
8599 this.dom.style["-khtml-opacity"] = "";
8605 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 hide : function(animate){
8610 this.setVisible(false, this.preanim(arguments, 0));
8615 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8616 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8617 * @return {Roo.Element} this
8619 show : function(animate){
8620 this.setVisible(true, this.preanim(arguments, 0));
8625 * @private Test if size has a unit, otherwise appends the default
8627 addUnits : function(size){
8628 return Roo.Element.addUnits(size, this.defaultUnit);
8632 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8633 * @return {Roo.Element} this
8635 beginMeasure : function(){
8637 if(el.offsetWidth || el.offsetHeight){
8638 return this; // offsets work already
8641 var p = this.dom, b = document.body; // start with this element
8642 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8643 var pe = Roo.get(p);
8644 if(pe.getStyle('display') == 'none'){
8645 changed.push({el: p, visibility: pe.getStyle("visibility")});
8646 p.style.visibility = "hidden";
8647 p.style.display = "block";
8651 this._measureChanged = changed;
8657 * Restores displays to before beginMeasure was called
8658 * @return {Roo.Element} this
8660 endMeasure : function(){
8661 var changed = this._measureChanged;
8663 for(var i = 0, len = changed.length; i < len; i++) {
8665 r.el.style.visibility = r.visibility;
8666 r.el.style.display = "none";
8668 this._measureChanged = null;
8674 * Update the innerHTML of this element, optionally searching for and processing scripts
8675 * @param {String} html The new HTML
8676 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8677 * @param {Function} callback For async script loading you can be noticed when the update completes
8678 * @return {Roo.Element} this
8680 update : function(html, loadScripts, callback){
8681 if(typeof html == "undefined"){
8684 if(loadScripts !== true){
8685 this.dom.innerHTML = html;
8686 if(typeof callback == "function"){
8694 html += '<span id="' + id + '"></span>';
8696 E.onAvailable(id, function(){
8697 var hd = document.getElementsByTagName("head")[0];
8698 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8699 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8700 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703 while(match = re.exec(html)){
8704 var attrs = match[1];
8705 var srcMatch = attrs ? attrs.match(srcRe) : false;
8706 if(srcMatch && srcMatch[2]){
8707 var s = document.createElement("script");
8708 s.src = srcMatch[2];
8709 var typeMatch = attrs.match(typeRe);
8710 if(typeMatch && typeMatch[2]){
8711 s.type = typeMatch[2];
8714 }else if(match[2] && match[2].length > 0){
8715 if(window.execScript) {
8716 window.execScript(match[2]);
8724 window.eval(match[2]);
8728 var el = document.getElementById(id);
8729 if(el){el.parentNode.removeChild(el);}
8730 if(typeof callback == "function"){
8734 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739 * Direct access to the UpdateManager update() method (takes the same parameters).
8740 * @param {String/Function} url The url for this request or a function to call to get the url
8741 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8742 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8743 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8744 * @return {Roo.Element} this
8747 var um = this.getUpdateManager();
8748 um.update.apply(um, arguments);
8753 * Gets this element's UpdateManager
8754 * @return {Roo.UpdateManager} The UpdateManager
8756 getUpdateManager : function(){
8757 if(!this.updateManager){
8758 this.updateManager = new Roo.UpdateManager(this);
8760 return this.updateManager;
8764 * Disables text selection for this element (normalized across browsers)
8765 * @return {Roo.Element} this
8767 unselectable : function(){
8768 this.dom.unselectable = "on";
8769 this.swallowEvent("selectstart", true);
8770 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8771 this.addClass("x-unselectable");
8776 * Calculates the x, y to center this element on the screen
8777 * @return {Array} The x, y values [x, y]
8779 getCenterXY : function(){
8780 return this.getAlignToXY(document, 'c-c');
8784 * Centers the Element in either the viewport, or another Element.
8785 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787 center : function(centerIn){
8788 this.alignTo(centerIn || document, 'c-c');
8793 * Tests various css rules/browsers to determine if this element uses a border box
8796 isBorderBox : function(){
8797 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801 * Return a box {x, y, width, height} that can be used to set another elements
8802 * size/location to match this element.
8803 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8804 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8805 * @return {Object} box An object in the format {x, y, width, height}
8807 getBox : function(contentBox, local){
8812 var left = parseInt(this.getStyle("left"), 10) || 0;
8813 var top = parseInt(this.getStyle("top"), 10) || 0;
8816 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820 var l = this.getBorderWidth("l")+this.getPadding("l");
8821 var r = this.getBorderWidth("r")+this.getPadding("r");
8822 var t = this.getBorderWidth("t")+this.getPadding("t");
8823 var b = this.getBorderWidth("b")+this.getPadding("b");
8824 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8826 bx.right = bx.x + bx.width;
8827 bx.bottom = bx.y + bx.height;
8832 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8833 for more information about the sides.
8834 * @param {String} sides
8837 getFrameWidth : function(sides, onlyContentBox){
8838 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8843 * @param {Object} box The box to fill {x, y, width, height}
8844 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8845 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8846 * @return {Roo.Element} this
8848 setBox : function(box, adjust, animate){
8849 var w = box.width, h = box.height;
8850 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8851 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8852 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859 * Forces the browser to repaint this element
8860 * @return {Roo.Element} this
8862 repaint : function(){
8864 this.addClass("x-repaint");
8865 setTimeout(function(){
8866 Roo.get(dom).removeClass("x-repaint");
8872 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8873 * then it returns the calculated width of the sides (see getPadding)
8874 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8875 * @return {Object/Number}
8877 getMargins : function(side){
8880 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8881 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8882 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8883 right: parseInt(this.getStyle("margin-right"), 10) || 0
8886 return this.addStyles(side, El.margins);
8891 addStyles : function(sides, styles){
8893 for(var i = 0, len = sides.length; i < len; i++){
8894 v = this.getStyle(styles[sides.charAt(i)]);
8896 w = parseInt(v, 10);
8904 * Creates a proxy element of this element
8905 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8906 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8907 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8908 * @return {Roo.Element} The new proxy element
8910 createProxy : function(config, renderTo, matchBox){
8912 renderTo = Roo.getDom(renderTo);
8914 renderTo = document.body;
8916 config = typeof config == "object" ?
8917 config : {tag : "div", cls: config};
8918 var proxy = Roo.DomHelper.append(renderTo, config, true);
8920 proxy.setBox(this.getBox());
8926 * Puts a mask over this element to disable user interaction. Requires core.css.
8927 * This method can only be applied to elements which accept child nodes.
8928 * @param {String} msg (optional) A message to display in the mask
8929 * @param {String} msgCls (optional) A css class to apply to the msg element
8930 * @return {Element} The mask element
8932 mask : function(msg, msgCls)
8934 if(this.getStyle("position") == "static"){
8935 this.setStyle("position", "relative");
8938 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940 this.addClass("x-masked");
8941 this._mask.setDisplayed(true);
8946 while (dom && dom.style) {
8947 if (!isNaN(parseInt(dom.style.zIndex))) {
8948 z = Math.max(z, parseInt(dom.style.zIndex));
8950 dom = dom.parentNode;
8952 // if we are masking the body - then it hides everything..
8953 if (this.dom == document.body) {
8955 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8956 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959 if(typeof msg == 'string'){
8961 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963 var mm = this._maskMsg;
8964 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8965 mm.dom.firstChild.innerHTML = msg;
8966 mm.setDisplayed(true);
8968 mm.setStyle('z-index', z + 102);
8970 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8971 this._mask.setHeight(this.getHeight());
8973 this._mask.setStyle('z-index', z + 100);
8979 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8980 * it is cached for reuse.
8982 unmask : function(removeEl){
8984 if(removeEl === true){
8985 this._mask.remove();
8988 this._maskMsg.remove();
8989 delete this._maskMsg;
8992 this._mask.setDisplayed(false);
8994 this._maskMsg.setDisplayed(false);
8998 this.removeClass("x-masked");
9002 * Returns true if this element is masked
9005 isMasked : function(){
9006 return this._mask && this._mask.isVisible();
9010 * Creates an iframe shim for this element to keep selects and other windowed objects from
9012 * @return {Roo.Element} The new shim element
9014 createShim : function(){
9015 var el = document.createElement('iframe');
9016 el.frameBorder = 'no';
9017 el.className = 'roo-shim';
9018 if(Roo.isIE && Roo.isSecure){
9019 el.src = Roo.SSL_SECURE_URL;
9021 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9022 shim.autoBoxAdjust = false;
9027 * Removes this element from the DOM and deletes it from the cache
9029 remove : function(){
9030 if(this.dom.parentNode){
9031 this.dom.parentNode.removeChild(this.dom);
9033 delete El.cache[this.dom.id];
9037 * Sets up event handlers to add and remove a css class when the mouse is over this element
9038 * @param {String} className
9039 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9040 * mouseout events for children elements
9041 * @return {Roo.Element} this
9043 addClassOnOver : function(className, preventFlicker){
9044 this.on("mouseover", function(){
9045 Roo.fly(this, '_internal').addClass(className);
9047 var removeFn = function(e){
9048 if(preventFlicker !== true || !e.within(this, true)){
9049 Roo.fly(this, '_internal').removeClass(className);
9052 this.on("mouseout", removeFn, this.dom);
9057 * Sets up event handlers to add and remove a css class when this element has the focus
9058 * @param {String} className
9059 * @return {Roo.Element} this
9061 addClassOnFocus : function(className){
9062 this.on("focus", function(){
9063 Roo.fly(this, '_internal').addClass(className);
9065 this.on("blur", function(){
9066 Roo.fly(this, '_internal').removeClass(className);
9071 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9072 * @param {String} className
9073 * @return {Roo.Element} this
9075 addClassOnClick : function(className){
9077 this.on("mousedown", function(){
9078 Roo.fly(dom, '_internal').addClass(className);
9079 var d = Roo.get(document);
9080 var fn = function(){
9081 Roo.fly(dom, '_internal').removeClass(className);
9082 d.removeListener("mouseup", fn);
9084 d.on("mouseup", fn);
9090 * Stops the specified event from bubbling and optionally prevents the default action
9091 * @param {String} eventName
9092 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9093 * @return {Roo.Element} this
9095 swallowEvent : function(eventName, preventDefault){
9096 var fn = function(e){
9097 e.stopPropagation();
9102 if(eventName instanceof Array){
9103 for(var i = 0, len = eventName.length; i < len; i++){
9104 this.on(eventName[i], fn);
9108 this.on(eventName, fn);
9115 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118 * Sizes this element to its parent element's dimensions performing
9119 * neccessary box adjustments.
9120 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9121 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9122 * @return {Roo.Element} this
9124 fitToParent : function(monitorResize, targetParent) {
9125 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9126 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9127 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130 var p = Roo.get(targetParent || this.dom.parentNode);
9131 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9132 if (monitorResize === true) {
9133 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9134 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9140 * Gets the next sibling, skipping text nodes
9141 * @return {HTMLElement} The next sibling or null
9143 getNextSibling : function(){
9144 var n = this.dom.nextSibling;
9145 while(n && n.nodeType != 1){
9152 * Gets the previous sibling, skipping text nodes
9153 * @return {HTMLElement} The previous sibling or null
9155 getPrevSibling : function(){
9156 var n = this.dom.previousSibling;
9157 while(n && n.nodeType != 1){
9158 n = n.previousSibling;
9165 * Appends the passed element(s) to this element
9166 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9167 * @return {Roo.Element} this
9169 appendChild: function(el){
9176 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9177 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9178 * automatically generated with the specified attributes.
9179 * @param {HTMLElement} insertBefore (optional) a child element of this element
9180 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9181 * @return {Roo.Element} The new child element
9183 createChild: function(config, insertBefore, returnDom){
9184 config = config || {tag:'div'};
9186 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9192 * Appends this element to the passed element
9193 * @param {String/HTMLElement/Element} el The new parent element
9194 * @return {Roo.Element} this
9196 appendTo: function(el){
9197 el = Roo.getDom(el);
9198 el.appendChild(this.dom);
9203 * Inserts this element before the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert before
9205 * @return {Roo.Element} this
9207 insertBefore: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el);
9214 * Inserts this element after the passed element in the DOM
9215 * @param {String/HTMLElement/Element} el The element to insert after
9216 * @return {Roo.Element} this
9218 insertAfter: function(el){
9219 el = Roo.getDom(el);
9220 el.parentNode.insertBefore(this.dom, el.nextSibling);
9225 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9226 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9227 * @return {Roo.Element} The new child
9229 insertFirst: function(el, returnDom){
9231 if(typeof el == 'object' && !el.nodeType){ // dh config
9232 return this.createChild(el, this.dom.firstChild, returnDom);
9234 el = Roo.getDom(el);
9235 this.dom.insertBefore(el, this.dom.firstChild);
9236 return !returnDom ? Roo.get(el) : el;
9241 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9242 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9243 * @param {String} where (optional) 'before' or 'after' defaults to before
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {Roo.Element} the inserted Element
9247 insertSibling: function(el, where, returnDom){
9248 where = where ? where.toLowerCase() : 'before';
9250 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252 if(typeof el == 'object' && !el.nodeType){ // dh config
9253 if(where == 'after' && !this.dom.nextSibling){
9254 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9261 where == 'before' ? this.dom : this.dom.nextSibling);
9270 * Creates and wraps this element with another element
9271 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9272 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9273 * @return {HTMLElement/Element} The newly created wrapper element
9275 wrap: function(config, returnDom){
9277 config = {tag: "div"};
9279 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9280 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285 * Replaces the passed element with this element
9286 * @param {String/HTMLElement/Element} el The element to replace
9287 * @return {Roo.Element} this
9289 replace: function(el){
9291 this.insertBefore(el);
9297 * Inserts an html fragment into this element
9298 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9299 * @param {String} html The HTML fragment
9300 * @param {Boolean} returnEl True to return an Roo.Element
9301 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303 insertHtml : function(where, html, returnEl){
9304 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9305 return returnEl ? Roo.get(el) : el;
9309 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9310 * @param {Object} o The object with the attributes
9311 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9312 * @return {Roo.Element} this
9314 set : function(o, useSet){
9316 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318 if(attr == "style" || typeof o[attr] == "function") continue;
9320 el.className = o["cls"];
9322 if(useSet) el.setAttribute(attr, o[attr]);
9323 else el[attr] = o[attr];
9327 Roo.DomHelper.applyStyles(el, o.style);
9333 * Convenience method for constructing a KeyMap
9334 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9335 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9336 * @param {Function} fn The function to call
9337 * @param {Object} scope (optional) The scope of the function
9338 * @return {Roo.KeyMap} The KeyMap created
9340 addKeyListener : function(key, fn, scope){
9342 if(typeof key != "object" || key instanceof Array){
9358 return new Roo.KeyMap(this, config);
9362 * Creates a KeyMap for this element
9363 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9364 * @return {Roo.KeyMap} The KeyMap created
9366 addKeyMap : function(config){
9367 return new Roo.KeyMap(this, config);
9371 * Returns true if this element is scrollable.
9374 isScrollable : function(){
9376 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9381 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9382 * @param {Number} value The new scroll value
9383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9384 * @return {Element} this
9387 scrollTo : function(side, value, animate){
9388 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390 this.dom[prop] = value;
9392 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9393 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9399 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9400 * within this element's scrollable range.
9401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9402 * @param {Number} distance How far to scroll the element in pixels
9403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9404 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9405 * was scrolled as far as it could go.
9407 scroll : function(direction, distance, animate){
9408 if(!this.isScrollable()){
9412 var l = el.scrollLeft, t = el.scrollTop;
9413 var w = el.scrollWidth, h = el.scrollHeight;
9414 var cw = el.clientWidth, ch = el.clientHeight;
9415 direction = direction.toLowerCase();
9416 var scrolled = false;
9417 var a = this.preanim(arguments, 2);
9422 var v = Math.min(l + distance, w-cw);
9423 this.scrollTo("left", v, a);
9430 var v = Math.max(l - distance, 0);
9431 this.scrollTo("left", v, a);
9439 var v = Math.max(t - distance, 0);
9440 this.scrollTo("top", v, a);
9448 var v = Math.min(t + distance, h-ch);
9449 this.scrollTo("top", v, a);
9458 * Translates the passed page coordinates into left/top css values for this element
9459 * @param {Number/Array} x The page x or an array containing [x, y]
9460 * @param {Number} y The page y
9461 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463 translatePoints : function(x, y){
9464 if(typeof x == 'object' || x instanceof Array){
9467 var p = this.getStyle('position');
9468 var o = this.getXY();
9470 var l = parseInt(this.getStyle('left'), 10);
9471 var t = parseInt(this.getStyle('top'), 10);
9474 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484 * Returns the current scroll position of the element.
9485 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487 getScroll : function(){
9488 var d = this.dom, doc = document;
9489 if(d == doc || d == doc.body){
9490 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9491 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9492 return {left: l, top: t};
9494 return {left: d.scrollLeft, top: d.scrollTop};
9499 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9500 * are convert to standard 6 digit hex color.
9501 * @param {String} attr The css attribute
9502 * @param {String} defaultValue The default value to use when a valid color isn't found
9503 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506 getColor : function(attr, defaultValue, prefix){
9507 var v = this.getStyle(attr);
9508 if(!v || v == "transparent" || v == "inherit") {
9509 return defaultValue;
9511 var color = typeof prefix == "undefined" ? "#" : prefix;
9512 if(v.substr(0, 4) == "rgb("){
9513 var rvs = v.slice(4, v.length -1).split(",");
9514 for(var i = 0; i < 3; i++){
9515 var h = parseInt(rvs[i]).toString(16);
9522 if(v.substr(0, 1) == "#"){
9524 for(var i = 1; i < 4; i++){
9525 var c = v.charAt(i);
9528 }else if(v.length == 7){
9529 color += v.substr(1);
9533 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9538 * gradient background, rounded corners and a 4-way shadow.
9539 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9540 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9541 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9542 * @return {Roo.Element} this
9544 boxWrap : function(cls){
9545 cls = cls || 'x-box';
9546 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9547 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9553 * @param {String} namespace The namespace in which to look for the attribute
9554 * @param {String} name The attribute name
9555 * @return {String} The attribute value
9557 getAttributeNS : Roo.isIE ? function(ns, name){
9559 var type = typeof d[ns+":"+name];
9560 if(type != 'undefined' && type != 'unknown'){
9561 return d[ns+":"+name];
9564 } : function(ns, name){
9566 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571 * Sets or Returns the value the dom attribute value
9572 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9573 * @param {String} value (optional) The value to set the attribute to
9574 * @return {String} The attribute value
9576 attr : function(name){
9577 if (arguments.length > 1) {
9578 this.dom.setAttribute(name, arguments[1]);
9579 return arguments[1];
9581 if (typeof(name) == 'object') {
9582 for(var i in name) {
9583 this.attr(i, name[i]);
9589 if (!this.dom.hasAttribute(name)) {
9592 return this.dom.getAttribute(name);
9599 var ep = El.prototype;
9602 * Appends an event handler (Shorthand for addListener)
9603 * @param {String} eventName The type of event to append
9604 * @param {Function} fn The method the event invokes
9605 * @param {Object} scope (optional) The scope (this object) of the fn
9606 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9609 ep.on = ep.addListener;
9611 ep.mon = ep.addListener;
9614 * Removes an event handler from this element (shorthand for removeListener)
9615 * @param {String} eventName the type of event to remove
9616 * @param {Function} fn the method the event invokes
9617 * @return {Roo.Element} this
9620 ep.un = ep.removeListener;
9623 * true to automatically adjust width and height settings for box-model issues (default to true)
9625 ep.autoBoxAdjust = true;
9628 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9631 El.addUnits = function(v, defaultUnit){
9632 if(v === "" || v == "auto"){
9635 if(v === undefined){
9638 if(typeof v == "number" || !El.unitPattern.test(v)){
9639 return v + (defaultUnit || 'px');
9644 // special markup used throughout Roo when box wrapping elements
9645 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9647 * Visibility mode constant - Use visibility to hide element
9653 * Visibility mode constant - Use display to hide element
9659 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9660 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9661 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9673 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9674 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9675 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9676 * @return {Element} The Element object
9679 El.get = function(el){
9681 if(!el){ return null; }
9682 if(typeof el == "string"){ // element id
9683 if(!(elm = document.getElementById(el))){
9686 if(ex = El.cache[el]){
9689 ex = El.cache[el] = new El(elm);
9692 }else if(el.tagName){ // dom element
9696 if(ex = El.cache[id]){
9699 ex = El.cache[id] = new El(el);
9702 }else if(el instanceof El){
9704 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9705 // catch case where it hasn't been appended
9706 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9709 }else if(el.isComposite){
9711 }else if(el instanceof Array){
9712 return El.select(el);
9713 }else if(el == document){
9714 // create a bogus element object representing the document object
9716 var f = function(){};
9717 f.prototype = El.prototype;
9719 docEl.dom = document;
9727 El.uncache = function(el){
9728 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9730 delete El.cache[a[i].id || a[i]];
9736 // Garbage collection - uncache elements/purge listeners on orphaned elements
9737 // so we don't hold a reference and cause the browser to retain them
9738 El.garbageCollect = function(){
9739 if(!Roo.enableGarbageCollector){
9740 clearInterval(El.collectorThread);
9743 for(var eid in El.cache){
9744 var el = El.cache[eid], d = el.dom;
9745 // -------------------------------------------------------
9746 // Determining what is garbage:
9747 // -------------------------------------------------------
9749 // dom node is null, definitely garbage
9750 // -------------------------------------------------------
9752 // no parentNode == direct orphan, definitely garbage
9753 // -------------------------------------------------------
9754 // !d.offsetParent && !document.getElementById(eid)
9755 // display none elements have no offsetParent so we will
9756 // also try to look it up by it's id. However, check
9757 // offsetParent first so we don't do unneeded lookups.
9758 // This enables collection of elements that are not orphans
9759 // directly, but somewhere up the line they have an orphan
9761 // -------------------------------------------------------
9762 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9763 delete El.cache[eid];
9764 if(d && Roo.enableListenerCollection){
9770 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9774 El.Flyweight = function(dom){
9777 El.Flyweight.prototype = El.prototype;
9779 El._flyweights = {};
9781 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9782 * the dom node can be overwritten by other code.
9783 * @param {String/HTMLElement} el The dom node or id
9784 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9785 * prevent conflicts (e.g. internally Roo uses "_internal")
9787 * @return {Element} The shared Element object
9789 El.fly = function(el, named){
9790 named = named || '_global';
9791 el = Roo.getDom(el);
9795 if(!El._flyweights[named]){
9796 El._flyweights[named] = new El.Flyweight();
9798 El._flyweights[named].dom = el;
9799 return El._flyweights[named];
9803 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9804 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9805 * Shorthand of {@link Roo.Element#get}
9806 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9807 * @return {Element} The Element object
9813 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9814 * the dom node can be overwritten by other code.
9815 * Shorthand of {@link Roo.Element#fly}
9816 * @param {String/HTMLElement} el The dom node or id
9817 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9818 * prevent conflicts (e.g. internally Roo uses "_internal")
9820 * @return {Element} The shared Element object
9826 // speedy lookup for elements never to box adjust
9827 var noBoxAdjust = Roo.isStrict ? {
9830 input:1, select:1, textarea:1
9832 if(Roo.isIE || Roo.isGecko){
9833 noBoxAdjust['button'] = 1;
9837 Roo.EventManager.on(window, 'unload', function(){
9839 delete El._flyweights;
9847 Roo.Element.selectorFunction = Roo.DomQuery.select;
9850 Roo.Element.select = function(selector, unique, root){
9852 if(typeof selector == "string"){
9853 els = Roo.Element.selectorFunction(selector, root);
9854 }else if(selector.length !== undefined){
9857 throw "Invalid selector";
9859 if(unique === true){
9860 return new Roo.CompositeElement(els);
9862 return new Roo.CompositeElementLite(els);
9866 * Selects elements based on the passed CSS selector to enable working on them as 1.
9867 * @param {String/Array} selector The CSS selector or an array of elements
9868 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9869 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9870 * @return {CompositeElementLite/CompositeElement}
9874 Roo.select = Roo.Element.select;
9891 * Ext JS Library 1.1.1
9892 * Copyright(c) 2006-2007, Ext JS, LLC.
9894 * Originally Released Under LGPL - original licence link has changed is not relivant.
9897 * <script type="text/javascript">
9902 //Notifies Element that fx methods are available
9903 Roo.enableFx = true;
9907 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9908 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9909 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9910 * Element effects to work.</p><br/>
9912 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9913 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9914 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9915 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9916 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9917 * expected results and should be done with care.</p><br/>
9919 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9920 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9923 ----- -----------------------------
9924 tl The top left corner
9925 t The center of the top edge
9926 tr The top right corner
9927 l The center of the left edge
9928 r The center of the right edge
9929 bl The bottom left corner
9930 b The center of the bottom edge
9931 br The bottom right corner
9933 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9934 * below are common options that can be passed to any Fx method.</b>
9935 * @cfg {Function} callback A function called when the effect is finished
9936 * @cfg {Object} scope The scope of the effect function
9937 * @cfg {String} easing A valid Easing value for the effect
9938 * @cfg {String} afterCls A css class to apply after the effect
9939 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9940 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9941 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9942 * effects that end with the element being visually hidden, ignored otherwise)
9943 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9944 * a function which returns such a specification that will be applied to the Element after the effect finishes
9945 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9946 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
9947 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9951 * Slides the element into view. An anchor point can be optionally passed to set the point of
9952 * origin for the slide effect. This function automatically handles wrapping the element with
9953 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9956 // default: slide the element in from the top
9959 // custom: slide the element in from the right with a 2-second duration
9960 el.slideIn('r', { duration: 2 });
9962 // common config options shown with default values
9968 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9969 * @param {Object} options (optional) Object literal with any of the Fx config options
9970 * @return {Roo.Element} The Element
9972 slideIn : function(anchor, o){
9973 var el = this.getFxEl();
9976 el.queueFx(o, function(){
9978 anchor = anchor || "t";
9980 // fix display to visibility
9983 // restore values after effect
9984 var r = this.getFxRestore();
9985 var b = this.getBox();
9986 // fixed size for slide
9990 var wrap = this.fxWrap(r.pos, o, "hidden");
9992 var st = this.dom.style;
9993 st.visibility = "visible";
9994 st.position = "absolute";
9996 // clear out temp styles after slide and unwrap
9997 var after = function(){
9998 el.fxUnwrap(wrap, r.pos, o);
10000 st.height = r.height;
10003 // time to calc the positions
10004 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10006 switch(anchor.toLowerCase()){
10008 wrap.setSize(b.width, 0);
10009 st.left = st.bottom = "0";
10013 wrap.setSize(0, b.height);
10014 st.right = st.top = "0";
10018 wrap.setSize(0, b.height);
10019 wrap.setX(b.right);
10020 st.left = st.top = "0";
10021 a = {width: bw, points: pt};
10024 wrap.setSize(b.width, 0);
10025 wrap.setY(b.bottom);
10026 st.left = st.top = "0";
10027 a = {height: bh, points: pt};
10030 wrap.setSize(0, 0);
10031 st.right = st.bottom = "0";
10032 a = {width: bw, height: bh};
10035 wrap.setSize(0, 0);
10036 wrap.setY(b.y+b.height);
10037 st.right = st.top = "0";
10038 a = {width: bw, height: bh, points: pt};
10041 wrap.setSize(0, 0);
10042 wrap.setXY([b.right, b.bottom]);
10043 st.left = st.top = "0";
10044 a = {width: bw, height: bh, points: pt};
10047 wrap.setSize(0, 0);
10048 wrap.setX(b.x+b.width);
10049 st.left = st.bottom = "0";
10050 a = {width: bw, height: bh, points: pt};
10053 this.dom.style.visibility = "visible";
10056 arguments.callee.anim = wrap.fxanim(a,
10066 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10067 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10068 * 'hidden') but block elements will still take up space in the document. The element must be removed
10069 * from the DOM using the 'remove' config option if desired. This function automatically handles
10070 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10073 // default: slide the element out to the top
10076 // custom: slide the element out to the right with a 2-second duration
10077 el.slideOut('r', { duration: 2 });
10079 // common config options shown with default values
10087 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10088 * @param {Object} options (optional) Object literal with any of the Fx config options
10089 * @return {Roo.Element} The Element
10091 slideOut : function(anchor, o){
10092 var el = this.getFxEl();
10095 el.queueFx(o, function(){
10097 anchor = anchor || "t";
10099 // restore values after effect
10100 var r = this.getFxRestore();
10102 var b = this.getBox();
10103 // fixed size for slide
10107 var wrap = this.fxWrap(r.pos, o, "visible");
10109 var st = this.dom.style;
10110 st.visibility = "visible";
10111 st.position = "absolute";
10115 var after = function(){
10117 el.setDisplayed(false);
10122 el.fxUnwrap(wrap, r.pos, o);
10124 st.width = r.width;
10125 st.height = r.height;
10130 var a, zero = {to: 0};
10131 switch(anchor.toLowerCase()){
10133 st.left = st.bottom = "0";
10134 a = {height: zero};
10137 st.right = st.top = "0";
10141 st.left = st.top = "0";
10142 a = {width: zero, points: {to:[b.right, b.y]}};
10145 st.left = st.top = "0";
10146 a = {height: zero, points: {to:[b.x, b.bottom]}};
10149 st.right = st.bottom = "0";
10150 a = {width: zero, height: zero};
10153 st.right = st.top = "0";
10154 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10157 st.left = st.top = "0";
10158 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10161 st.left = st.bottom = "0";
10162 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10166 arguments.callee.anim = wrap.fxanim(a,
10176 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10177 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10178 * The element must be removed from the DOM using the 'remove' config option if desired.
10184 // common config options shown with default values
10192 * @param {Object} options (optional) Object literal with any of the Fx config options
10193 * @return {Roo.Element} The Element
10195 puff : function(o){
10196 var el = this.getFxEl();
10199 el.queueFx(o, function(){
10200 this.clearOpacity();
10203 // restore values after effect
10204 var r = this.getFxRestore();
10205 var st = this.dom.style;
10207 var after = function(){
10209 el.setDisplayed(false);
10216 el.setPositioning(r.pos);
10217 st.width = r.width;
10218 st.height = r.height;
10223 var width = this.getWidth();
10224 var height = this.getHeight();
10226 arguments.callee.anim = this.fxanim({
10227 width : {to: this.adjustWidth(width * 2)},
10228 height : {to: this.adjustHeight(height * 2)},
10229 points : {by: [-(width * .5), -(height * .5)]},
10231 fontSize: {to:200, unit: "%"}
10242 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10243 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10244 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10250 // all config options shown with default values
10258 * @param {Object} options (optional) Object literal with any of the Fx config options
10259 * @return {Roo.Element} The Element
10261 switchOff : function(o){
10262 var el = this.getFxEl();
10265 el.queueFx(o, function(){
10266 this.clearOpacity();
10269 // restore values after effect
10270 var r = this.getFxRestore();
10271 var st = this.dom.style;
10273 var after = function(){
10275 el.setDisplayed(false);
10281 el.setPositioning(r.pos);
10282 st.width = r.width;
10283 st.height = r.height;
10288 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10289 this.clearOpacity();
10293 points:{by:[0, this.getHeight() * .5]}
10294 }, o, 'motion', 0.3, 'easeIn', after);
10295 }).defer(100, this);
10302 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10303 * changed using the "attr" config option) and then fading back to the original color. If no original
10304 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10307 // default: highlight background to yellow
10310 // custom: highlight foreground text to blue for 2 seconds
10311 el.highlight("0000ff", { attr: 'color', duration: 2 });
10313 // common config options shown with default values
10314 el.highlight("ffff9c", {
10315 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10316 endColor: (current color) or "ffffff",
10321 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10322 * @param {Object} options (optional) Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 highlight : function(color, o){
10326 var el = this.getFxEl();
10329 el.queueFx(o, function(){
10330 color = color || "ffff9c";
10331 attr = o.attr || "backgroundColor";
10333 this.clearOpacity();
10336 var origColor = this.getColor(attr);
10337 var restoreColor = this.dom.style[attr];
10338 endColor = (o.endColor || origColor) || "ffffff";
10340 var after = function(){
10341 el.dom.style[attr] = restoreColor;
10346 a[attr] = {from: color, to: endColor};
10347 arguments.callee.anim = this.fxanim(a,
10357 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10360 // default: a single light blue ripple
10363 // custom: 3 red ripples lasting 3 seconds total
10364 el.frame("ff0000", 3, { duration: 3 });
10366 // common config options shown with default values
10367 el.frame("C3DAF9", 1, {
10368 duration: 1 //duration of entire animation (not each individual ripple)
10369 // Note: Easing is not configurable and will be ignored if included
10372 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10373 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10374 * @param {Object} options (optional) Object literal with any of the Fx config options
10375 * @return {Roo.Element} The Element
10377 frame : function(color, count, o){
10378 var el = this.getFxEl();
10381 el.queueFx(o, function(){
10382 color = color || "#C3DAF9";
10383 if(color.length == 6){
10384 color = "#" + color;
10386 count = count || 1;
10387 duration = o.duration || 1;
10390 var b = this.getBox();
10391 var animFn = function(){
10392 var proxy = this.createProxy({
10395 visbility:"hidden",
10396 position:"absolute",
10397 "z-index":"35000", // yee haw
10398 border:"0px solid " + color
10401 var scale = Roo.isBorderBox ? 2 : 1;
10403 top:{from:b.y, to:b.y - 20},
10404 left:{from:b.x, to:b.x - 20},
10405 borderWidth:{from:0, to:10},
10406 opacity:{from:1, to:0},
10407 height:{from:b.height, to:(b.height + (20*scale))},
10408 width:{from:b.width, to:(b.width + (20*scale))}
10409 }, duration, function(){
10413 animFn.defer((duration/2)*1000, this);
10424 * Creates a pause before any subsequent queued effects begin. If there are
10425 * no effects queued after the pause it will have no effect.
10430 * @param {Number} seconds The length of time to pause (in seconds)
10431 * @return {Roo.Element} The Element
10433 pause : function(seconds){
10434 var el = this.getFxEl();
10437 el.queueFx(o, function(){
10438 setTimeout(function(){
10440 }, seconds * 1000);
10446 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade in from opacity 0 to 100%
10453 // custom: fade in from opacity 0 to 75% over 2 seconds
10454 el.fadeIn({ endOpacity: .75, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10463 * @param {Object} options (optional) Object literal with any of the Fx config options
10464 * @return {Roo.Element} The Element
10466 fadeIn : function(o){
10467 var el = this.getFxEl();
10469 el.queueFx(o, function(){
10470 this.setOpacity(0);
10472 this.dom.style.visibility = 'visible';
10473 var to = o.endOpacity || 1;
10474 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10475 o, null, .5, "easeOut", function(){
10477 this.clearOpacity();
10486 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10487 * using the "endOpacity" config option.
10490 // default: fade out from the element's current opacity to 0
10493 // custom: fade out from the element's current opacity to 25% over 2 seconds
10494 el.fadeOut({ endOpacity: .25, duration: 2});
10496 // common config options shown with default values
10498 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 fadeOut : function(o){
10509 var el = this.getFxEl();
10511 el.queueFx(o, function(){
10512 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10513 o, null, .5, "easeOut", function(){
10514 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10515 this.dom.style.display = "none";
10517 this.dom.style.visibility = "hidden";
10519 this.clearOpacity();
10527 * Animates the transition of an element's dimensions from a starting height/width
10528 * to an ending height/width.
10531 // change height and width to 100x100 pixels
10532 el.scale(100, 100);
10534 // common config options shown with default values. The height and width will default to
10535 // the element's existing values if passed as null.
10538 [element's height], {
10543 * @param {Number} width The new width (pass undefined to keep the original width)
10544 * @param {Number} height The new height (pass undefined to keep the original height)
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 scale : function(w, h, o){
10549 this.shift(Roo.apply({}, o, {
10557 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10558 * Any of these properties not specified in the config object will not be changed. This effect
10559 * requires that at least one new dimension, position or opacity setting must be passed in on
10560 * the config object in order for the function to have any effect.
10563 // slide the element horizontally to x position 200 while changing the height and opacity
10564 el.shift({ x: 200, height: 50, opacity: .8 });
10566 // common config options shown with default values.
10568 width: [element's width],
10569 height: [element's height],
10570 x: [element's x position],
10571 y: [element's y position],
10572 opacity: [element's opacity],
10577 * @param {Object} options Object literal with any of the Fx config options
10578 * @return {Roo.Element} The Element
10580 shift : function(o){
10581 var el = this.getFxEl();
10583 el.queueFx(o, function(){
10584 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10585 if(w !== undefined){
10586 a.width = {to: this.adjustWidth(w)};
10588 if(h !== undefined){
10589 a.height = {to: this.adjustHeight(h)};
10591 if(x !== undefined || y !== undefined){
10593 x !== undefined ? x : this.getX(),
10594 y !== undefined ? y : this.getY()
10597 if(op !== undefined){
10598 a.opacity = {to: op};
10600 if(o.xy !== undefined){
10601 a.points = {to: o.xy};
10603 arguments.callee.anim = this.fxanim(a,
10604 o, 'motion', .35, "easeOut", function(){
10612 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10613 * ending point of the effect.
10616 // default: slide the element downward while fading out
10619 // custom: slide the element out to the right with a 2-second duration
10620 el.ghost('r', { duration: 2 });
10622 // common config options shown with default values
10630 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10631 * @param {Object} options (optional) Object literal with any of the Fx config options
10632 * @return {Roo.Element} The Element
10634 ghost : function(anchor, o){
10635 var el = this.getFxEl();
10638 el.queueFx(o, function(){
10639 anchor = anchor || "b";
10641 // restore values after effect
10642 var r = this.getFxRestore();
10643 var w = this.getWidth(),
10644 h = this.getHeight();
10646 var st = this.dom.style;
10648 var after = function(){
10650 el.setDisplayed(false);
10656 el.setPositioning(r.pos);
10657 st.width = r.width;
10658 st.height = r.height;
10663 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10664 switch(anchor.toLowerCase()){
10691 arguments.callee.anim = this.fxanim(a,
10701 * Ensures that all effects queued after syncFx is called on the element are
10702 * run concurrently. This is the opposite of {@link #sequenceFx}.
10703 * @return {Roo.Element} The Element
10705 syncFx : function(){
10706 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10715 * Ensures that all effects queued after sequenceFx is called on the element are
10716 * run in sequence. This is the opposite of {@link #syncFx}.
10717 * @return {Roo.Element} The Element
10719 sequenceFx : function(){
10720 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10722 concurrent : false,
10729 nextFx : function(){
10730 var ef = this.fxQueue[0];
10737 * Returns true if the element has any effects actively running or queued, else returns false.
10738 * @return {Boolean} True if element has active effects, else false
10740 hasActiveFx : function(){
10741 return this.fxQueue && this.fxQueue[0];
10745 * Stops any running effects and clears the element's internal effects queue if it contains
10746 * any additional effects that haven't started yet.
10747 * @return {Roo.Element} The Element
10749 stopFx : function(){
10750 if(this.hasActiveFx()){
10751 var cur = this.fxQueue[0];
10752 if(cur && cur.anim && cur.anim.isAnimated()){
10753 this.fxQueue = [cur]; // clear out others
10754 cur.anim.stop(true);
10761 beforeFx : function(o){
10762 if(this.hasActiveFx() && !o.concurrent){
10773 * Returns true if the element is currently blocking so that no other effect can be queued
10774 * until this effect is finished, else returns false if blocking is not set. This is commonly
10775 * used to ensure that an effect initiated by a user action runs to completion prior to the
10776 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10777 * @return {Boolean} True if blocking, else false
10779 hasFxBlock : function(){
10780 var q = this.fxQueue;
10781 return q && q[0] && q[0].block;
10785 queueFx : function(o, fn){
10789 if(!this.hasFxBlock()){
10790 Roo.applyIf(o, this.fxDefaults);
10792 var run = this.beforeFx(o);
10793 fn.block = o.block;
10794 this.fxQueue.push(fn);
10806 fxWrap : function(pos, o, vis){
10808 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10811 wrapXY = this.getXY();
10813 var div = document.createElement("div");
10814 div.style.visibility = vis;
10815 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10816 wrap.setPositioning(pos);
10817 if(wrap.getStyle("position") == "static"){
10818 wrap.position("relative");
10820 this.clearPositioning('auto');
10822 wrap.dom.appendChild(this.dom);
10824 wrap.setXY(wrapXY);
10831 fxUnwrap : function(wrap, pos, o){
10832 this.clearPositioning();
10833 this.setPositioning(pos);
10835 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10841 getFxRestore : function(){
10842 var st = this.dom.style;
10843 return {pos: this.getPositioning(), width: st.width, height : st.height};
10847 afterFx : function(o){
10849 this.applyStyles(o.afterStyle);
10852 this.addClass(o.afterCls);
10854 if(o.remove === true){
10857 Roo.callback(o.callback, o.scope, [this]);
10859 this.fxQueue.shift();
10865 getFxEl : function(){ // support for composite element fx
10866 return Roo.get(this.dom);
10870 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10871 animType = animType || 'run';
10873 var anim = Roo.lib.Anim[animType](
10875 (opt.duration || defaultDur) || .35,
10876 (opt.easing || defaultEase) || 'easeOut',
10878 Roo.callback(cb, this);
10887 // backwords compat
10888 Roo.Fx.resize = Roo.Fx.scale;
10890 //When included, Roo.Fx is automatically applied to Element so that all basic
10891 //effects are available directly via the Element API
10892 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10894 * Ext JS Library 1.1.1
10895 * Copyright(c) 2006-2007, Ext JS, LLC.
10897 * Originally Released Under LGPL - original licence link has changed is not relivant.
10900 * <script type="text/javascript">
10905 * @class Roo.CompositeElement
10906 * Standard composite class. Creates a Roo.Element for every element in the collection.
10908 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10909 * actions will be performed on all the elements in this collection.</b>
10911 * All methods return <i>this</i> and can be chained.
10913 var els = Roo.select("#some-el div.some-class", true);
10914 // or select directly from an existing element
10915 var el = Roo.get('some-el');
10916 el.select('div.some-class', true);
10918 els.setWidth(100); // all elements become 100 width
10919 els.hide(true); // all elements fade out and hide
10921 els.setWidth(100).hide(true);
10924 Roo.CompositeElement = function(els){
10925 this.elements = [];
10926 this.addElements(els);
10928 Roo.CompositeElement.prototype = {
10930 addElements : function(els){
10931 if(!els) return this;
10932 if(typeof els == "string"){
10933 els = Roo.Element.selectorFunction(els);
10935 var yels = this.elements;
10936 var index = yels.length-1;
10937 for(var i = 0, len = els.length; i < len; i++) {
10938 yels[++index] = Roo.get(els[i]);
10944 * Clears this composite and adds the elements returned by the passed selector.
10945 * @param {String/Array} els A string CSS selector, an array of elements or an element
10946 * @return {CompositeElement} this
10948 fill : function(els){
10949 this.elements = [];
10955 * Filters this composite to only elements that match the passed selector.
10956 * @param {String} selector A string CSS selector
10957 * @param {Boolean} inverse return inverse filter (not matches)
10958 * @return {CompositeElement} this
10960 filter : function(selector, inverse){
10962 inverse = inverse || false;
10963 this.each(function(el){
10964 var match = inverse ? !el.is(selector) : el.is(selector);
10966 els[els.length] = el.dom;
10973 invoke : function(fn, args){
10974 var els = this.elements;
10975 for(var i = 0, len = els.length; i < len; i++) {
10976 Roo.Element.prototype[fn].apply(els[i], args);
10981 * Adds elements to this composite.
10982 * @param {String/Array} els A string CSS selector, an array of elements or an element
10983 * @return {CompositeElement} this
10985 add : function(els){
10986 if(typeof els == "string"){
10987 this.addElements(Roo.Element.selectorFunction(els));
10988 }else if(els.length !== undefined){
10989 this.addElements(els);
10991 this.addElements([els]);
10996 * Calls the passed function passing (el, this, index) for each element in this composite.
10997 * @param {Function} fn The function to call
10998 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10999 * @return {CompositeElement} this
11001 each : function(fn, scope){
11002 var els = this.elements;
11003 for(var i = 0, len = els.length; i < len; i++){
11004 if(fn.call(scope || els[i], els[i], this, i) === false) {
11012 * Returns the Element object at the specified index
11013 * @param {Number} index
11014 * @return {Roo.Element}
11016 item : function(index){
11017 return this.elements[index] || null;
11021 * Returns the first Element
11022 * @return {Roo.Element}
11024 first : function(){
11025 return this.item(0);
11029 * Returns the last Element
11030 * @return {Roo.Element}
11033 return this.item(this.elements.length-1);
11037 * Returns the number of elements in this composite
11040 getCount : function(){
11041 return this.elements.length;
11045 * Returns true if this composite contains the passed element
11048 contains : function(el){
11049 return this.indexOf(el) !== -1;
11053 * Returns true if this composite contains the passed element
11056 indexOf : function(el){
11057 return this.elements.indexOf(Roo.get(el));
11062 * Removes the specified element(s).
11063 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11064 * or an array of any of those.
11065 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11066 * @return {CompositeElement} this
11068 removeElement : function(el, removeDom){
11069 if(el instanceof Array){
11070 for(var i = 0, len = el.length; i < len; i++){
11071 this.removeElement(el[i]);
11075 var index = typeof el == 'number' ? el : this.indexOf(el);
11078 var d = this.elements[index];
11082 d.parentNode.removeChild(d);
11085 this.elements.splice(index, 1);
11091 * Replaces the specified element with the passed element.
11092 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11094 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11095 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11096 * @return {CompositeElement} this
11098 replaceElement : function(el, replacement, domReplace){
11099 var index = typeof el == 'number' ? el : this.indexOf(el);
11102 this.elements[index].replaceWith(replacement);
11104 this.elements.splice(index, 1, Roo.get(replacement))
11111 * Removes all elements.
11113 clear : function(){
11114 this.elements = [];
11118 Roo.CompositeElement.createCall = function(proto, fnName){
11119 if(!proto[fnName]){
11120 proto[fnName] = function(){
11121 return this.invoke(fnName, arguments);
11125 for(var fnName in Roo.Element.prototype){
11126 if(typeof Roo.Element.prototype[fnName] == "function"){
11127 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11133 * Ext JS Library 1.1.1
11134 * Copyright(c) 2006-2007, Ext JS, LLC.
11136 * Originally Released Under LGPL - original licence link has changed is not relivant.
11139 * <script type="text/javascript">
11143 * @class Roo.CompositeElementLite
11144 * @extends Roo.CompositeElement
11145 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11147 var els = Roo.select("#some-el div.some-class");
11148 // or select directly from an existing element
11149 var el = Roo.get('some-el');
11150 el.select('div.some-class');
11152 els.setWidth(100); // all elements become 100 width
11153 els.hide(true); // all elements fade out and hide
11155 els.setWidth(100).hide(true);
11156 </code></pre><br><br>
11157 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11158 * actions will be performed on all the elements in this collection.</b>
11160 Roo.CompositeElementLite = function(els){
11161 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11162 this.el = new Roo.Element.Flyweight();
11164 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11165 addElements : function(els){
11167 if(els instanceof Array){
11168 this.elements = this.elements.concat(els);
11170 var yels = this.elements;
11171 var index = yels.length-1;
11172 for(var i = 0, len = els.length; i < len; i++) {
11173 yels[++index] = els[i];
11179 invoke : function(fn, args){
11180 var els = this.elements;
11182 for(var i = 0, len = els.length; i < len; i++) {
11184 Roo.Element.prototype[fn].apply(el, args);
11189 * Returns a flyweight Element of the dom element object at the specified index
11190 * @param {Number} index
11191 * @return {Roo.Element}
11193 item : function(index){
11194 if(!this.elements[index]){
11197 this.el.dom = this.elements[index];
11201 // fixes scope with flyweight
11202 addListener : function(eventName, handler, scope, opt){
11203 var els = this.elements;
11204 for(var i = 0, len = els.length; i < len; i++) {
11205 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11211 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11212 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11213 * a reference to the dom node, use el.dom.</b>
11214 * @param {Function} fn The function to call
11215 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11216 * @return {CompositeElement} this
11218 each : function(fn, scope){
11219 var els = this.elements;
11221 for(var i = 0, len = els.length; i < len; i++){
11223 if(fn.call(scope || el, el, this, i) === false){
11230 indexOf : function(el){
11231 return this.elements.indexOf(Roo.getDom(el));
11234 replaceElement : function(el, replacement, domReplace){
11235 var index = typeof el == 'number' ? el : this.indexOf(el);
11237 replacement = Roo.getDom(replacement);
11239 var d = this.elements[index];
11240 d.parentNode.insertBefore(replacement, d);
11241 d.parentNode.removeChild(d);
11243 this.elements.splice(index, 1, replacement);
11248 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11252 * Ext JS Library 1.1.1
11253 * Copyright(c) 2006-2007, Ext JS, LLC.
11255 * Originally Released Under LGPL - original licence link has changed is not relivant.
11258 * <script type="text/javascript">
11264 * @class Roo.data.Connection
11265 * @extends Roo.util.Observable
11266 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11267 * either to a configured URL, or to a URL specified at request time.<br><br>
11269 * Requests made by this class are asynchronous, and will return immediately. No data from
11270 * the server will be available to the statement immediately following the {@link #request} call.
11271 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11273 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11274 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11275 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11276 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11277 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11278 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11279 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11280 * standard DOM methods.
11282 * @param {Object} config a configuration object.
11284 Roo.data.Connection = function(config){
11285 Roo.apply(this, config);
11288 * @event beforerequest
11289 * Fires before a network request is made to retrieve a data object.
11290 * @param {Connection} conn This Connection object.
11291 * @param {Object} options The options config object passed to the {@link #request} method.
11293 "beforerequest" : true,
11295 * @event requestcomplete
11296 * Fires if the request was successfully completed.
11297 * @param {Connection} conn This Connection object.
11298 * @param {Object} response The XHR object containing the response data.
11299 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11300 * @param {Object} options The options config object passed to the {@link #request} method.
11302 "requestcomplete" : true,
11304 * @event requestexception
11305 * Fires if an error HTTP status was returned from the server.
11306 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11307 * @param {Connection} conn This Connection object.
11308 * @param {Object} response The XHR object containing the response data.
11309 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11310 * @param {Object} options The options config object passed to the {@link #request} method.
11312 "requestexception" : true
11314 Roo.data.Connection.superclass.constructor.call(this);
11317 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11319 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11322 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11323 * extra parameters to each request made by this object. (defaults to undefined)
11326 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11327 * to each request made by this object. (defaults to undefined)
11330 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11333 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11337 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11343 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11346 disableCaching: true,
11349 * Sends an HTTP request to a remote server.
11350 * @param {Object} options An object which may contain the following properties:<ul>
11351 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11352 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11353 * request, a url encoded string or a function to call to get either.</li>
11354 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11355 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11356 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11357 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11358 * <li>options {Object} The parameter to the request call.</li>
11359 * <li>success {Boolean} True if the request succeeded.</li>
11360 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11363 * The callback is passed the following parameters:<ul>
11364 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11365 * <li>options {Object} The parameter to the request call.</li>
11367 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11368 * The callback is passed the following parameters:<ul>
11369 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11370 * <li>options {Object} The parameter to the request call.</li>
11372 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11373 * for the callback function. Defaults to the browser window.</li>
11374 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11375 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11376 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11377 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11378 * params for the post data. Any params will be appended to the URL.</li>
11379 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11381 * @return {Number} transactionId
11383 request : function(o){
11384 if(this.fireEvent("beforerequest", this, o) !== false){
11387 if(typeof p == "function"){
11388 p = p.call(o.scope||window, o);
11390 if(typeof p == "object"){
11391 p = Roo.urlEncode(o.params);
11393 if(this.extraParams){
11394 var extras = Roo.urlEncode(this.extraParams);
11395 p = p ? (p + '&' + extras) : extras;
11398 var url = o.url || this.url;
11399 if(typeof url == 'function'){
11400 url = url.call(o.scope||window, o);
11404 var form = Roo.getDom(o.form);
11405 url = url || form.action;
11407 var enctype = form.getAttribute("enctype");
11408 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11409 return this.doFormUpload(o, p, url);
11411 var f = Roo.lib.Ajax.serializeForm(form);
11412 p = p ? (p + '&' + f) : f;
11415 var hs = o.headers;
11416 if(this.defaultHeaders){
11417 hs = Roo.apply(hs || {}, this.defaultHeaders);
11424 success: this.handleResponse,
11425 failure: this.handleFailure,
11427 argument: {options: o},
11428 timeout : o.timeout || this.timeout
11431 var method = o.method||this.method||(p ? "POST" : "GET");
11433 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11434 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11437 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11441 }else if(this.autoAbort !== false){
11445 if((method == 'GET' && p) || o.xmlData){
11446 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11449 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11450 return this.transId;
11452 Roo.callback(o.callback, o.scope, [o, null, null]);
11458 * Determine whether this object has a request outstanding.
11459 * @param {Number} transactionId (Optional) defaults to the last transaction
11460 * @return {Boolean} True if there is an outstanding request.
11462 isLoading : function(transId){
11464 return Roo.lib.Ajax.isCallInProgress(transId);
11466 return this.transId ? true : false;
11471 * Aborts any outstanding request.
11472 * @param {Number} transactionId (Optional) defaults to the last transaction
11474 abort : function(transId){
11475 if(transId || this.isLoading()){
11476 Roo.lib.Ajax.abort(transId || this.transId);
11481 handleResponse : function(response){
11482 this.transId = false;
11483 var options = response.argument.options;
11484 response.argument = options ? options.argument : null;
11485 this.fireEvent("requestcomplete", this, response, options);
11486 Roo.callback(options.success, options.scope, [response, options]);
11487 Roo.callback(options.callback, options.scope, [options, true, response]);
11491 handleFailure : function(response, e){
11492 this.transId = false;
11493 var options = response.argument.options;
11494 response.argument = options ? options.argument : null;
11495 this.fireEvent("requestexception", this, response, options, e);
11496 Roo.callback(options.failure, options.scope, [response, options]);
11497 Roo.callback(options.callback, options.scope, [options, false, response]);
11501 doFormUpload : function(o, ps, url){
11503 var frame = document.createElement('iframe');
11506 frame.className = 'x-hidden';
11508 frame.src = Roo.SSL_SECURE_URL;
11510 document.body.appendChild(frame);
11513 document.frames[id].name = id;
11516 var form = Roo.getDom(o.form);
11518 form.method = 'POST';
11519 form.enctype = form.encoding = 'multipart/form-data';
11525 if(ps){ // add dynamic params
11527 ps = Roo.urlDecode(ps, false);
11529 if(ps.hasOwnProperty(k)){
11530 hd = document.createElement('input');
11531 hd.type = 'hidden';
11534 form.appendChild(hd);
11541 var r = { // bogus response object
11546 r.argument = o ? o.argument : null;
11551 doc = frame.contentWindow.document;
11553 doc = (frame.contentDocument || window.frames[id].document);
11555 if(doc && doc.body){
11556 r.responseText = doc.body.innerHTML;
11558 if(doc && doc.XMLDocument){
11559 r.responseXML = doc.XMLDocument;
11561 r.responseXML = doc;
11568 Roo.EventManager.removeListener(frame, 'load', cb, this);
11570 this.fireEvent("requestcomplete", this, r, o);
11571 Roo.callback(o.success, o.scope, [r, o]);
11572 Roo.callback(o.callback, o.scope, [o, true, r]);
11574 setTimeout(function(){document.body.removeChild(frame);}, 100);
11577 Roo.EventManager.on(frame, 'load', cb, this);
11580 if(hiddens){ // remove dynamic params
11581 for(var i = 0, len = hiddens.length; i < len; i++){
11582 form.removeChild(hiddens[i]);
11589 * Ext JS Library 1.1.1
11590 * Copyright(c) 2006-2007, Ext JS, LLC.
11592 * Originally Released Under LGPL - original licence link has changed is not relivant.
11595 * <script type="text/javascript">
11599 * Global Ajax request class.
11602 * @extends Roo.data.Connection
11605 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11606 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11607 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11608 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11609 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11610 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11611 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11613 Roo.Ajax = new Roo.data.Connection({
11622 * Serialize the passed form into a url encoded string
11624 * @param {String/HTMLElement} form
11627 serializeForm : function(form){
11628 return Roo.lib.Ajax.serializeForm(form);
11632 * Ext JS Library 1.1.1
11633 * Copyright(c) 2006-2007, Ext JS, LLC.
11635 * Originally Released Under LGPL - original licence link has changed is not relivant.
11638 * <script type="text/javascript">
11643 * @class Roo.UpdateManager
11644 * @extends Roo.util.Observable
11645 * Provides AJAX-style update for Element object.<br><br>
11648 * // Get it from a Roo.Element object
11649 * var el = Roo.get("foo");
11650 * var mgr = el.getUpdateManager();
11651 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11653 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11655 * // or directly (returns the same UpdateManager instance)
11656 * var mgr = new Roo.UpdateManager("myElementId");
11657 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11658 * mgr.on("update", myFcnNeedsToKnow);
11660 // short handed call directly from the element object
11661 Roo.get("foo").load({
11665 text: "Loading Foo..."
11669 * Create new UpdateManager directly.
11670 * @param {String/HTMLElement/Roo.Element} el The element to update
11671 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11673 Roo.UpdateManager = function(el, forceNew){
11675 if(!forceNew && el.updateManager){
11676 return el.updateManager;
11679 * The Element object
11680 * @type Roo.Element
11684 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11687 this.defaultUrl = null;
11691 * @event beforeupdate
11692 * Fired before an update is made, return false from your handler and the update is cancelled.
11693 * @param {Roo.Element} el
11694 * @param {String/Object/Function} url
11695 * @param {String/Object} params
11697 "beforeupdate": true,
11700 * Fired after successful update is made.
11701 * @param {Roo.Element} el
11702 * @param {Object} oResponseObject The response Object
11707 * Fired on update failure.
11708 * @param {Roo.Element} el
11709 * @param {Object} oResponseObject The response Object
11713 var d = Roo.UpdateManager.defaults;
11715 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11718 this.sslBlankUrl = d.sslBlankUrl;
11720 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11723 this.disableCaching = d.disableCaching;
11725 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11728 this.indicatorText = d.indicatorText;
11730 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11733 this.showLoadIndicator = d.showLoadIndicator;
11735 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11738 this.timeout = d.timeout;
11741 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11744 this.loadScripts = d.loadScripts;
11747 * Transaction object of current executing transaction
11749 this.transaction = null;
11754 this.autoRefreshProcId = null;
11756 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11759 this.refreshDelegate = this.refresh.createDelegate(this);
11761 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11764 this.updateDelegate = this.update.createDelegate(this);
11766 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11769 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11773 this.successDelegate = this.processSuccess.createDelegate(this);
11777 this.failureDelegate = this.processFailure.createDelegate(this);
11779 if(!this.renderer){
11781 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11783 this.renderer = new Roo.UpdateManager.BasicRenderer();
11786 Roo.UpdateManager.superclass.constructor.call(this);
11789 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11791 * Get the Element this UpdateManager is bound to
11792 * @return {Roo.Element} The element
11794 getEl : function(){
11798 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11799 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11802 url: "your-url.php",<br/>
11803 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11804 callback: yourFunction,<br/>
11805 scope: yourObject, //(optional scope) <br/>
11806 discardUrl: false, <br/>
11807 nocache: false,<br/>
11808 text: "Loading...",<br/>
11810 scripts: false<br/>
11813 * The only required property is url. The optional properties nocache, text and scripts
11814 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11815 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11816 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11817 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11819 update : function(url, params, callback, discardUrl){
11820 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11821 var method = this.method,
11823 if(typeof url == "object"){ // must be config object
11826 params = params || cfg.params;
11827 callback = callback || cfg.callback;
11828 discardUrl = discardUrl || cfg.discardUrl;
11829 if(callback && cfg.scope){
11830 callback = callback.createDelegate(cfg.scope);
11832 if(typeof cfg.method != "undefined"){method = cfg.method;};
11833 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11834 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11835 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11836 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11838 this.showLoading();
11840 this.defaultUrl = url;
11842 if(typeof url == "function"){
11843 url = url.call(this);
11846 method = method || (params ? "POST" : "GET");
11847 if(method == "GET"){
11848 url = this.prepareUrl(url);
11851 var o = Roo.apply(cfg ||{}, {
11854 success: this.successDelegate,
11855 failure: this.failureDelegate,
11856 callback: undefined,
11857 timeout: (this.timeout*1000),
11858 argument: {"url": url, "form": null, "callback": callback, "params": params}
11860 Roo.log("updated manager called with timeout of " + o.timeout);
11861 this.transaction = Roo.Ajax.request(o);
11866 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11867 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11868 * @param {String/HTMLElement} form The form Id or form element
11869 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11870 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11871 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11873 formUpdate : function(form, url, reset, callback){
11874 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11875 if(typeof url == "function"){
11876 url = url.call(this);
11878 form = Roo.getDom(form);
11879 this.transaction = Roo.Ajax.request({
11882 success: this.successDelegate,
11883 failure: this.failureDelegate,
11884 timeout: (this.timeout*1000),
11885 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11887 this.showLoading.defer(1, this);
11892 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11893 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11895 refresh : function(callback){
11896 if(this.defaultUrl == null){
11899 this.update(this.defaultUrl, null, callback, true);
11903 * Set this element to auto refresh.
11904 * @param {Number} interval How often to update (in seconds).
11905 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11906 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11907 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11908 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11910 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11912 this.update(url || this.defaultUrl, params, callback, true);
11914 if(this.autoRefreshProcId){
11915 clearInterval(this.autoRefreshProcId);
11917 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11921 * Stop auto refresh on this element.
11923 stopAutoRefresh : function(){
11924 if(this.autoRefreshProcId){
11925 clearInterval(this.autoRefreshProcId);
11926 delete this.autoRefreshProcId;
11930 isAutoRefreshing : function(){
11931 return this.autoRefreshProcId ? true : false;
11934 * Called to update the element to "Loading" state. Override to perform custom action.
11936 showLoading : function(){
11937 if(this.showLoadIndicator){
11938 this.el.update(this.indicatorText);
11943 * Adds unique parameter to query string if disableCaching = true
11946 prepareUrl : function(url){
11947 if(this.disableCaching){
11948 var append = "_dc=" + (new Date().getTime());
11949 if(url.indexOf("?") !== -1){
11950 url += "&" + append;
11952 url += "?" + append;
11961 processSuccess : function(response){
11962 this.transaction = null;
11963 if(response.argument.form && response.argument.reset){
11964 try{ // put in try/catch since some older FF releases had problems with this
11965 response.argument.form.reset();
11968 if(this.loadScripts){
11969 this.renderer.render(this.el, response, this,
11970 this.updateComplete.createDelegate(this, [response]));
11972 this.renderer.render(this.el, response, this);
11973 this.updateComplete(response);
11977 updateComplete : function(response){
11978 this.fireEvent("update", this.el, response);
11979 if(typeof response.argument.callback == "function"){
11980 response.argument.callback(this.el, true, response);
11987 processFailure : function(response){
11988 this.transaction = null;
11989 this.fireEvent("failure", this.el, response);
11990 if(typeof response.argument.callback == "function"){
11991 response.argument.callback(this.el, false, response);
11996 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11997 * @param {Object} renderer The object implementing the render() method
11999 setRenderer : function(renderer){
12000 this.renderer = renderer;
12003 getRenderer : function(){
12004 return this.renderer;
12008 * Set the defaultUrl used for updates
12009 * @param {String/Function} defaultUrl The url or a function to call to get the url
12011 setDefaultUrl : function(defaultUrl){
12012 this.defaultUrl = defaultUrl;
12016 * Aborts the executing transaction
12018 abort : function(){
12019 if(this.transaction){
12020 Roo.Ajax.abort(this.transaction);
12025 * Returns true if an update is in progress
12026 * @return {Boolean}
12028 isUpdating : function(){
12029 if(this.transaction){
12030 return Roo.Ajax.isLoading(this.transaction);
12037 * @class Roo.UpdateManager.defaults
12038 * @static (not really - but it helps the doc tool)
12039 * The defaults collection enables customizing the default properties of UpdateManager
12041 Roo.UpdateManager.defaults = {
12043 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12049 * True to process scripts by default (Defaults to false).
12052 loadScripts : false,
12055 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12058 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12060 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12063 disableCaching : false,
12065 * Whether to show indicatorText when loading (Defaults to true).
12068 showLoadIndicator : true,
12070 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12073 indicatorText : '<div class="loading-indicator">Loading...</div>'
12077 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12079 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12080 * @param {String/HTMLElement/Roo.Element} el The element to update
12081 * @param {String} url The url
12082 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12083 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12086 * @member Roo.UpdateManager
12088 Roo.UpdateManager.updateElement = function(el, url, params, options){
12089 var um = Roo.get(el, true).getUpdateManager();
12090 Roo.apply(um, options);
12091 um.update(url, params, options ? options.callback : null);
12093 // alias for backwards compat
12094 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12096 * @class Roo.UpdateManager.BasicRenderer
12097 * Default Content renderer. Updates the elements innerHTML with the responseText.
12099 Roo.UpdateManager.BasicRenderer = function(){};
12101 Roo.UpdateManager.BasicRenderer.prototype = {
12103 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12104 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12105 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12106 * @param {Roo.Element} el The element being rendered
12107 * @param {Object} response The YUI Connect response object
12108 * @param {UpdateManager} updateManager The calling update manager
12109 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12111 render : function(el, response, updateManager, callback){
12112 el.update(response.responseText, updateManager.loadScripts, callback);
12118 * (c)) Alan Knowles
12124 * @class Roo.DomTemplate
12125 * @extends Roo.Template
12126 * An effort at a dom based template engine..
12128 * Similar to XTemplate, except it uses dom parsing to create the template..
12130 * Supported features:
12135 {a_variable} - output encoded.
12136 {a_variable.format:("Y-m-d")} - call a method on the variable
12137 {a_variable:raw} - unencoded output
12138 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12139 {a_variable:this.method_on_template(...)} - call a method on the template object.
12144 <div roo-for="a_variable or condition.."></div>
12145 <div roo-if="a_variable or condition"></div>
12146 <div roo-exec="some javascript"></div>
12147 <div roo-name="named_template"></div>
12152 Roo.DomTemplate = function()
12154 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12161 Roo.extend(Roo.DomTemplate, Roo.Template, {
12163 * id counter for sub templates.
12167 * flag to indicate if dom parser is inside a pre,
12168 * it will strip whitespace if not.
12173 * The various sub templates
12181 * basic tag replacing syntax
12184 * // you can fake an object call by doing this
12188 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12189 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12191 iterChild : function (node, method) {
12193 var oldPre = this.inPre;
12194 if (node.tagName == 'PRE') {
12197 for( var i = 0; i < node.childNodes.length; i++) {
12198 method.call(this, node.childNodes[i]);
12200 this.inPre = oldPre;
12206 * compile the template
12208 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12211 compile: function()
12215 // covert the html into DOM...
12219 doc = document.implementation.createHTMLDocument("");
12220 doc.documentElement.innerHTML = this.html ;
12221 div = doc.documentElement;
12223 // old IE... - nasty -- it causes all sorts of issues.. with
12224 // images getting pulled from server..
12225 div = document.createElement('div');
12226 div.innerHTML = this.html;
12228 //doc.documentElement.innerHTML = htmlBody
12234 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12236 var tpls = this.tpls;
12238 // create a top level template from the snippet..
12240 //Roo.log(div.innerHTML);
12247 body : div.innerHTML,
12260 Roo.each(tpls, function(tp){
12261 this.compileTpl(tp);
12262 this.tpls[tp.id] = tp;
12265 this.master = tpls[0];
12271 compileNode : function(node, istop) {
12276 // skip anything not a tag..
12277 if (node.nodeType != 1) {
12278 if (node.nodeType == 3 && !this.inPre) {
12279 // reduce white space..
12280 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12303 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12304 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12305 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12306 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12312 // just itterate children..
12313 this.iterChild(node,this.compileNode);
12316 tpl.uid = this.id++;
12317 tpl.value = node.getAttribute('roo-' + tpl.attr);
12318 node.removeAttribute('roo-'+ tpl.attr);
12319 if (tpl.attr != 'name') {
12320 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12321 node.parentNode.replaceChild(placeholder, node);
12324 var placeholder = document.createElement('span');
12325 placeholder.className = 'roo-tpl-' + tpl.value;
12326 node.parentNode.replaceChild(placeholder, node);
12329 // parent now sees '{domtplXXXX}
12330 this.iterChild(node,this.compileNode);
12332 // we should now have node body...
12333 var div = document.createElement('div');
12334 div.appendChild(node);
12336 // this has the unfortunate side effect of converting tagged attributes
12337 // eg. href="{...}" into %7C...%7D
12338 // this has been fixed by searching for those combo's although it's a bit hacky..
12341 tpl.body = div.innerHTML;
12348 switch (tpl.value) {
12349 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12350 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12351 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12356 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12360 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12364 tpl.id = tpl.value; // replace non characters???
12370 this.tpls.push(tpl);
12380 * Compile a segment of the template into a 'sub-template'
12386 compileTpl : function(tpl)
12388 var fm = Roo.util.Format;
12389 var useF = this.disableFormats !== true;
12391 var sep = Roo.isGecko ? "+\n" : ",\n";
12393 var undef = function(str) {
12394 Roo.debug && Roo.log("Property not found :" + str);
12398 //Roo.log(tpl.body);
12402 var fn = function(m, lbrace, name, format, args)
12405 //Roo.log(arguments);
12406 args = args ? args.replace(/\\'/g,"'") : args;
12407 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12408 if (typeof(format) == 'undefined') {
12409 format = 'htmlEncode';
12411 if (format == 'raw' ) {
12415 if(name.substr(0, 6) == 'domtpl'){
12416 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12419 // build an array of options to determine if value is undefined..
12421 // basically get 'xxxx.yyyy' then do
12422 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12423 // (function () { Roo.log("Property not found"); return ''; })() :
12428 Roo.each(name.split('.'), function(st) {
12429 lookfor += (lookfor.length ? '.': '') + st;
12430 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12433 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12436 if(format && useF){
12438 args = args ? ',' + args : "";
12440 if(format.substr(0, 5) != "this."){
12441 format = "fm." + format + '(';
12443 format = 'this.call("'+ format.substr(5) + '", ';
12447 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12450 if (args && args.length) {
12451 // called with xxyx.yuu:(test,test)
12453 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12455 // raw.. - :raw modifier..
12456 return "'"+ sep + udef_st + name + ")"+sep+"'";
12460 // branched to use + in gecko and [].join() in others
12462 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12463 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12466 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12467 body.push(tpl.body.replace(/(\r\n|\n)/g,
12468 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12469 body.push("'].join('');};};");
12470 body = body.join('');
12473 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12475 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12482 * same as applyTemplate, except it's done to one of the subTemplates
12483 * when using named templates, you can do:
12485 * var str = pl.applySubTemplate('your-name', values);
12488 * @param {Number} id of the template
12489 * @param {Object} values to apply to template
12490 * @param {Object} parent (normaly the instance of this object)
12492 applySubTemplate : function(id, values, parent)
12496 var t = this.tpls[id];
12500 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12501 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12505 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12512 if(t.execCall && t.execCall.call(this, values, parent)){
12516 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12522 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12523 parent = t.target ? values : parent;
12524 if(t.forCall && vs instanceof Array){
12526 for(var i = 0, len = vs.length; i < len; i++){
12528 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12530 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12532 //Roo.log(t.compiled);
12536 return buf.join('');
12539 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12544 return t.compiled.call(this, vs, parent);
12546 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12548 //Roo.log(t.compiled);
12556 applyTemplate : function(values){
12557 return this.master.compiled.call(this, values, {});
12558 //var s = this.subs;
12561 apply : function(){
12562 return this.applyTemplate.apply(this, arguments);
12567 Roo.DomTemplate.from = function(el){
12568 el = Roo.getDom(el);
12569 return new Roo.Domtemplate(el.value || el.innerHTML);
12572 * Ext JS Library 1.1.1
12573 * Copyright(c) 2006-2007, Ext JS, LLC.
12575 * Originally Released Under LGPL - original licence link has changed is not relivant.
12578 * <script type="text/javascript">
12582 * @class Roo.util.DelayedTask
12583 * Provides a convenient method of performing setTimeout where a new
12584 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12585 * You can use this class to buffer
12586 * the keypress events for a certain number of milliseconds, and perform only if they stop
12587 * for that amount of time.
12588 * @constructor The parameters to this constructor serve as defaults and are not required.
12589 * @param {Function} fn (optional) The default function to timeout
12590 * @param {Object} scope (optional) The default scope of that timeout
12591 * @param {Array} args (optional) The default Array of arguments
12593 Roo.util.DelayedTask = function(fn, scope, args){
12594 var id = null, d, t;
12596 var call = function(){
12597 var now = new Date().getTime();
12601 fn.apply(scope, args || []);
12605 * Cancels any pending timeout and queues a new one
12606 * @param {Number} delay The milliseconds to delay
12607 * @param {Function} newFn (optional) Overrides function passed to constructor
12608 * @param {Object} newScope (optional) Overrides scope passed to constructor
12609 * @param {Array} newArgs (optional) Overrides args passed to constructor
12611 this.delay = function(delay, newFn, newScope, newArgs){
12612 if(id && delay != d){
12616 t = new Date().getTime();
12618 scope = newScope || scope;
12619 args = newArgs || args;
12621 id = setInterval(call, d);
12626 * Cancel the last queued timeout
12628 this.cancel = function(){
12636 * Ext JS Library 1.1.1
12637 * Copyright(c) 2006-2007, Ext JS, LLC.
12639 * Originally Released Under LGPL - original licence link has changed is not relivant.
12642 * <script type="text/javascript">
12646 Roo.util.TaskRunner = function(interval){
12647 interval = interval || 10;
12648 var tasks = [], removeQueue = [];
12650 var running = false;
12652 var stopThread = function(){
12658 var startThread = function(){
12661 id = setInterval(runTasks, interval);
12665 var removeTask = function(task){
12666 removeQueue.push(task);
12672 var runTasks = function(){
12673 if(removeQueue.length > 0){
12674 for(var i = 0, len = removeQueue.length; i < len; i++){
12675 tasks.remove(removeQueue[i]);
12678 if(tasks.length < 1){
12683 var now = new Date().getTime();
12684 for(var i = 0, len = tasks.length; i < len; ++i){
12686 var itime = now - t.taskRunTime;
12687 if(t.interval <= itime){
12688 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12689 t.taskRunTime = now;
12690 if(rt === false || t.taskRunCount === t.repeat){
12695 if(t.duration && t.duration <= (now - t.taskStartTime)){
12702 * Queues a new task.
12703 * @param {Object} task
12705 this.start = function(task){
12707 task.taskStartTime = new Date().getTime();
12708 task.taskRunTime = 0;
12709 task.taskRunCount = 0;
12714 this.stop = function(task){
12719 this.stopAll = function(){
12721 for(var i = 0, len = tasks.length; i < len; i++){
12722 if(tasks[i].onStop){
12731 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12733 * Ext JS Library 1.1.1
12734 * Copyright(c) 2006-2007, Ext JS, LLC.
12736 * Originally Released Under LGPL - original licence link has changed is not relivant.
12739 * <script type="text/javascript">
12744 * @class Roo.util.MixedCollection
12745 * @extends Roo.util.Observable
12746 * A Collection class that maintains both numeric indexes and keys and exposes events.
12748 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12749 * collection (defaults to false)
12750 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12751 * and return the key value for that item. This is used when available to look up the key on items that
12752 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12753 * equivalent to providing an implementation for the {@link #getKey} method.
12755 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12763 * Fires when the collection is cleared.
12768 * Fires when an item is added to the collection.
12769 * @param {Number} index The index at which the item was added.
12770 * @param {Object} o The item added.
12771 * @param {String} key The key associated with the added item.
12776 * Fires when an item is replaced in the collection.
12777 * @param {String} key he key associated with the new added.
12778 * @param {Object} old The item being replaced.
12779 * @param {Object} new The new item.
12784 * Fires when an item is removed from the collection.
12785 * @param {Object} o The item being removed.
12786 * @param {String} key (optional) The key associated with the removed item.
12791 this.allowFunctions = allowFunctions === true;
12793 this.getKey = keyFn;
12795 Roo.util.MixedCollection.superclass.constructor.call(this);
12798 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12799 allowFunctions : false,
12802 * Adds an item to the collection.
12803 * @param {String} key The key to associate with the item
12804 * @param {Object} o The item to add.
12805 * @return {Object} The item added.
12807 add : function(key, o){
12808 if(arguments.length == 1){
12810 key = this.getKey(o);
12812 if(typeof key == "undefined" || key === null){
12814 this.items.push(o);
12815 this.keys.push(null);
12817 var old = this.map[key];
12819 return this.replace(key, o);
12822 this.items.push(o);
12824 this.keys.push(key);
12826 this.fireEvent("add", this.length-1, o, key);
12831 * MixedCollection has a generic way to fetch keys if you implement getKey.
12834 var mc = new Roo.util.MixedCollection();
12835 mc.add(someEl.dom.id, someEl);
12836 mc.add(otherEl.dom.id, otherEl);
12840 var mc = new Roo.util.MixedCollection();
12841 mc.getKey = function(el){
12847 // or via the constructor
12848 var mc = new Roo.util.MixedCollection(false, function(el){
12854 * @param o {Object} The item for which to find the key.
12855 * @return {Object} The key for the passed item.
12857 getKey : function(o){
12862 * Replaces an item in the collection.
12863 * @param {String} key The key associated with the item to replace, or the item to replace.
12864 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12865 * @return {Object} The new item.
12867 replace : function(key, o){
12868 if(arguments.length == 1){
12870 key = this.getKey(o);
12872 var old = this.item(key);
12873 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12874 return this.add(key, o);
12876 var index = this.indexOfKey(key);
12877 this.items[index] = o;
12879 this.fireEvent("replace", key, old, o);
12884 * Adds all elements of an Array or an Object to the collection.
12885 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12886 * an Array of values, each of which are added to the collection.
12888 addAll : function(objs){
12889 if(arguments.length > 1 || objs instanceof Array){
12890 var args = arguments.length > 1 ? arguments : objs;
12891 for(var i = 0, len = args.length; i < len; i++){
12895 for(var key in objs){
12896 if(this.allowFunctions || typeof objs[key] != "function"){
12897 this.add(key, objs[key]);
12904 * Executes the specified function once for every item in the collection, passing each
12905 * item as the first and only parameter. returning false from the function will stop the iteration.
12906 * @param {Function} fn The function to execute for each item.
12907 * @param {Object} scope (optional) The scope in which to execute the function.
12909 each : function(fn, scope){
12910 var items = [].concat(this.items); // each safe for removal
12911 for(var i = 0, len = items.length; i < len; i++){
12912 if(fn.call(scope || items[i], items[i], i, len) === false){
12919 * Executes the specified function once for every key in the collection, passing each
12920 * key, and its associated item as the first two parameters.
12921 * @param {Function} fn The function to execute for each item.
12922 * @param {Object} scope (optional) The scope in which to execute the function.
12924 eachKey : function(fn, scope){
12925 for(var i = 0, len = this.keys.length; i < len; i++){
12926 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12931 * Returns the first item in the collection which elicits a true return value from the
12932 * passed selection function.
12933 * @param {Function} fn The selection function to execute for each item.
12934 * @param {Object} scope (optional) The scope in which to execute the function.
12935 * @return {Object} The first item in the collection which returned true from the selection function.
12937 find : function(fn, scope){
12938 for(var i = 0, len = this.items.length; i < len; i++){
12939 if(fn.call(scope || window, this.items[i], this.keys[i])){
12940 return this.items[i];
12947 * Inserts an item at the specified index in the collection.
12948 * @param {Number} index The index to insert the item at.
12949 * @param {String} key The key to associate with the new item, or the item itself.
12950 * @param {Object} o (optional) If the second parameter was a key, the new item.
12951 * @return {Object} The item inserted.
12953 insert : function(index, key, o){
12954 if(arguments.length == 2){
12956 key = this.getKey(o);
12958 if(index >= this.length){
12959 return this.add(key, o);
12962 this.items.splice(index, 0, o);
12963 if(typeof key != "undefined" && key != null){
12966 this.keys.splice(index, 0, key);
12967 this.fireEvent("add", index, o, key);
12972 * Removed an item from the collection.
12973 * @param {Object} o The item to remove.
12974 * @return {Object} The item removed.
12976 remove : function(o){
12977 return this.removeAt(this.indexOf(o));
12981 * Remove an item from a specified index in the collection.
12982 * @param {Number} index The index within the collection of the item to remove.
12984 removeAt : function(index){
12985 if(index < this.length && index >= 0){
12987 var o = this.items[index];
12988 this.items.splice(index, 1);
12989 var key = this.keys[index];
12990 if(typeof key != "undefined"){
12991 delete this.map[key];
12993 this.keys.splice(index, 1);
12994 this.fireEvent("remove", o, key);
12999 * Removed an item associated with the passed key fom the collection.
13000 * @param {String} key The key of the item to remove.
13002 removeKey : function(key){
13003 return this.removeAt(this.indexOfKey(key));
13007 * Returns the number of items in the collection.
13008 * @return {Number} the number of items in the collection.
13010 getCount : function(){
13011 return this.length;
13015 * Returns index within the collection of the passed Object.
13016 * @param {Object} o The item to find the index of.
13017 * @return {Number} index of the item.
13019 indexOf : function(o){
13020 if(!this.items.indexOf){
13021 for(var i = 0, len = this.items.length; i < len; i++){
13022 if(this.items[i] == o) return i;
13026 return this.items.indexOf(o);
13031 * Returns index within the collection of the passed key.
13032 * @param {String} key The key to find the index of.
13033 * @return {Number} index of the key.
13035 indexOfKey : function(key){
13036 if(!this.keys.indexOf){
13037 for(var i = 0, len = this.keys.length; i < len; i++){
13038 if(this.keys[i] == key) return i;
13042 return this.keys.indexOf(key);
13047 * Returns the item associated with the passed key OR index. Key has priority over index.
13048 * @param {String/Number} key The key or index of the item.
13049 * @return {Object} The item associated with the passed key.
13051 item : function(key){
13052 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13053 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13057 * Returns the item at the specified index.
13058 * @param {Number} index The index of the item.
13061 itemAt : function(index){
13062 return this.items[index];
13066 * Returns the item associated with the passed key.
13067 * @param {String/Number} key The key of the item.
13068 * @return {Object} The item associated with the passed key.
13070 key : function(key){
13071 return this.map[key];
13075 * Returns true if the collection contains the passed Object as an item.
13076 * @param {Object} o The Object to look for in the collection.
13077 * @return {Boolean} True if the collection contains the Object as an item.
13079 contains : function(o){
13080 return this.indexOf(o) != -1;
13084 * Returns true if the collection contains the passed Object as a key.
13085 * @param {String} key The key to look for in the collection.
13086 * @return {Boolean} True if the collection contains the Object as a key.
13088 containsKey : function(key){
13089 return typeof this.map[key] != "undefined";
13093 * Removes all items from the collection.
13095 clear : function(){
13100 this.fireEvent("clear");
13104 * Returns the first item in the collection.
13105 * @return {Object} the first item in the collection..
13107 first : function(){
13108 return this.items[0];
13112 * Returns the last item in the collection.
13113 * @return {Object} the last item in the collection..
13116 return this.items[this.length-1];
13119 _sort : function(property, dir, fn){
13120 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13121 fn = fn || function(a, b){
13124 var c = [], k = this.keys, items = this.items;
13125 for(var i = 0, len = items.length; i < len; i++){
13126 c[c.length] = {key: k[i], value: items[i], index: i};
13128 c.sort(function(a, b){
13129 var v = fn(a[property], b[property]) * dsc;
13131 v = (a.index < b.index ? -1 : 1);
13135 for(var i = 0, len = c.length; i < len; i++){
13136 items[i] = c[i].value;
13139 this.fireEvent("sort", this);
13143 * Sorts this collection with the passed comparison function
13144 * @param {String} direction (optional) "ASC" or "DESC"
13145 * @param {Function} fn (optional) comparison function
13147 sort : function(dir, fn){
13148 this._sort("value", dir, fn);
13152 * Sorts this collection by keys
13153 * @param {String} direction (optional) "ASC" or "DESC"
13154 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13156 keySort : function(dir, fn){
13157 this._sort("key", dir, fn || function(a, b){
13158 return String(a).toUpperCase()-String(b).toUpperCase();
13163 * Returns a range of items in this collection
13164 * @param {Number} startIndex (optional) defaults to 0
13165 * @param {Number} endIndex (optional) default to the last item
13166 * @return {Array} An array of items
13168 getRange : function(start, end){
13169 var items = this.items;
13170 if(items.length < 1){
13173 start = start || 0;
13174 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13177 for(var i = start; i <= end; i++) {
13178 r[r.length] = items[i];
13181 for(var i = start; i >= end; i--) {
13182 r[r.length] = items[i];
13189 * Filter the <i>objects</i> in this collection by a specific property.
13190 * Returns a new collection that has been filtered.
13191 * @param {String} property A property on your objects
13192 * @param {String/RegExp} value Either string that the property values
13193 * should start with or a RegExp to test against the property
13194 * @return {MixedCollection} The new filtered collection
13196 filter : function(property, value){
13197 if(!value.exec){ // not a regex
13198 value = String(value);
13199 if(value.length == 0){
13200 return this.clone();
13202 value = new RegExp("^" + Roo.escapeRe(value), "i");
13204 return this.filterBy(function(o){
13205 return o && value.test(o[property]);
13210 * Filter by a function. * Returns a new collection that has been filtered.
13211 * The passed function will be called with each
13212 * object in the collection. If the function returns true, the value is included
13213 * otherwise it is filtered.
13214 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13215 * @param {Object} scope (optional) The scope of the function (defaults to this)
13216 * @return {MixedCollection} The new filtered collection
13218 filterBy : function(fn, scope){
13219 var r = new Roo.util.MixedCollection();
13220 r.getKey = this.getKey;
13221 var k = this.keys, it = this.items;
13222 for(var i = 0, len = it.length; i < len; i++){
13223 if(fn.call(scope||this, it[i], k[i])){
13224 r.add(k[i], it[i]);
13231 * Creates a duplicate of this collection
13232 * @return {MixedCollection}
13234 clone : function(){
13235 var r = new Roo.util.MixedCollection();
13236 var k = this.keys, it = this.items;
13237 for(var i = 0, len = it.length; i < len; i++){
13238 r.add(k[i], it[i]);
13240 r.getKey = this.getKey;
13245 * Returns the item associated with the passed key or index.
13247 * @param {String/Number} key The key or index of the item.
13248 * @return {Object} The item associated with the passed key.
13250 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13252 * Ext JS Library 1.1.1
13253 * Copyright(c) 2006-2007, Ext JS, LLC.
13255 * Originally Released Under LGPL - original licence link has changed is not relivant.
13258 * <script type="text/javascript">
13261 * @class Roo.util.JSON
13262 * Modified version of Douglas Crockford"s json.js that doesn"t
13263 * mess with the Object prototype
13264 * http://www.json.org/js.html
13267 Roo.util.JSON = new (function(){
13268 var useHasOwn = {}.hasOwnProperty ? true : false;
13270 // crashes Safari in some instances
13271 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13273 var pad = function(n) {
13274 return n < 10 ? "0" + n : n;
13287 var encodeString = function(s){
13288 if (/["\\\x00-\x1f]/.test(s)) {
13289 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13294 c = b.charCodeAt();
13296 Math.floor(c / 16).toString(16) +
13297 (c % 16).toString(16);
13300 return '"' + s + '"';
13303 var encodeArray = function(o){
13304 var a = ["["], b, i, l = o.length, v;
13305 for (i = 0; i < l; i += 1) {
13307 switch (typeof v) {
13316 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13324 var encodeDate = function(o){
13325 return '"' + o.getFullYear() + "-" +
13326 pad(o.getMonth() + 1) + "-" +
13327 pad(o.getDate()) + "T" +
13328 pad(o.getHours()) + ":" +
13329 pad(o.getMinutes()) + ":" +
13330 pad(o.getSeconds()) + '"';
13334 * Encodes an Object, Array or other value
13335 * @param {Mixed} o The variable to encode
13336 * @return {String} The JSON string
13338 this.encode = function(o)
13340 // should this be extended to fully wrap stringify..
13342 if(typeof o == "undefined" || o === null){
13344 }else if(o instanceof Array){
13345 return encodeArray(o);
13346 }else if(o instanceof Date){
13347 return encodeDate(o);
13348 }else if(typeof o == "string"){
13349 return encodeString(o);
13350 }else if(typeof o == "number"){
13351 return isFinite(o) ? String(o) : "null";
13352 }else if(typeof o == "boolean"){
13355 var a = ["{"], b, i, v;
13357 if(!useHasOwn || o.hasOwnProperty(i)) {
13359 switch (typeof v) {
13368 a.push(this.encode(i), ":",
13369 v === null ? "null" : this.encode(v));
13380 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13381 * @param {String} json The JSON string
13382 * @return {Object} The resulting object
13384 this.decode = function(json){
13386 return /** eval:var:json */ eval("(" + json + ')');
13390 * Shorthand for {@link Roo.util.JSON#encode}
13391 * @member Roo encode
13393 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13395 * Shorthand for {@link Roo.util.JSON#decode}
13396 * @member Roo decode
13398 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13401 * Ext JS Library 1.1.1
13402 * Copyright(c) 2006-2007, Ext JS, LLC.
13404 * Originally Released Under LGPL - original licence link has changed is not relivant.
13407 * <script type="text/javascript">
13411 * @class Roo.util.Format
13412 * Reusable data formatting functions
13415 Roo.util.Format = function(){
13416 var trimRe = /^\s+|\s+$/g;
13419 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13420 * @param {String} value The string to truncate
13421 * @param {Number} length The maximum length to allow before truncating
13422 * @return {String} The converted text
13424 ellipsis : function(value, len){
13425 if(value && value.length > len){
13426 return value.substr(0, len-3)+"...";
13432 * Checks a reference and converts it to empty string if it is undefined
13433 * @param {Mixed} value Reference to check
13434 * @return {Mixed} Empty string if converted, otherwise the original value
13436 undef : function(value){
13437 return typeof value != "undefined" ? value : "";
13441 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13442 * @param {String} value The string to encode
13443 * @return {String} The encoded text
13445 htmlEncode : function(value){
13446 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13450 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13451 * @param {String} value The string to decode
13452 * @return {String} The decoded text
13454 htmlDecode : function(value){
13455 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13459 * Trims any whitespace from either side of a string
13460 * @param {String} value The text to trim
13461 * @return {String} The trimmed text
13463 trim : function(value){
13464 return String(value).replace(trimRe, "");
13468 * Returns a substring from within an original string
13469 * @param {String} value The original text
13470 * @param {Number} start The start index of the substring
13471 * @param {Number} length The length of the substring
13472 * @return {String} The substring
13474 substr : function(value, start, length){
13475 return String(value).substr(start, length);
13479 * Converts a string to all lower case letters
13480 * @param {String} value The text to convert
13481 * @return {String} The converted text
13483 lowercase : function(value){
13484 return String(value).toLowerCase();
13488 * Converts a string to all upper case letters
13489 * @param {String} value The text to convert
13490 * @return {String} The converted text
13492 uppercase : function(value){
13493 return String(value).toUpperCase();
13497 * Converts the first character only of a string to upper case
13498 * @param {String} value The text to convert
13499 * @return {String} The converted text
13501 capitalize : function(value){
13502 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13506 call : function(value, fn){
13507 if(arguments.length > 2){
13508 var args = Array.prototype.slice.call(arguments, 2);
13509 args.unshift(value);
13511 return /** eval:var:value */ eval(fn).apply(window, args);
13513 /** eval:var:value */
13514 return /** eval:var:value */ eval(fn).call(window, value);
13520 * safer version of Math.toFixed..??/
13521 * @param {Number/String} value The numeric value to format
13522 * @param {Number/String} value Decimal places
13523 * @return {String} The formatted currency string
13525 toFixed : function(v, n)
13527 // why not use to fixed - precision is buggered???
13529 return Math.round(v-0);
13531 var fact = Math.pow(10,n+1);
13532 v = (Math.round((v-0)*fact))/fact;
13533 var z = (''+fact).substring(2);
13534 if (v == Math.floor(v)) {
13535 return Math.floor(v) + '.' + z;
13538 // now just padd decimals..
13539 var ps = String(v).split('.');
13540 var fd = (ps[1] + z);
13541 var r = fd.substring(0,n);
13542 var rm = fd.substring(n);
13544 return ps[0] + '.' + r;
13546 r*=1; // turn it into a number;
13548 if (String(r).length != n) {
13551 r = String(r).substring(1); // chop the end off.
13554 return ps[0] + '.' + r;
13559 * Format a number as US currency
13560 * @param {Number/String} value The numeric value to format
13561 * @return {String} The formatted currency string
13563 usMoney : function(v){
13564 return '$' + Roo.util.Format.number(v);
13569 * eventually this should probably emulate php's number_format
13570 * @param {Number/String} value The numeric value to format
13571 * @param {Number} decimals number of decimal places
13572 * @return {String} The formatted currency string
13574 number : function(v,decimals)
13576 // multiply and round.
13577 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13578 var mul = Math.pow(10, decimals);
13579 var zero = String(mul).substring(1);
13580 v = (Math.round((v-0)*mul))/mul;
13582 // if it's '0' number.. then
13584 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13586 var ps = v.split('.');
13590 var r = /(\d+)(\d{3})/;
13592 while (r.test(whole)) {
13593 whole = whole.replace(r, '$1' + ',' + '$2');
13599 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13600 // does not have decimals
13601 (decimals ? ('.' + zero) : '');
13604 return whole + sub ;
13608 * Parse a value into a formatted date using the specified format pattern.
13609 * @param {Mixed} value The value to format
13610 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13611 * @return {String} The formatted date string
13613 date : function(v, format){
13617 if(!(v instanceof Date)){
13618 v = new Date(Date.parse(v));
13620 return v.dateFormat(format || Roo.util.Format.defaults.date);
13624 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13625 * @param {String} format Any valid date format string
13626 * @return {Function} The date formatting function
13628 dateRenderer : function(format){
13629 return function(v){
13630 return Roo.util.Format.date(v, format);
13635 stripTagsRE : /<\/?[^>]+>/gi,
13638 * Strips all HTML tags
13639 * @param {Mixed} value The text from which to strip tags
13640 * @return {String} The stripped text
13642 stripTags : function(v){
13643 return !v ? v : String(v).replace(this.stripTagsRE, "");
13647 Roo.util.Format.defaults = {
13651 * Ext JS Library 1.1.1
13652 * Copyright(c) 2006-2007, Ext JS, LLC.
13654 * Originally Released Under LGPL - original licence link has changed is not relivant.
13657 * <script type="text/javascript">
13664 * @class Roo.MasterTemplate
13665 * @extends Roo.Template
13666 * Provides a template that can have child templates. The syntax is:
13668 var t = new Roo.MasterTemplate(
13669 '<select name="{name}">',
13670 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13673 t.add('options', {value: 'foo', text: 'bar'});
13674 // or you can add multiple child elements in one shot
13675 t.addAll('options', [
13676 {value: 'foo', text: 'bar'},
13677 {value: 'foo2', text: 'bar2'},
13678 {value: 'foo3', text: 'bar3'}
13680 // then append, applying the master template values
13681 t.append('my-form', {name: 'my-select'});
13683 * A name attribute for the child template is not required if you have only one child
13684 * template or you want to refer to them by index.
13686 Roo.MasterTemplate = function(){
13687 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13688 this.originalHtml = this.html;
13690 var m, re = this.subTemplateRe;
13693 while(m = re.exec(this.html)){
13694 var name = m[1], content = m[2];
13699 tpl : new Roo.Template(content)
13702 st[name] = st[subIndex];
13704 st[subIndex].tpl.compile();
13705 st[subIndex].tpl.call = this.call.createDelegate(this);
13708 this.subCount = subIndex;
13711 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13713 * The regular expression used to match sub templates
13717 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13720 * Applies the passed values to a child template.
13721 * @param {String/Number} name (optional) The name or index of the child template
13722 * @param {Array/Object} values The values to be applied to the template
13723 * @return {MasterTemplate} this
13725 add : function(name, values){
13726 if(arguments.length == 1){
13727 values = arguments[0];
13730 var s = this.subs[name];
13731 s.buffer[s.buffer.length] = s.tpl.apply(values);
13736 * Applies all the passed values to a child template.
13737 * @param {String/Number} name (optional) The name or index of the child template
13738 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13739 * @param {Boolean} reset (optional) True to reset the template first
13740 * @return {MasterTemplate} this
13742 fill : function(name, values, reset){
13744 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13752 for(var i = 0, len = values.length; i < len; i++){
13753 this.add(name, values[i]);
13759 * Resets the template for reuse
13760 * @return {MasterTemplate} this
13762 reset : function(){
13764 for(var i = 0; i < this.subCount; i++){
13770 applyTemplate : function(values){
13772 var replaceIndex = -1;
13773 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13774 return s[++replaceIndex].buffer.join("");
13776 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13779 apply : function(){
13780 return this.applyTemplate.apply(this, arguments);
13783 compile : function(){return this;}
13787 * Alias for fill().
13790 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13792 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13793 * var tpl = Roo.MasterTemplate.from('element-id');
13794 * @param {String/HTMLElement} el
13795 * @param {Object} config
13798 Roo.MasterTemplate.from = function(el, config){
13799 el = Roo.getDom(el);
13800 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13803 * Ext JS Library 1.1.1
13804 * Copyright(c) 2006-2007, Ext JS, LLC.
13806 * Originally Released Under LGPL - original licence link has changed is not relivant.
13809 * <script type="text/javascript">
13814 * @class Roo.util.CSS
13815 * Utility class for manipulating CSS rules
13818 Roo.util.CSS = function(){
13820 var doc = document;
13822 var camelRe = /(-[a-z])/gi;
13823 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13827 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13828 * tag and appended to the HEAD of the document.
13829 * @param {String|Object} cssText The text containing the css rules
13830 * @param {String} id An id to add to the stylesheet for later removal
13831 * @return {StyleSheet}
13833 createStyleSheet : function(cssText, id){
13835 var head = doc.getElementsByTagName("head")[0];
13836 var nrules = doc.createElement("style");
13837 nrules.setAttribute("type", "text/css");
13839 nrules.setAttribute("id", id);
13841 if (typeof(cssText) != 'string') {
13842 // support object maps..
13843 // not sure if this a good idea..
13844 // perhaps it should be merged with the general css handling
13845 // and handle js style props.
13846 var cssTextNew = [];
13847 for(var n in cssText) {
13849 for(var k in cssText[n]) {
13850 citems.push( k + ' : ' +cssText[n][k] + ';' );
13852 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13855 cssText = cssTextNew.join("\n");
13861 head.appendChild(nrules);
13862 ss = nrules.styleSheet;
13863 ss.cssText = cssText;
13866 nrules.appendChild(doc.createTextNode(cssText));
13868 nrules.cssText = cssText;
13870 head.appendChild(nrules);
13871 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13873 this.cacheStyleSheet(ss);
13878 * Removes a style or link tag by id
13879 * @param {String} id The id of the tag
13881 removeStyleSheet : function(id){
13882 var existing = doc.getElementById(id);
13884 existing.parentNode.removeChild(existing);
13889 * Dynamically swaps an existing stylesheet reference for a new one
13890 * @param {String} id The id of an existing link tag to remove
13891 * @param {String} url The href of the new stylesheet to include
13893 swapStyleSheet : function(id, url){
13894 this.removeStyleSheet(id);
13895 var ss = doc.createElement("link");
13896 ss.setAttribute("rel", "stylesheet");
13897 ss.setAttribute("type", "text/css");
13898 ss.setAttribute("id", id);
13899 ss.setAttribute("href", url);
13900 doc.getElementsByTagName("head")[0].appendChild(ss);
13904 * Refresh the rule cache if you have dynamically added stylesheets
13905 * @return {Object} An object (hash) of rules indexed by selector
13907 refreshCache : function(){
13908 return this.getRules(true);
13912 cacheStyleSheet : function(stylesheet){
13916 try{// try catch for cross domain access issue
13917 var ssRules = stylesheet.cssRules || stylesheet.rules;
13918 for(var j = ssRules.length-1; j >= 0; --j){
13919 rules[ssRules[j].selectorText] = ssRules[j];
13925 * Gets all css rules for the document
13926 * @param {Boolean} refreshCache true to refresh the internal cache
13927 * @return {Object} An object (hash) of rules indexed by selector
13929 getRules : function(refreshCache){
13930 if(rules == null || refreshCache){
13932 var ds = doc.styleSheets;
13933 for(var i =0, len = ds.length; i < len; i++){
13935 this.cacheStyleSheet(ds[i]);
13943 * Gets an an individual CSS rule by selector(s)
13944 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13945 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13946 * @return {CSSRule} The CSS rule or null if one is not found
13948 getRule : function(selector, refreshCache){
13949 var rs = this.getRules(refreshCache);
13950 if(!(selector instanceof Array)){
13951 return rs[selector];
13953 for(var i = 0; i < selector.length; i++){
13954 if(rs[selector[i]]){
13955 return rs[selector[i]];
13963 * Updates a rule property
13964 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13965 * @param {String} property The css property
13966 * @param {String} value The new value for the property
13967 * @return {Boolean} true If a rule was found and updated
13969 updateRule : function(selector, property, value){
13970 if(!(selector instanceof Array)){
13971 var rule = this.getRule(selector);
13973 rule.style[property.replace(camelRe, camelFn)] = value;
13977 for(var i = 0; i < selector.length; i++){
13978 if(this.updateRule(selector[i], property, value)){
13988 * Ext JS Library 1.1.1
13989 * Copyright(c) 2006-2007, Ext JS, LLC.
13991 * Originally Released Under LGPL - original licence link has changed is not relivant.
13994 * <script type="text/javascript">
14000 * @class Roo.util.ClickRepeater
14001 * @extends Roo.util.Observable
14003 * A wrapper class which can be applied to any element. Fires a "click" event while the
14004 * mouse is pressed. The interval between firings may be specified in the config but
14005 * defaults to 10 milliseconds.
14007 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14009 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14010 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14011 * Similar to an autorepeat key delay.
14012 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14013 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14014 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14015 * "interval" and "delay" are ignored. "immediate" is honored.
14016 * @cfg {Boolean} preventDefault True to prevent the default click event
14017 * @cfg {Boolean} stopDefault True to stop the default click event
14020 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14021 * 2007-02-02 jvs Renamed to ClickRepeater
14022 * 2007-02-03 jvs Modifications for FF Mac and Safari
14025 * @param {String/HTMLElement/Element} el The element to listen on
14026 * @param {Object} config
14028 Roo.util.ClickRepeater = function(el, config)
14030 this.el = Roo.get(el);
14031 this.el.unselectable();
14033 Roo.apply(this, config);
14038 * Fires when the mouse button is depressed.
14039 * @param {Roo.util.ClickRepeater} this
14041 "mousedown" : true,
14044 * Fires on a specified interval during the time the element is pressed.
14045 * @param {Roo.util.ClickRepeater} this
14050 * Fires when the mouse key is released.
14051 * @param {Roo.util.ClickRepeater} this
14056 this.el.on("mousedown", this.handleMouseDown, this);
14057 if(this.preventDefault || this.stopDefault){
14058 this.el.on("click", function(e){
14059 if(this.preventDefault){
14060 e.preventDefault();
14062 if(this.stopDefault){
14068 // allow inline handler
14070 this.on("click", this.handler, this.scope || this);
14073 Roo.util.ClickRepeater.superclass.constructor.call(this);
14076 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14079 preventDefault : true,
14080 stopDefault : false,
14084 handleMouseDown : function(){
14085 clearTimeout(this.timer);
14087 if(this.pressClass){
14088 this.el.addClass(this.pressClass);
14090 this.mousedownTime = new Date();
14092 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14093 this.el.on("mouseout", this.handleMouseOut, this);
14095 this.fireEvent("mousedown", this);
14096 this.fireEvent("click", this);
14098 this.timer = this.click.defer(this.delay || this.interval, this);
14102 click : function(){
14103 this.fireEvent("click", this);
14104 this.timer = this.click.defer(this.getInterval(), this);
14108 getInterval: function(){
14109 if(!this.accelerate){
14110 return this.interval;
14112 var pressTime = this.mousedownTime.getElapsed();
14113 if(pressTime < 500){
14115 }else if(pressTime < 1700){
14117 }else if(pressTime < 2600){
14119 }else if(pressTime < 3500){
14121 }else if(pressTime < 4400){
14123 }else if(pressTime < 5300){
14125 }else if(pressTime < 6200){
14133 handleMouseOut : function(){
14134 clearTimeout(this.timer);
14135 if(this.pressClass){
14136 this.el.removeClass(this.pressClass);
14138 this.el.on("mouseover", this.handleMouseReturn, this);
14142 handleMouseReturn : function(){
14143 this.el.un("mouseover", this.handleMouseReturn);
14144 if(this.pressClass){
14145 this.el.addClass(this.pressClass);
14151 handleMouseUp : function(){
14152 clearTimeout(this.timer);
14153 this.el.un("mouseover", this.handleMouseReturn);
14154 this.el.un("mouseout", this.handleMouseOut);
14155 Roo.get(document).un("mouseup", this.handleMouseUp);
14156 this.el.removeClass(this.pressClass);
14157 this.fireEvent("mouseup", this);
14161 * Ext JS Library 1.1.1
14162 * Copyright(c) 2006-2007, Ext JS, LLC.
14164 * Originally Released Under LGPL - original licence link has changed is not relivant.
14167 * <script type="text/javascript">
14172 * @class Roo.KeyNav
14173 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14174 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14175 * way to implement custom navigation schemes for any UI component.</p>
14176 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14177 * pageUp, pageDown, del, home, end. Usage:</p>
14179 var nav = new Roo.KeyNav("my-element", {
14180 "left" : function(e){
14181 this.moveLeft(e.ctrlKey);
14183 "right" : function(e){
14184 this.moveRight(e.ctrlKey);
14186 "enter" : function(e){
14193 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14194 * @param {Object} config The config
14196 Roo.KeyNav = function(el, config){
14197 this.el = Roo.get(el);
14198 Roo.apply(this, config);
14199 if(!this.disabled){
14200 this.disabled = true;
14205 Roo.KeyNav.prototype = {
14207 * @cfg {Boolean} disabled
14208 * True to disable this KeyNav instance (defaults to false)
14212 * @cfg {String} defaultEventAction
14213 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14214 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14215 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14217 defaultEventAction: "stopEvent",
14219 * @cfg {Boolean} forceKeyDown
14220 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14221 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14222 * handle keydown instead of keypress.
14224 forceKeyDown : false,
14227 prepareEvent : function(e){
14228 var k = e.getKey();
14229 var h = this.keyToHandler[k];
14230 //if(h && this[h]){
14231 // e.stopPropagation();
14233 if(Roo.isSafari && h && k >= 37 && k <= 40){
14239 relay : function(e){
14240 var k = e.getKey();
14241 var h = this.keyToHandler[k];
14243 if(this.doRelay(e, this[h], h) !== true){
14244 e[this.defaultEventAction]();
14250 doRelay : function(e, h, hname){
14251 return h.call(this.scope || this, e);
14254 // possible handlers
14268 // quick lookup hash
14285 * Enable this KeyNav
14287 enable: function(){
14289 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14290 // the EventObject will normalize Safari automatically
14291 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14292 this.el.on("keydown", this.relay, this);
14294 this.el.on("keydown", this.prepareEvent, this);
14295 this.el.on("keypress", this.relay, this);
14297 this.disabled = false;
14302 * Disable this KeyNav
14304 disable: function(){
14305 if(!this.disabled){
14306 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14307 this.el.un("keydown", this.relay);
14309 this.el.un("keydown", this.prepareEvent);
14310 this.el.un("keypress", this.relay);
14312 this.disabled = true;
14317 * Ext JS Library 1.1.1
14318 * Copyright(c) 2006-2007, Ext JS, LLC.
14320 * Originally Released Under LGPL - original licence link has changed is not relivant.
14323 * <script type="text/javascript">
14328 * @class Roo.KeyMap
14329 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14330 * The constructor accepts the same config object as defined by {@link #addBinding}.
14331 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14332 * combination it will call the function with this signature (if the match is a multi-key
14333 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14334 * A KeyMap can also handle a string representation of keys.<br />
14337 // map one key by key code
14338 var map = new Roo.KeyMap("my-element", {
14339 key: 13, // or Roo.EventObject.ENTER
14344 // map multiple keys to one action by string
14345 var map = new Roo.KeyMap("my-element", {
14351 // map multiple keys to multiple actions by strings and array of codes
14352 var map = new Roo.KeyMap("my-element", [
14355 fn: function(){ alert("Return was pressed"); }
14358 fn: function(){ alert('a, b or c was pressed'); }
14363 fn: function(){ alert('Control + shift + tab was pressed.'); }
14367 * <b>Note: A KeyMap starts enabled</b>
14369 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14370 * @param {Object} config The config (see {@link #addBinding})
14371 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14373 Roo.KeyMap = function(el, config, eventName){
14374 this.el = Roo.get(el);
14375 this.eventName = eventName || "keydown";
14376 this.bindings = [];
14378 this.addBinding(config);
14383 Roo.KeyMap.prototype = {
14385 * True to stop the event from bubbling and prevent the default browser action if the
14386 * key was handled by the KeyMap (defaults to false)
14392 * Add a new binding to this KeyMap. The following config object properties are supported:
14394 Property Type Description
14395 ---------- --------------- ----------------------------------------------------------------------
14396 key String/Array A single keycode or an array of keycodes to handle
14397 shift Boolean True to handle key only when shift is pressed (defaults to false)
14398 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14399 alt Boolean True to handle key only when alt is pressed (defaults to false)
14400 fn Function The function to call when KeyMap finds the expected key combination
14401 scope Object The scope of the callback function
14407 var map = new Roo.KeyMap(document, {
14408 key: Roo.EventObject.ENTER,
14413 //Add a new binding to the existing KeyMap later
14421 * @param {Object/Array} config A single KeyMap config or an array of configs
14423 addBinding : function(config){
14424 if(config instanceof Array){
14425 for(var i = 0, len = config.length; i < len; i++){
14426 this.addBinding(config[i]);
14430 var keyCode = config.key,
14431 shift = config.shift,
14432 ctrl = config.ctrl,
14435 scope = config.scope;
14436 if(typeof keyCode == "string"){
14438 var keyString = keyCode.toUpperCase();
14439 for(var j = 0, len = keyString.length; j < len; j++){
14440 ks.push(keyString.charCodeAt(j));
14444 var keyArray = keyCode instanceof Array;
14445 var handler = function(e){
14446 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14447 var k = e.getKey();
14449 for(var i = 0, len = keyCode.length; i < len; i++){
14450 if(keyCode[i] == k){
14451 if(this.stopEvent){
14454 fn.call(scope || window, k, e);
14460 if(this.stopEvent){
14463 fn.call(scope || window, k, e);
14468 this.bindings.push(handler);
14472 * Shorthand for adding a single key listener
14473 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14474 * following options:
14475 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14476 * @param {Function} fn The function to call
14477 * @param {Object} scope (optional) The scope of the function
14479 on : function(key, fn, scope){
14480 var keyCode, shift, ctrl, alt;
14481 if(typeof key == "object" && !(key instanceof Array)){
14500 handleKeyDown : function(e){
14501 if(this.enabled){ //just in case
14502 var b = this.bindings;
14503 for(var i = 0, len = b.length; i < len; i++){
14504 b[i].call(this, e);
14510 * Returns true if this KeyMap is enabled
14511 * @return {Boolean}
14513 isEnabled : function(){
14514 return this.enabled;
14518 * Enables this KeyMap
14520 enable: function(){
14522 this.el.on(this.eventName, this.handleKeyDown, this);
14523 this.enabled = true;
14528 * Disable this KeyMap
14530 disable: function(){
14532 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14533 this.enabled = false;
14538 * Ext JS Library 1.1.1
14539 * Copyright(c) 2006-2007, Ext JS, LLC.
14541 * Originally Released Under LGPL - original licence link has changed is not relivant.
14544 * <script type="text/javascript">
14549 * @class Roo.util.TextMetrics
14550 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14551 * wide, in pixels, a given block of text will be.
14554 Roo.util.TextMetrics = function(){
14558 * Measures the size of the specified text
14559 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14560 * that can affect the size of the rendered text
14561 * @param {String} text The text to measure
14562 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14563 * in order to accurately measure the text height
14564 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14566 measure : function(el, text, fixedWidth){
14568 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14571 shared.setFixedWidth(fixedWidth || 'auto');
14572 return shared.getSize(text);
14576 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14577 * the overhead of multiple calls to initialize the style properties on each measurement.
14578 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14579 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14580 * in order to accurately measure the text height
14581 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14583 createInstance : function(el, fixedWidth){
14584 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14591 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14592 var ml = new Roo.Element(document.createElement('div'));
14593 document.body.appendChild(ml.dom);
14594 ml.position('absolute');
14595 ml.setLeftTop(-1000, -1000);
14599 ml.setWidth(fixedWidth);
14604 * Returns the size of the specified text based on the internal element's style and width properties
14605 * @memberOf Roo.util.TextMetrics.Instance#
14606 * @param {String} text The text to measure
14607 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14609 getSize : function(text){
14611 var s = ml.getSize();
14617 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14618 * that can affect the size of the rendered text
14619 * @memberOf Roo.util.TextMetrics.Instance#
14620 * @param {String/HTMLElement} el The element, dom node or id
14622 bind : function(el){
14624 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14629 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14630 * to set a fixed width in order to accurately measure the text height.
14631 * @memberOf Roo.util.TextMetrics.Instance#
14632 * @param {Number} width The width to set on the element
14634 setFixedWidth : function(width){
14635 ml.setWidth(width);
14639 * Returns the measured width of the specified text
14640 * @memberOf Roo.util.TextMetrics.Instance#
14641 * @param {String} text The text to measure
14642 * @return {Number} width The width in pixels
14644 getWidth : function(text){
14645 ml.dom.style.width = 'auto';
14646 return this.getSize(text).width;
14650 * Returns the measured height of the specified text. For multiline text, be sure to call
14651 * {@link #setFixedWidth} if necessary.
14652 * @memberOf Roo.util.TextMetrics.Instance#
14653 * @param {String} text The text to measure
14654 * @return {Number} height The height in pixels
14656 getHeight : function(text){
14657 return this.getSize(text).height;
14661 instance.bind(bindTo);
14666 // backwards compat
14667 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14669 * Ext JS Library 1.1.1
14670 * Copyright(c) 2006-2007, Ext JS, LLC.
14672 * Originally Released Under LGPL - original licence link has changed is not relivant.
14675 * <script type="text/javascript">
14679 * @class Roo.state.Provider
14680 * Abstract base class for state provider implementations. This class provides methods
14681 * for encoding and decoding <b>typed</b> variables including dates and defines the
14682 * Provider interface.
14684 Roo.state.Provider = function(){
14686 * @event statechange
14687 * Fires when a state change occurs.
14688 * @param {Provider} this This state provider
14689 * @param {String} key The state key which was changed
14690 * @param {String} value The encoded value for the state
14693 "statechange": true
14696 Roo.state.Provider.superclass.constructor.call(this);
14698 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14700 * Returns the current value for a key
14701 * @param {String} name The key name
14702 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14703 * @return {Mixed} The state data
14705 get : function(name, defaultValue){
14706 return typeof this.state[name] == "undefined" ?
14707 defaultValue : this.state[name];
14711 * Clears a value from the state
14712 * @param {String} name The key name
14714 clear : function(name){
14715 delete this.state[name];
14716 this.fireEvent("statechange", this, name, null);
14720 * Sets the value for a key
14721 * @param {String} name The key name
14722 * @param {Mixed} value The value to set
14724 set : function(name, value){
14725 this.state[name] = value;
14726 this.fireEvent("statechange", this, name, value);
14730 * Decodes a string previously encoded with {@link #encodeValue}.
14731 * @param {String} value The value to decode
14732 * @return {Mixed} The decoded value
14734 decodeValue : function(cookie){
14735 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14736 var matches = re.exec(unescape(cookie));
14737 if(!matches || !matches[1]) return; // non state cookie
14738 var type = matches[1];
14739 var v = matches[2];
14742 return parseFloat(v);
14744 return new Date(Date.parse(v));
14749 var values = v.split("^");
14750 for(var i = 0, len = values.length; i < len; i++){
14751 all.push(this.decodeValue(values[i]));
14756 var values = v.split("^");
14757 for(var i = 0, len = values.length; i < len; i++){
14758 var kv = values[i].split("=");
14759 all[kv[0]] = this.decodeValue(kv[1]);
14768 * Encodes a value including type information. Decode with {@link #decodeValue}.
14769 * @param {Mixed} value The value to encode
14770 * @return {String} The encoded value
14772 encodeValue : function(v){
14774 if(typeof v == "number"){
14776 }else if(typeof v == "boolean"){
14777 enc = "b:" + (v ? "1" : "0");
14778 }else if(v instanceof Date){
14779 enc = "d:" + v.toGMTString();
14780 }else if(v instanceof Array){
14782 for(var i = 0, len = v.length; i < len; i++){
14783 flat += this.encodeValue(v[i]);
14784 if(i != len-1) flat += "^";
14787 }else if(typeof v == "object"){
14790 if(typeof v[key] != "function"){
14791 flat += key + "=" + this.encodeValue(v[key]) + "^";
14794 enc = "o:" + flat.substring(0, flat.length-1);
14798 return escape(enc);
14804 * Ext JS Library 1.1.1
14805 * Copyright(c) 2006-2007, Ext JS, LLC.
14807 * Originally Released Under LGPL - original licence link has changed is not relivant.
14810 * <script type="text/javascript">
14813 * @class Roo.state.Manager
14814 * This is the global state manager. By default all components that are "state aware" check this class
14815 * for state information if you don't pass them a custom state provider. In order for this class
14816 * to be useful, it must be initialized with a provider when your application initializes.
14818 // in your initialization function
14820 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14822 // supposed you have a {@link Roo.BorderLayout}
14823 var layout = new Roo.BorderLayout(...);
14824 layout.restoreState();
14825 // or a {Roo.BasicDialog}
14826 var dialog = new Roo.BasicDialog(...);
14827 dialog.restoreState();
14831 Roo.state.Manager = function(){
14832 var provider = new Roo.state.Provider();
14836 * Configures the default state provider for your application
14837 * @param {Provider} stateProvider The state provider to set
14839 setProvider : function(stateProvider){
14840 provider = stateProvider;
14844 * Returns the current value for a key
14845 * @param {String} name The key name
14846 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14847 * @return {Mixed} The state data
14849 get : function(key, defaultValue){
14850 return provider.get(key, defaultValue);
14854 * Sets the value for a key
14855 * @param {String} name The key name
14856 * @param {Mixed} value The state data
14858 set : function(key, value){
14859 provider.set(key, value);
14863 * Clears a value from the state
14864 * @param {String} name The key name
14866 clear : function(key){
14867 provider.clear(key);
14871 * Gets the currently configured state provider
14872 * @return {Provider} The state provider
14874 getProvider : function(){
14881 * Ext JS Library 1.1.1
14882 * Copyright(c) 2006-2007, Ext JS, LLC.
14884 * Originally Released Under LGPL - original licence link has changed is not relivant.
14887 * <script type="text/javascript">
14890 * @class Roo.state.CookieProvider
14891 * @extends Roo.state.Provider
14892 * The default Provider implementation which saves state via cookies.
14895 var cp = new Roo.state.CookieProvider({
14897 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14898 domain: "roojs.com"
14900 Roo.state.Manager.setProvider(cp);
14902 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14903 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14904 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14905 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14906 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14907 * domain the page is running on including the 'www' like 'www.roojs.com')
14908 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14910 * Create a new CookieProvider
14911 * @param {Object} config The configuration object
14913 Roo.state.CookieProvider = function(config){
14914 Roo.state.CookieProvider.superclass.constructor.call(this);
14916 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14917 this.domain = null;
14918 this.secure = false;
14919 Roo.apply(this, config);
14920 this.state = this.readCookies();
14923 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14925 set : function(name, value){
14926 if(typeof value == "undefined" || value === null){
14930 this.setCookie(name, value);
14931 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14935 clear : function(name){
14936 this.clearCookie(name);
14937 Roo.state.CookieProvider.superclass.clear.call(this, name);
14941 readCookies : function(){
14943 var c = document.cookie + ";";
14944 var re = /\s?(.*?)=(.*?);/g;
14946 while((matches = re.exec(c)) != null){
14947 var name = matches[1];
14948 var value = matches[2];
14949 if(name && name.substring(0,3) == "ys-"){
14950 cookies[name.substr(3)] = this.decodeValue(value);
14957 setCookie : function(name, value){
14958 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14959 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14960 ((this.path == null) ? "" : ("; path=" + this.path)) +
14961 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14962 ((this.secure == true) ? "; secure" : "");
14966 clearCookie : function(name){
14967 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14968 ((this.path == null) ? "" : ("; path=" + this.path)) +
14969 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14970 ((this.secure == true) ? "; secure" : "");
14974 * Ext JS Library 1.1.1
14975 * Copyright(c) 2006-2007, Ext JS, LLC.
14977 * Originally Released Under LGPL - original licence link has changed is not relivant.
14980 * <script type="text/javascript">
14985 * @class Roo.ComponentMgr
14986 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14989 Roo.ComponentMgr = function(){
14990 var all = new Roo.util.MixedCollection();
14994 * Registers a component.
14995 * @param {Roo.Component} c The component
14997 register : function(c){
15002 * Unregisters a component.
15003 * @param {Roo.Component} c The component
15005 unregister : function(c){
15010 * Returns a component by id
15011 * @param {String} id The component id
15013 get : function(id){
15014 return all.get(id);
15018 * Registers a function that will be called when a specified component is added to ComponentMgr
15019 * @param {String} id The component id
15020 * @param {Funtction} fn The callback function
15021 * @param {Object} scope The scope of the callback
15023 onAvailable : function(id, fn, scope){
15024 all.on("add", function(index, o){
15026 fn.call(scope || o, o);
15027 all.un("add", fn, scope);
15034 * Ext JS Library 1.1.1
15035 * Copyright(c) 2006-2007, Ext JS, LLC.
15037 * Originally Released Under LGPL - original licence link has changed is not relivant.
15040 * <script type="text/javascript">
15044 * @class Roo.Component
15045 * @extends Roo.util.Observable
15046 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15047 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15048 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15049 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15050 * All visual components (widgets) that require rendering into a layout should subclass Component.
15052 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15053 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15054 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15056 Roo.Component = function(config){
15057 config = config || {};
15058 if(config.tagName || config.dom || typeof config == "string"){ // element object
15059 config = {el: config, id: config.id || config};
15061 this.initialConfig = config;
15063 Roo.apply(this, config);
15067 * Fires after the component is disabled.
15068 * @param {Roo.Component} this
15073 * Fires after the component is enabled.
15074 * @param {Roo.Component} this
15078 * @event beforeshow
15079 * Fires before the component is shown. Return false to stop the show.
15080 * @param {Roo.Component} this
15085 * Fires after the component is shown.
15086 * @param {Roo.Component} this
15090 * @event beforehide
15091 * Fires before the component is hidden. Return false to stop the hide.
15092 * @param {Roo.Component} this
15097 * Fires after the component is hidden.
15098 * @param {Roo.Component} this
15102 * @event beforerender
15103 * Fires before the component is rendered. Return false to stop the render.
15104 * @param {Roo.Component} this
15106 beforerender : true,
15109 * Fires after the component is rendered.
15110 * @param {Roo.Component} this
15114 * @event beforedestroy
15115 * Fires before the component is destroyed. Return false to stop the destroy.
15116 * @param {Roo.Component} this
15118 beforedestroy : true,
15121 * Fires after the component is destroyed.
15122 * @param {Roo.Component} this
15127 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15129 Roo.ComponentMgr.register(this);
15130 Roo.Component.superclass.constructor.call(this);
15131 this.initComponent();
15132 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15133 this.render(this.renderTo);
15134 delete this.renderTo;
15139 Roo.Component.AUTO_ID = 1000;
15141 Roo.extend(Roo.Component, Roo.util.Observable, {
15143 * @scope Roo.Component.prototype
15145 * true if this component is hidden. Read-only.
15150 * true if this component is disabled. Read-only.
15155 * true if this component has been rendered. Read-only.
15159 /** @cfg {String} disableClass
15160 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15162 disabledClass : "x-item-disabled",
15163 /** @cfg {Boolean} allowDomMove
15164 * Whether the component can move the Dom node when rendering (defaults to true).
15166 allowDomMove : true,
15167 /** @cfg {String} hideMode
15168 * How this component should hidden. Supported values are
15169 * "visibility" (css visibility), "offsets" (negative offset position) and
15170 * "display" (css display) - defaults to "display".
15172 hideMode: 'display',
15175 ctype : "Roo.Component",
15178 * @cfg {String} actionMode
15179 * which property holds the element that used for hide() / show() / disable() / enable()
15185 getActionEl : function(){
15186 return this[this.actionMode];
15189 initComponent : Roo.emptyFn,
15191 * If this is a lazy rendering component, render it to its container element.
15192 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15194 render : function(container, position){
15195 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15196 if(!container && this.el){
15197 this.el = Roo.get(this.el);
15198 container = this.el.dom.parentNode;
15199 this.allowDomMove = false;
15201 this.container = Roo.get(container);
15202 this.rendered = true;
15203 if(position !== undefined){
15204 if(typeof position == 'number'){
15205 position = this.container.dom.childNodes[position];
15207 position = Roo.getDom(position);
15210 this.onRender(this.container, position || null);
15212 this.el.addClass(this.cls);
15216 this.el.applyStyles(this.style);
15219 this.fireEvent("render", this);
15220 this.afterRender(this.container);
15232 // default function is not really useful
15233 onRender : function(ct, position){
15235 this.el = Roo.get(this.el);
15236 if(this.allowDomMove !== false){
15237 ct.dom.insertBefore(this.el.dom, position);
15243 getAutoCreate : function(){
15244 var cfg = typeof this.autoCreate == "object" ?
15245 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15246 if(this.id && !cfg.id){
15253 afterRender : Roo.emptyFn,
15256 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15257 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15259 destroy : function(){
15260 if(this.fireEvent("beforedestroy", this) !== false){
15261 this.purgeListeners();
15262 this.beforeDestroy();
15264 this.el.removeAllListeners();
15266 if(this.actionMode == "container"){
15267 this.container.remove();
15271 Roo.ComponentMgr.unregister(this);
15272 this.fireEvent("destroy", this);
15277 beforeDestroy : function(){
15282 onDestroy : function(){
15287 * Returns the underlying {@link Roo.Element}.
15288 * @return {Roo.Element} The element
15290 getEl : function(){
15295 * Returns the id of this component.
15298 getId : function(){
15303 * Try to focus this component.
15304 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15305 * @return {Roo.Component} this
15307 focus : function(selectText){
15310 if(selectText === true){
15311 this.el.dom.select();
15326 * Disable this component.
15327 * @return {Roo.Component} this
15329 disable : function(){
15333 this.disabled = true;
15334 this.fireEvent("disable", this);
15339 onDisable : function(){
15340 this.getActionEl().addClass(this.disabledClass);
15341 this.el.dom.disabled = true;
15345 * Enable this component.
15346 * @return {Roo.Component} this
15348 enable : function(){
15352 this.disabled = false;
15353 this.fireEvent("enable", this);
15358 onEnable : function(){
15359 this.getActionEl().removeClass(this.disabledClass);
15360 this.el.dom.disabled = false;
15364 * Convenience function for setting disabled/enabled by boolean.
15365 * @param {Boolean} disabled
15367 setDisabled : function(disabled){
15368 this[disabled ? "disable" : "enable"]();
15372 * Show this component.
15373 * @return {Roo.Component} this
15376 if(this.fireEvent("beforeshow", this) !== false){
15377 this.hidden = false;
15381 this.fireEvent("show", this);
15387 onShow : function(){
15388 var ae = this.getActionEl();
15389 if(this.hideMode == 'visibility'){
15390 ae.dom.style.visibility = "visible";
15391 }else if(this.hideMode == 'offsets'){
15392 ae.removeClass('x-hidden');
15394 ae.dom.style.display = "";
15399 * Hide this component.
15400 * @return {Roo.Component} this
15403 if(this.fireEvent("beforehide", this) !== false){
15404 this.hidden = true;
15408 this.fireEvent("hide", this);
15414 onHide : function(){
15415 var ae = this.getActionEl();
15416 if(this.hideMode == 'visibility'){
15417 ae.dom.style.visibility = "hidden";
15418 }else if(this.hideMode == 'offsets'){
15419 ae.addClass('x-hidden');
15421 ae.dom.style.display = "none";
15426 * Convenience function to hide or show this component by boolean.
15427 * @param {Boolean} visible True to show, false to hide
15428 * @return {Roo.Component} this
15430 setVisible: function(visible){
15440 * Returns true if this component is visible.
15442 isVisible : function(){
15443 return this.getActionEl().isVisible();
15446 cloneConfig : function(overrides){
15447 overrides = overrides || {};
15448 var id = overrides.id || Roo.id();
15449 var cfg = Roo.applyIf(overrides, this.initialConfig);
15450 cfg.id = id; // prevent dup id
15451 return new this.constructor(cfg);
15455 * Ext JS Library 1.1.1
15456 * Copyright(c) 2006-2007, Ext JS, LLC.
15458 * Originally Released Under LGPL - original licence link has changed is not relivant.
15461 * <script type="text/javascript">
15465 * @class Roo.BoxComponent
15466 * @extends Roo.Component
15467 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15468 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15469 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15470 * layout containers.
15472 * @param {Roo.Element/String/Object} config The configuration options.
15474 Roo.BoxComponent = function(config){
15475 Roo.Component.call(this, config);
15479 * Fires after the component is resized.
15480 * @param {Roo.Component} this
15481 * @param {Number} adjWidth The box-adjusted width that was set
15482 * @param {Number} adjHeight The box-adjusted height that was set
15483 * @param {Number} rawWidth The width that was originally specified
15484 * @param {Number} rawHeight The height that was originally specified
15489 * Fires after the component is moved.
15490 * @param {Roo.Component} this
15491 * @param {Number} x The new x position
15492 * @param {Number} y The new y position
15498 Roo.extend(Roo.BoxComponent, Roo.Component, {
15499 // private, set in afterRender to signify that the component has been rendered
15501 // private, used to defer height settings to subclasses
15502 deferHeight: false,
15503 /** @cfg {Number} width
15504 * width (optional) size of component
15506 /** @cfg {Number} height
15507 * height (optional) size of component
15511 * Sets the width and height of the component. This method fires the resize event. This method can accept
15512 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15513 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15514 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15515 * @return {Roo.BoxComponent} this
15517 setSize : function(w, h){
15518 // support for standard size objects
15519 if(typeof w == 'object'){
15524 if(!this.boxReady){
15530 // prevent recalcs when not needed
15531 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15534 this.lastSize = {width: w, height: h};
15536 var adj = this.adjustSize(w, h);
15537 var aw = adj.width, ah = adj.height;
15538 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15539 var rz = this.getResizeEl();
15540 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15541 rz.setSize(aw, ah);
15542 }else if(!this.deferHeight && ah !== undefined){
15544 }else if(aw !== undefined){
15547 this.onResize(aw, ah, w, h);
15548 this.fireEvent('resize', this, aw, ah, w, h);
15554 * Gets the current size of the component's underlying element.
15555 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15557 getSize : function(){
15558 return this.el.getSize();
15562 * Gets the current XY position of the component's underlying element.
15563 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15564 * @return {Array} The XY position of the element (e.g., [100, 200])
15566 getPosition : function(local){
15567 if(local === true){
15568 return [this.el.getLeft(true), this.el.getTop(true)];
15570 return this.xy || this.el.getXY();
15574 * Gets the current box measurements of the component's underlying element.
15575 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15576 * @returns {Object} box An object in the format {x, y, width, height}
15578 getBox : function(local){
15579 var s = this.el.getSize();
15581 s.x = this.el.getLeft(true);
15582 s.y = this.el.getTop(true);
15584 var xy = this.xy || this.el.getXY();
15592 * Sets the current box measurements of the component's underlying element.
15593 * @param {Object} box An object in the format {x, y, width, height}
15594 * @returns {Roo.BoxComponent} this
15596 updateBox : function(box){
15597 this.setSize(box.width, box.height);
15598 this.setPagePosition(box.x, box.y);
15603 getResizeEl : function(){
15604 return this.resizeEl || this.el;
15608 getPositionEl : function(){
15609 return this.positionEl || this.el;
15613 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15614 * This method fires the move event.
15615 * @param {Number} left The new left
15616 * @param {Number} top The new top
15617 * @returns {Roo.BoxComponent} this
15619 setPosition : function(x, y){
15622 if(!this.boxReady){
15625 var adj = this.adjustPosition(x, y);
15626 var ax = adj.x, ay = adj.y;
15628 var el = this.getPositionEl();
15629 if(ax !== undefined || ay !== undefined){
15630 if(ax !== undefined && ay !== undefined){
15631 el.setLeftTop(ax, ay);
15632 }else if(ax !== undefined){
15634 }else if(ay !== undefined){
15637 this.onPosition(ax, ay);
15638 this.fireEvent('move', this, ax, ay);
15644 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15645 * This method fires the move event.
15646 * @param {Number} x The new x position
15647 * @param {Number} y The new y position
15648 * @returns {Roo.BoxComponent} this
15650 setPagePosition : function(x, y){
15653 if(!this.boxReady){
15656 if(x === undefined || y === undefined){ // cannot translate undefined points
15659 var p = this.el.translatePoints(x, y);
15660 this.setPosition(p.left, p.top);
15665 onRender : function(ct, position){
15666 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15668 this.resizeEl = Roo.get(this.resizeEl);
15670 if(this.positionEl){
15671 this.positionEl = Roo.get(this.positionEl);
15676 afterRender : function(){
15677 Roo.BoxComponent.superclass.afterRender.call(this);
15678 this.boxReady = true;
15679 this.setSize(this.width, this.height);
15680 if(this.x || this.y){
15681 this.setPosition(this.x, this.y);
15683 if(this.pageX || this.pageY){
15684 this.setPagePosition(this.pageX, this.pageY);
15689 * Force the component's size to recalculate based on the underlying element's current height and width.
15690 * @returns {Roo.BoxComponent} this
15692 syncSize : function(){
15693 delete this.lastSize;
15694 this.setSize(this.el.getWidth(), this.el.getHeight());
15699 * Called after the component is resized, this method is empty by default but can be implemented by any
15700 * subclass that needs to perform custom logic after a resize occurs.
15701 * @param {Number} adjWidth The box-adjusted width that was set
15702 * @param {Number} adjHeight The box-adjusted height that was set
15703 * @param {Number} rawWidth The width that was originally specified
15704 * @param {Number} rawHeight The height that was originally specified
15706 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15711 * Called after the component is moved, this method is empty by default but can be implemented by any
15712 * subclass that needs to perform custom logic after a move occurs.
15713 * @param {Number} x The new x position
15714 * @param {Number} y The new y position
15716 onPosition : function(x, y){
15721 adjustSize : function(w, h){
15722 if(this.autoWidth){
15725 if(this.autoHeight){
15728 return {width : w, height: h};
15732 adjustPosition : function(x, y){
15733 return {x : x, y: y};
15736 * Original code for Roojs - LGPL
15737 * <script type="text/javascript">
15741 * @class Roo.XComponent
15742 * A delayed Element creator...
15743 * Or a way to group chunks of interface together.
15745 * Mypart.xyx = new Roo.XComponent({
15747 parent : 'Mypart.xyz', // empty == document.element.!!
15751 disabled : function() {}
15753 tree : function() { // return an tree of xtype declared components
15757 xtype : 'NestedLayoutPanel',
15764 * It can be used to build a big heiracy, with parent etc.
15765 * or you can just use this to render a single compoent to a dom element
15766 * MYPART.render(Roo.Element | String(id) | dom_element )
15768 * @extends Roo.util.Observable
15770 * @param cfg {Object} configuration of component
15773 Roo.XComponent = function(cfg) {
15774 Roo.apply(this, cfg);
15778 * Fires when this the componnt is built
15779 * @param {Roo.XComponent} c the component
15784 this.region = this.region || 'center'; // default..
15785 Roo.XComponent.register(this);
15786 this.modules = false;
15787 this.el = false; // where the layout goes..
15791 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15794 * The created element (with Roo.factory())
15795 * @type {Roo.Layout}
15801 * for BC - use el in new code
15802 * @type {Roo.Layout}
15808 * for BC - use el in new code
15809 * @type {Roo.Layout}
15814 * @cfg {Function|boolean} disabled
15815 * If this module is disabled by some rule, return true from the funtion
15820 * @cfg {String} parent
15821 * Name of parent element which it get xtype added to..
15826 * @cfg {String} order
15827 * Used to set the order in which elements are created (usefull for multiple tabs)
15832 * @cfg {String} name
15833 * String to display while loading.
15837 * @cfg {String} region
15838 * Region to render component to (defaults to center)
15843 * @cfg {Array} items
15844 * A single item array - the first element is the root of the tree..
15845 * It's done this way to stay compatible with the Xtype system...
15851 * The method that retuns the tree of parts that make up this compoennt
15858 * render element to dom or tree
15859 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15862 render : function(el)
15866 var hp = this.parent ? 1 : 0;
15868 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15869 // if parent is a '#.....' string, then let's use that..
15870 var ename = this.parent.substr(1)
15871 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15872 el = Roo.get(ename);
15873 if (!el && !this.parent) {
15874 Roo.log("Warning - element can not be found :#" + ename );
15878 var tree = this._tree ? this._tree() : this.tree();
15880 // altertive root elements ??? - we need a better way to indicate these.
15881 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15882 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15884 if (!this.parent && is_alt) {
15885 //el = Roo.get(document.body);
15886 this.parent = { el : true };
15891 if (!this.parent) {
15893 Roo.log("no parent - creating one");
15895 el = el ? Roo.get(el) : false;
15897 // it's a top level one..
15899 el : new Roo.BorderLayout(el || document.body, {
15905 tabPosition: 'top',
15906 //resizeTabs: true,
15907 alwaysShowTabs: el && hp? false : true,
15908 hideTabs: el || !hp ? true : false,
15915 if (!this.parent.el) {
15916 // probably an old style ctor, which has been disabled.
15920 // The 'tree' method is '_tree now'
15922 tree.region = tree.region || this.region;
15924 if (this.parent.el === true) {
15925 // bootstrap... - body..
15926 this.parent.el = Roo.factory(tree);
15929 this.el = this.parent.el.addxtype(tree);
15930 this.fireEvent('built', this);
15932 this.panel = this.el;
15933 this.layout = this.panel.layout;
15934 this.parentLayout = this.parent.layout || false;
15940 Roo.apply(Roo.XComponent, {
15942 * @property hideProgress
15943 * true to disable the building progress bar.. usefull on single page renders.
15946 hideProgress : false,
15948 * @property buildCompleted
15949 * True when the builder has completed building the interface.
15952 buildCompleted : false,
15955 * @property topModule
15956 * the upper most module - uses document.element as it's constructor.
15963 * @property modules
15964 * array of modules to be created by registration system.
15965 * @type {Array} of Roo.XComponent
15970 * @property elmodules
15971 * array of modules to be created by which use #ID
15972 * @type {Array} of Roo.XComponent
15978 * @property build_from_html
15979 * Build elements from html - used by bootstrap HTML stuff
15980 * - this is cleared after build is completed
15981 * @type {boolean} true (default false)
15984 build_from_html : false,
15987 * Register components to be built later.
15989 * This solves the following issues
15990 * - Building is not done on page load, but after an authentication process has occured.
15991 * - Interface elements are registered on page load
15992 * - Parent Interface elements may not be loaded before child, so this handles that..
15999 module : 'Pman.Tab.projectMgr',
16001 parent : 'Pman.layout',
16002 disabled : false, // or use a function..
16005 * * @param {Object} details about module
16007 register : function(obj) {
16009 Roo.XComponent.event.fireEvent('register', obj);
16010 switch(typeof(obj.disabled) ) {
16016 if ( obj.disabled() ) {
16022 if (obj.disabled) {
16028 this.modules.push(obj);
16032 * convert a string to an object..
16033 * eg. 'AAA.BBB' -> finds AAA.BBB
16037 toObject : function(str)
16039 if (!str || typeof(str) == 'object') {
16042 if (str.substring(0,1) == '#') {
16046 var ar = str.split('.');
16051 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16053 throw "Module not found : " + str;
16057 throw "Module not found : " + str;
16059 Roo.each(ar, function(e) {
16060 if (typeof(o[e]) == 'undefined') {
16061 throw "Module not found : " + str;
16072 * move modules into their correct place in the tree..
16075 preBuild : function ()
16078 Roo.each(this.modules , function (obj)
16080 Roo.XComponent.event.fireEvent('beforebuild', obj);
16082 var opar = obj.parent;
16084 obj.parent = this.toObject(opar);
16086 Roo.log("parent:toObject failed: " + e.toString());
16091 Roo.debug && Roo.log("GOT top level module");
16092 Roo.debug && Roo.log(obj);
16093 obj.modules = new Roo.util.MixedCollection(false,
16094 function(o) { return o.order + '' }
16096 this.topModule = obj;
16099 // parent is a string (usually a dom element name..)
16100 if (typeof(obj.parent) == 'string') {
16101 this.elmodules.push(obj);
16104 if (obj.parent.constructor != Roo.XComponent) {
16105 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16107 if (!obj.parent.modules) {
16108 obj.parent.modules = new Roo.util.MixedCollection(false,
16109 function(o) { return o.order + '' }
16112 if (obj.parent.disabled) {
16113 obj.disabled = true;
16115 obj.parent.modules.add(obj);
16120 * make a list of modules to build.
16121 * @return {Array} list of modules.
16124 buildOrder : function()
16127 var cmp = function(a,b) {
16128 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16130 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16131 throw "No top level modules to build";
16134 // make a flat list in order of modules to build.
16135 var mods = this.topModule ? [ this.topModule ] : [];
16138 // elmodules (is a list of DOM based modules )
16139 Roo.each(this.elmodules, function(e) {
16141 if (!this.topModule &&
16142 typeof(e.parent) == 'string' &&
16143 e.parent.substring(0,1) == '#' &&
16144 Roo.get(e.parent.substr(1))
16147 _this.topModule = e;
16153 // add modules to their parents..
16154 var addMod = function(m) {
16155 Roo.debug && Roo.log("build Order: add: " + m.name);
16158 if (m.modules && !m.disabled) {
16159 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16160 m.modules.keySort('ASC', cmp );
16161 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16163 m.modules.each(addMod);
16165 Roo.debug && Roo.log("build Order: no child modules");
16167 // not sure if this is used any more..
16169 m.finalize.name = m.name + " (clean up) ";
16170 mods.push(m.finalize);
16174 if (this.topModule && this.topModule.modules) {
16175 this.topModule.modules.keySort('ASC', cmp );
16176 this.topModule.modules.each(addMod);
16182 * Build the registered modules.
16183 * @param {Object} parent element.
16184 * @param {Function} optional method to call after module has been added.
16188 build : function(opts)
16191 if (typeof(opts) != 'undefined') {
16192 Roo.apply(this,opts);
16196 var mods = this.buildOrder();
16198 //this.allmods = mods;
16199 //Roo.debug && Roo.log(mods);
16201 if (!mods.length) { // should not happen
16202 throw "NO modules!!!";
16206 var msg = "Building Interface...";
16207 // flash it up as modal - so we store the mask!?
16208 if (!this.hideProgress && Roo.MessageBox) {
16209 Roo.MessageBox.show({ title: 'loading' });
16210 Roo.MessageBox.show({
16211 title: "Please wait...",
16220 var total = mods.length;
16223 var progressRun = function() {
16224 if (!mods.length) {
16225 Roo.debug && Roo.log('hide?');
16226 if (!this.hideProgress && Roo.MessageBox) {
16227 Roo.MessageBox.hide();
16229 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16231 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16237 var m = mods.shift();
16240 Roo.debug && Roo.log(m);
16241 // not sure if this is supported any more.. - modules that are are just function
16242 if (typeof(m) == 'function') {
16244 return progressRun.defer(10, _this);
16248 msg = "Building Interface " + (total - mods.length) +
16250 (m.name ? (' - ' + m.name) : '');
16251 Roo.debug && Roo.log(msg);
16252 if (!this.hideProgress && Roo.MessageBox) {
16253 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16257 // is the module disabled?
16258 var disabled = (typeof(m.disabled) == 'function') ?
16259 m.disabled.call(m.module.disabled) : m.disabled;
16263 return progressRun(); // we do not update the display!
16271 // it's 10 on top level, and 1 on others??? why...
16272 return progressRun.defer(10, _this);
16275 progressRun.defer(1, _this);
16289 * wrapper for event.on - aliased later..
16290 * Typically use to register a event handler for register:
16292 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16301 Roo.XComponent.event = new Roo.util.Observable({
16305 * Fires when an Component is registered,
16306 * set the disable property on the Component to stop registration.
16307 * @param {Roo.XComponent} c the component being registerd.
16312 * @event beforebuild
16313 * Fires before each Component is built
16314 * can be used to apply permissions.
16315 * @param {Roo.XComponent} c the component being registerd.
16318 'beforebuild' : true,
16320 * @event buildcomplete
16321 * Fires on the top level element when all elements have been built
16322 * @param {Roo.XComponent} the top level component.
16324 'buildcomplete' : true
16329 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16332 * Ext JS Library 1.1.1
16333 * Copyright(c) 2006-2007, Ext JS, LLC.
16335 * Originally Released Under LGPL - original licence link has changed is not relivant.
16338 * <script type="text/javascript">
16344 * These classes are derivatives of the similarly named classes in the YUI Library.
16345 * The original license:
16346 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16347 * Code licensed under the BSD License:
16348 * http://developer.yahoo.net/yui/license.txt
16353 var Event=Roo.EventManager;
16354 var Dom=Roo.lib.Dom;
16357 * @class Roo.dd.DragDrop
16358 * @extends Roo.util.Observable
16359 * Defines the interface and base operation of items that that can be
16360 * dragged or can be drop targets. It was designed to be extended, overriding
16361 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16362 * Up to three html elements can be associated with a DragDrop instance:
16364 * <li>linked element: the element that is passed into the constructor.
16365 * This is the element which defines the boundaries for interaction with
16366 * other DragDrop objects.</li>
16367 * <li>handle element(s): The drag operation only occurs if the element that
16368 * was clicked matches a handle element. By default this is the linked
16369 * element, but there are times that you will want only a portion of the
16370 * linked element to initiate the drag operation, and the setHandleElId()
16371 * method provides a way to define this.</li>
16372 * <li>drag element: this represents the element that would be moved along
16373 * with the cursor during a drag operation. By default, this is the linked
16374 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16375 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16378 * This class should not be instantiated until the onload event to ensure that
16379 * the associated elements are available.
16380 * The following would define a DragDrop obj that would interact with any
16381 * other DragDrop obj in the "group1" group:
16383 * dd = new Roo.dd.DragDrop("div1", "group1");
16385 * Since none of the event handlers have been implemented, nothing would
16386 * actually happen if you were to run the code above. Normally you would
16387 * override this class or one of the default implementations, but you can
16388 * also override the methods you want on an instance of the class...
16390 * dd.onDragDrop = function(e, id) {
16391 * alert("dd was dropped on " + id);
16395 * @param {String} id of the element that is linked to this instance
16396 * @param {String} sGroup the group of related DragDrop objects
16397 * @param {object} config an object containing configurable attributes
16398 * Valid properties for DragDrop:
16399 * padding, isTarget, maintainOffset, primaryButtonOnly
16401 Roo.dd.DragDrop = function(id, sGroup, config) {
16403 this.init(id, sGroup, config);
16408 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16411 * The id of the element associated with this object. This is what we
16412 * refer to as the "linked element" because the size and position of
16413 * this element is used to determine when the drag and drop objects have
16421 * Configuration attributes passed into the constructor
16428 * The id of the element that will be dragged. By default this is same
16429 * as the linked element , but could be changed to another element. Ex:
16431 * @property dragElId
16438 * the id of the element that initiates the drag operation. By default
16439 * this is the linked element, but could be changed to be a child of this
16440 * element. This lets us do things like only starting the drag when the
16441 * header element within the linked html element is clicked.
16442 * @property handleElId
16449 * An associative array of HTML tags that will be ignored if clicked.
16450 * @property invalidHandleTypes
16451 * @type {string: string}
16453 invalidHandleTypes: null,
16456 * An associative array of ids for elements that will be ignored if clicked
16457 * @property invalidHandleIds
16458 * @type {string: string}
16460 invalidHandleIds: null,
16463 * An indexted array of css class names for elements that will be ignored
16465 * @property invalidHandleClasses
16468 invalidHandleClasses: null,
16471 * The linked element's absolute X position at the time the drag was
16473 * @property startPageX
16480 * The linked element's absolute X position at the time the drag was
16482 * @property startPageY
16489 * The group defines a logical collection of DragDrop objects that are
16490 * related. Instances only get events when interacting with other
16491 * DragDrop object in the same group. This lets us define multiple
16492 * groups using a single DragDrop subclass if we want.
16494 * @type {string: string}
16499 * Individual drag/drop instances can be locked. This will prevent
16500 * onmousedown start drag.
16508 * Lock this instance
16511 lock: function() { this.locked = true; },
16514 * Unlock this instace
16517 unlock: function() { this.locked = false; },
16520 * By default, all insances can be a drop target. This can be disabled by
16521 * setting isTarget to false.
16528 * The padding configured for this drag and drop object for calculating
16529 * the drop zone intersection with this object.
16536 * Cached reference to the linked element
16537 * @property _domRef
16543 * Internal typeof flag
16544 * @property __ygDragDrop
16547 __ygDragDrop: true,
16550 * Set to true when horizontal contraints are applied
16551 * @property constrainX
16558 * Set to true when vertical contraints are applied
16559 * @property constrainY
16566 * The left constraint
16574 * The right constraint
16582 * The up constraint
16591 * The down constraint
16599 * Maintain offsets when we resetconstraints. Set to true when you want
16600 * the position of the element relative to its parent to stay the same
16601 * when the page changes
16603 * @property maintainOffset
16606 maintainOffset: false,
16609 * Array of pixel locations the element will snap to if we specified a
16610 * horizontal graduation/interval. This array is generated automatically
16611 * when you define a tick interval.
16618 * Array of pixel locations the element will snap to if we specified a
16619 * vertical graduation/interval. This array is generated automatically
16620 * when you define a tick interval.
16627 * By default the drag and drop instance will only respond to the primary
16628 * button click (left button for a right-handed mouse). Set to true to
16629 * allow drag and drop to start with any mouse click that is propogated
16631 * @property primaryButtonOnly
16634 primaryButtonOnly: true,
16637 * The availabe property is false until the linked dom element is accessible.
16638 * @property available
16644 * By default, drags can only be initiated if the mousedown occurs in the
16645 * region the linked element is. This is done in part to work around a
16646 * bug in some browsers that mis-report the mousedown if the previous
16647 * mouseup happened outside of the window. This property is set to true
16648 * if outer handles are defined.
16650 * @property hasOuterHandles
16654 hasOuterHandles: false,
16657 * Code that executes immediately before the startDrag event
16658 * @method b4StartDrag
16661 b4StartDrag: function(x, y) { },
16664 * Abstract method called after a drag/drop object is clicked
16665 * and the drag or mousedown time thresholds have beeen met.
16666 * @method startDrag
16667 * @param {int} X click location
16668 * @param {int} Y click location
16670 startDrag: function(x, y) { /* override this */ },
16673 * Code that executes immediately before the onDrag event
16677 b4Drag: function(e) { },
16680 * Abstract method called during the onMouseMove event while dragging an
16683 * @param {Event} e the mousemove event
16685 onDrag: function(e) { /* override this */ },
16688 * Abstract method called when this element fist begins hovering over
16689 * another DragDrop obj
16690 * @method onDragEnter
16691 * @param {Event} e the mousemove event
16692 * @param {String|DragDrop[]} id In POINT mode, the element
16693 * id this is hovering over. In INTERSECT mode, an array of one or more
16694 * dragdrop items being hovered over.
16696 onDragEnter: function(e, id) { /* override this */ },
16699 * Code that executes immediately before the onDragOver event
16700 * @method b4DragOver
16703 b4DragOver: function(e) { },
16706 * Abstract method called when this element is hovering over another
16708 * @method onDragOver
16709 * @param {Event} e the mousemove event
16710 * @param {String|DragDrop[]} id In POINT mode, the element
16711 * id this is hovering over. In INTERSECT mode, an array of dd items
16712 * being hovered over.
16714 onDragOver: function(e, id) { /* override this */ },
16717 * Code that executes immediately before the onDragOut event
16718 * @method b4DragOut
16721 b4DragOut: function(e) { },
16724 * Abstract method called when we are no longer hovering over an element
16725 * @method onDragOut
16726 * @param {Event} e the mousemove event
16727 * @param {String|DragDrop[]} id In POINT mode, the element
16728 * id this was hovering over. In INTERSECT mode, an array of dd items
16729 * that the mouse is no longer over.
16731 onDragOut: function(e, id) { /* override this */ },
16734 * Code that executes immediately before the onDragDrop event
16735 * @method b4DragDrop
16738 b4DragDrop: function(e) { },
16741 * Abstract method called when this item is dropped on another DragDrop
16743 * @method onDragDrop
16744 * @param {Event} e the mouseup event
16745 * @param {String|DragDrop[]} id In POINT mode, the element
16746 * id this was dropped on. In INTERSECT mode, an array of dd items this
16749 onDragDrop: function(e, id) { /* override this */ },
16752 * Abstract method called when this item is dropped on an area with no
16754 * @method onInvalidDrop
16755 * @param {Event} e the mouseup event
16757 onInvalidDrop: function(e) { /* override this */ },
16760 * Code that executes immediately before the endDrag event
16761 * @method b4EndDrag
16764 b4EndDrag: function(e) { },
16767 * Fired when we are done dragging the object
16769 * @param {Event} e the mouseup event
16771 endDrag: function(e) { /* override this */ },
16774 * Code executed immediately before the onMouseDown event
16775 * @method b4MouseDown
16776 * @param {Event} e the mousedown event
16779 b4MouseDown: function(e) { },
16782 * Event handler that fires when a drag/drop obj gets a mousedown
16783 * @method onMouseDown
16784 * @param {Event} e the mousedown event
16786 onMouseDown: function(e) { /* override this */ },
16789 * Event handler that fires when a drag/drop obj gets a mouseup
16790 * @method onMouseUp
16791 * @param {Event} e the mouseup event
16793 onMouseUp: function(e) { /* override this */ },
16796 * Override the onAvailable method to do what is needed after the initial
16797 * position was determined.
16798 * @method onAvailable
16800 onAvailable: function () {
16804 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16807 defaultPadding : {left:0, right:0, top:0, bottom:0},
16810 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16814 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16815 { dragElId: "existingProxyDiv" });
16816 dd.startDrag = function(){
16817 this.constrainTo("parent-id");
16820 * Or you can initalize it using the {@link Roo.Element} object:
16822 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16823 startDrag : function(){
16824 this.constrainTo("parent-id");
16828 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16829 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16830 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16831 * an object containing the sides to pad. For example: {right:10, bottom:10}
16832 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16834 constrainTo : function(constrainTo, pad, inContent){
16835 if(typeof pad == "number"){
16836 pad = {left: pad, right:pad, top:pad, bottom:pad};
16838 pad = pad || this.defaultPadding;
16839 var b = Roo.get(this.getEl()).getBox();
16840 var ce = Roo.get(constrainTo);
16841 var s = ce.getScroll();
16842 var c, cd = ce.dom;
16843 if(cd == document.body){
16844 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16847 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16851 var topSpace = b.y - c.y;
16852 var leftSpace = b.x - c.x;
16854 this.resetConstraints();
16855 this.setXConstraint(leftSpace - (pad.left||0), // left
16856 c.width - leftSpace - b.width - (pad.right||0) //right
16858 this.setYConstraint(topSpace - (pad.top||0), //top
16859 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16864 * Returns a reference to the linked element
16866 * @return {HTMLElement} the html element
16868 getEl: function() {
16869 if (!this._domRef) {
16870 this._domRef = Roo.getDom(this.id);
16873 return this._domRef;
16877 * Returns a reference to the actual element to drag. By default this is
16878 * the same as the html element, but it can be assigned to another
16879 * element. An example of this can be found in Roo.dd.DDProxy
16880 * @method getDragEl
16881 * @return {HTMLElement} the html element
16883 getDragEl: function() {
16884 return Roo.getDom(this.dragElId);
16888 * Sets up the DragDrop object. Must be called in the constructor of any
16889 * Roo.dd.DragDrop subclass
16891 * @param id the id of the linked element
16892 * @param {String} sGroup the group of related items
16893 * @param {object} config configuration attributes
16895 init: function(id, sGroup, config) {
16896 this.initTarget(id, sGroup, config);
16897 if (!Roo.isTouch) {
16898 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16900 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16901 // Event.on(this.id, "selectstart", Event.preventDefault);
16905 * Initializes Targeting functionality only... the object does not
16906 * get a mousedown handler.
16907 * @method initTarget
16908 * @param id the id of the linked element
16909 * @param {String} sGroup the group of related items
16910 * @param {object} config configuration attributes
16912 initTarget: function(id, sGroup, config) {
16914 // configuration attributes
16915 this.config = config || {};
16917 // create a local reference to the drag and drop manager
16918 this.DDM = Roo.dd.DDM;
16919 // initialize the groups array
16922 // assume that we have an element reference instead of an id if the
16923 // parameter is not a string
16924 if (typeof id !== "string") {
16931 // add to an interaction group
16932 this.addToGroup((sGroup) ? sGroup : "default");
16934 // We don't want to register this as the handle with the manager
16935 // so we just set the id rather than calling the setter.
16936 this.handleElId = id;
16938 // the linked element is the element that gets dragged by default
16939 this.setDragElId(id);
16941 // by default, clicked anchors will not start drag operations.
16942 this.invalidHandleTypes = { A: "A" };
16943 this.invalidHandleIds = {};
16944 this.invalidHandleClasses = [];
16946 this.applyConfig();
16948 this.handleOnAvailable();
16952 * Applies the configuration parameters that were passed into the constructor.
16953 * This is supposed to happen at each level through the inheritance chain. So
16954 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16955 * DragDrop in order to get all of the parameters that are available in
16957 * @method applyConfig
16959 applyConfig: function() {
16961 // configurable properties:
16962 // padding, isTarget, maintainOffset, primaryButtonOnly
16963 this.padding = this.config.padding || [0, 0, 0, 0];
16964 this.isTarget = (this.config.isTarget !== false);
16965 this.maintainOffset = (this.config.maintainOffset);
16966 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16971 * Executed when the linked element is available
16972 * @method handleOnAvailable
16975 handleOnAvailable: function() {
16976 this.available = true;
16977 this.resetConstraints();
16978 this.onAvailable();
16982 * Configures the padding for the target zone in px. Effectively expands
16983 * (or reduces) the virtual object size for targeting calculations.
16984 * Supports css-style shorthand; if only one parameter is passed, all sides
16985 * will have that padding, and if only two are passed, the top and bottom
16986 * will have the first param, the left and right the second.
16987 * @method setPadding
16988 * @param {int} iTop Top pad
16989 * @param {int} iRight Right pad
16990 * @param {int} iBot Bot pad
16991 * @param {int} iLeft Left pad
16993 setPadding: function(iTop, iRight, iBot, iLeft) {
16994 // this.padding = [iLeft, iRight, iTop, iBot];
16995 if (!iRight && 0 !== iRight) {
16996 this.padding = [iTop, iTop, iTop, iTop];
16997 } else if (!iBot && 0 !== iBot) {
16998 this.padding = [iTop, iRight, iTop, iRight];
17000 this.padding = [iTop, iRight, iBot, iLeft];
17005 * Stores the initial placement of the linked element.
17006 * @method setInitialPosition
17007 * @param {int} diffX the X offset, default 0
17008 * @param {int} diffY the Y offset, default 0
17010 setInitPosition: function(diffX, diffY) {
17011 var el = this.getEl();
17013 if (!this.DDM.verifyEl(el)) {
17017 var dx = diffX || 0;
17018 var dy = diffY || 0;
17020 var p = Dom.getXY( el );
17022 this.initPageX = p[0] - dx;
17023 this.initPageY = p[1] - dy;
17025 this.lastPageX = p[0];
17026 this.lastPageY = p[1];
17029 this.setStartPosition(p);
17033 * Sets the start position of the element. This is set when the obj
17034 * is initialized, the reset when a drag is started.
17035 * @method setStartPosition
17036 * @param pos current position (from previous lookup)
17039 setStartPosition: function(pos) {
17040 var p = pos || Dom.getXY( this.getEl() );
17041 this.deltaSetXY = null;
17043 this.startPageX = p[0];
17044 this.startPageY = p[1];
17048 * Add this instance to a group of related drag/drop objects. All
17049 * instances belong to at least one group, and can belong to as many
17050 * groups as needed.
17051 * @method addToGroup
17052 * @param sGroup {string} the name of the group
17054 addToGroup: function(sGroup) {
17055 this.groups[sGroup] = true;
17056 this.DDM.regDragDrop(this, sGroup);
17060 * Remove's this instance from the supplied interaction group
17061 * @method removeFromGroup
17062 * @param {string} sGroup The group to drop
17064 removeFromGroup: function(sGroup) {
17065 if (this.groups[sGroup]) {
17066 delete this.groups[sGroup];
17069 this.DDM.removeDDFromGroup(this, sGroup);
17073 * Allows you to specify that an element other than the linked element
17074 * will be moved with the cursor during a drag
17075 * @method setDragElId
17076 * @param id {string} the id of the element that will be used to initiate the drag
17078 setDragElId: function(id) {
17079 this.dragElId = id;
17083 * Allows you to specify a child of the linked element that should be
17084 * used to initiate the drag operation. An example of this would be if
17085 * you have a content div with text and links. Clicking anywhere in the
17086 * content area would normally start the drag operation. Use this method
17087 * to specify that an element inside of the content div is the element
17088 * that starts the drag operation.
17089 * @method setHandleElId
17090 * @param id {string} the id of the element that will be used to
17091 * initiate the drag.
17093 setHandleElId: function(id) {
17094 if (typeof id !== "string") {
17097 this.handleElId = id;
17098 this.DDM.regHandle(this.id, id);
17102 * Allows you to set an element outside of the linked element as a drag
17104 * @method setOuterHandleElId
17105 * @param id the id of the element that will be used to initiate the drag
17107 setOuterHandleElId: function(id) {
17108 if (typeof id !== "string") {
17111 Event.on(id, "mousedown",
17112 this.handleMouseDown, this);
17113 this.setHandleElId(id);
17115 this.hasOuterHandles = true;
17119 * Remove all drag and drop hooks for this element
17122 unreg: function() {
17123 Event.un(this.id, "mousedown",
17124 this.handleMouseDown);
17125 Event.un(this.id, "touchstart",
17126 this.handleMouseDown);
17127 this._domRef = null;
17128 this.DDM._remove(this);
17131 destroy : function(){
17136 * Returns true if this instance is locked, or the drag drop mgr is locked
17137 * (meaning that all drag/drop is disabled on the page.)
17139 * @return {boolean} true if this obj or all drag/drop is locked, else
17142 isLocked: function() {
17143 return (this.DDM.isLocked() || this.locked);
17147 * Fired when this object is clicked
17148 * @method handleMouseDown
17150 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17153 handleMouseDown: function(e, oDD){
17155 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17156 //Roo.log('not touch/ button !=0');
17159 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17160 return; // double touch..
17164 if (this.isLocked()) {
17165 //Roo.log('locked');
17169 this.DDM.refreshCache(this.groups);
17170 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17171 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17172 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17173 //Roo.log('no outer handes or not over target');
17176 // Roo.log('check validator');
17177 if (this.clickValidator(e)) {
17178 // Roo.log('validate success');
17179 // set the initial element position
17180 this.setStartPosition();
17183 this.b4MouseDown(e);
17184 this.onMouseDown(e);
17186 this.DDM.handleMouseDown(e, this);
17188 this.DDM.stopEvent(e);
17196 clickValidator: function(e) {
17197 var target = e.getTarget();
17198 return ( this.isValidHandleChild(target) &&
17199 (this.id == this.handleElId ||
17200 this.DDM.handleWasClicked(target, this.id)) );
17204 * Allows you to specify a tag name that should not start a drag operation
17205 * when clicked. This is designed to facilitate embedding links within a
17206 * drag handle that do something other than start the drag.
17207 * @method addInvalidHandleType
17208 * @param {string} tagName the type of element to exclude
17210 addInvalidHandleType: function(tagName) {
17211 var type = tagName.toUpperCase();
17212 this.invalidHandleTypes[type] = type;
17216 * Lets you to specify an element id for a child of a drag handle
17217 * that should not initiate a drag
17218 * @method addInvalidHandleId
17219 * @param {string} id the element id of the element you wish to ignore
17221 addInvalidHandleId: function(id) {
17222 if (typeof id !== "string") {
17225 this.invalidHandleIds[id] = id;
17229 * Lets you specify a css class of elements that will not initiate a drag
17230 * @method addInvalidHandleClass
17231 * @param {string} cssClass the class of the elements you wish to ignore
17233 addInvalidHandleClass: function(cssClass) {
17234 this.invalidHandleClasses.push(cssClass);
17238 * Unsets an excluded tag name set by addInvalidHandleType
17239 * @method removeInvalidHandleType
17240 * @param {string} tagName the type of element to unexclude
17242 removeInvalidHandleType: function(tagName) {
17243 var type = tagName.toUpperCase();
17244 // this.invalidHandleTypes[type] = null;
17245 delete this.invalidHandleTypes[type];
17249 * Unsets an invalid handle id
17250 * @method removeInvalidHandleId
17251 * @param {string} id the id of the element to re-enable
17253 removeInvalidHandleId: function(id) {
17254 if (typeof id !== "string") {
17257 delete this.invalidHandleIds[id];
17261 * Unsets an invalid css class
17262 * @method removeInvalidHandleClass
17263 * @param {string} cssClass the class of the element(s) you wish to
17266 removeInvalidHandleClass: function(cssClass) {
17267 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17268 if (this.invalidHandleClasses[i] == cssClass) {
17269 delete this.invalidHandleClasses[i];
17275 * Checks the tag exclusion list to see if this click should be ignored
17276 * @method isValidHandleChild
17277 * @param {HTMLElement} node the HTMLElement to evaluate
17278 * @return {boolean} true if this is a valid tag type, false if not
17280 isValidHandleChild: function(node) {
17283 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17286 nodeName = node.nodeName.toUpperCase();
17288 nodeName = node.nodeName;
17290 valid = valid && !this.invalidHandleTypes[nodeName];
17291 valid = valid && !this.invalidHandleIds[node.id];
17293 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17294 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17303 * Create the array of horizontal tick marks if an interval was specified
17304 * in setXConstraint().
17305 * @method setXTicks
17308 setXTicks: function(iStartX, iTickSize) {
17310 this.xTickSize = iTickSize;
17314 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17316 this.xTicks[this.xTicks.length] = i;
17321 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17323 this.xTicks[this.xTicks.length] = i;
17328 this.xTicks.sort(this.DDM.numericSort) ;
17332 * Create the array of vertical tick marks if an interval was specified in
17333 * setYConstraint().
17334 * @method setYTicks
17337 setYTicks: function(iStartY, iTickSize) {
17339 this.yTickSize = iTickSize;
17343 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17345 this.yTicks[this.yTicks.length] = i;
17350 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17352 this.yTicks[this.yTicks.length] = i;
17357 this.yTicks.sort(this.DDM.numericSort) ;
17361 * By default, the element can be dragged any place on the screen. Use
17362 * this method to limit the horizontal travel of the element. Pass in
17363 * 0,0 for the parameters if you want to lock the drag to the y axis.
17364 * @method setXConstraint
17365 * @param {int} iLeft the number of pixels the element can move to the left
17366 * @param {int} iRight the number of pixels the element can move to the
17368 * @param {int} iTickSize optional parameter for specifying that the
17370 * should move iTickSize pixels at a time.
17372 setXConstraint: function(iLeft, iRight, iTickSize) {
17373 this.leftConstraint = iLeft;
17374 this.rightConstraint = iRight;
17376 this.minX = this.initPageX - iLeft;
17377 this.maxX = this.initPageX + iRight;
17378 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17380 this.constrainX = true;
17384 * Clears any constraints applied to this instance. Also clears ticks
17385 * since they can't exist independent of a constraint at this time.
17386 * @method clearConstraints
17388 clearConstraints: function() {
17389 this.constrainX = false;
17390 this.constrainY = false;
17395 * Clears any tick interval defined for this instance
17396 * @method clearTicks
17398 clearTicks: function() {
17399 this.xTicks = null;
17400 this.yTicks = null;
17401 this.xTickSize = 0;
17402 this.yTickSize = 0;
17406 * By default, the element can be dragged any place on the screen. Set
17407 * this to limit the vertical travel of the element. Pass in 0,0 for the
17408 * parameters if you want to lock the drag to the x axis.
17409 * @method setYConstraint
17410 * @param {int} iUp the number of pixels the element can move up
17411 * @param {int} iDown the number of pixels the element can move down
17412 * @param {int} iTickSize optional parameter for specifying that the
17413 * element should move iTickSize pixels at a time.
17415 setYConstraint: function(iUp, iDown, iTickSize) {
17416 this.topConstraint = iUp;
17417 this.bottomConstraint = iDown;
17419 this.minY = this.initPageY - iUp;
17420 this.maxY = this.initPageY + iDown;
17421 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17423 this.constrainY = true;
17428 * resetConstraints must be called if you manually reposition a dd element.
17429 * @method resetConstraints
17430 * @param {boolean} maintainOffset
17432 resetConstraints: function() {
17435 // Maintain offsets if necessary
17436 if (this.initPageX || this.initPageX === 0) {
17437 // figure out how much this thing has moved
17438 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17439 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17441 this.setInitPosition(dx, dy);
17443 // This is the first time we have detected the element's position
17445 this.setInitPosition();
17448 if (this.constrainX) {
17449 this.setXConstraint( this.leftConstraint,
17450 this.rightConstraint,
17454 if (this.constrainY) {
17455 this.setYConstraint( this.topConstraint,
17456 this.bottomConstraint,
17462 * Normally the drag element is moved pixel by pixel, but we can specify
17463 * that it move a number of pixels at a time. This method resolves the
17464 * location when we have it set up like this.
17466 * @param {int} val where we want to place the object
17467 * @param {int[]} tickArray sorted array of valid points
17468 * @return {int} the closest tick
17471 getTick: function(val, tickArray) {
17474 // If tick interval is not defined, it is effectively 1 pixel,
17475 // so we return the value passed to us.
17477 } else if (tickArray[0] >= val) {
17478 // The value is lower than the first tick, so we return the first
17480 return tickArray[0];
17482 for (var i=0, len=tickArray.length; i<len; ++i) {
17484 if (tickArray[next] && tickArray[next] >= val) {
17485 var diff1 = val - tickArray[i];
17486 var diff2 = tickArray[next] - val;
17487 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17491 // The value is larger than the last tick, so we return the last
17493 return tickArray[tickArray.length - 1];
17500 * @return {string} string representation of the dd obj
17502 toString: function() {
17503 return ("DragDrop " + this.id);
17511 * Ext JS Library 1.1.1
17512 * Copyright(c) 2006-2007, Ext JS, LLC.
17514 * Originally Released Under LGPL - original licence link has changed is not relivant.
17517 * <script type="text/javascript">
17522 * The drag and drop utility provides a framework for building drag and drop
17523 * applications. In addition to enabling drag and drop for specific elements,
17524 * the drag and drop elements are tracked by the manager class, and the
17525 * interactions between the various elements are tracked during the drag and
17526 * the implementing code is notified about these important moments.
17529 // Only load the library once. Rewriting the manager class would orphan
17530 // existing drag and drop instances.
17531 if (!Roo.dd.DragDropMgr) {
17534 * @class Roo.dd.DragDropMgr
17535 * DragDropMgr is a singleton that tracks the element interaction for
17536 * all DragDrop items in the window. Generally, you will not call
17537 * this class directly, but it does have helper methods that could
17538 * be useful in your DragDrop implementations.
17541 Roo.dd.DragDropMgr = function() {
17543 var Event = Roo.EventManager;
17548 * Two dimensional Array of registered DragDrop objects. The first
17549 * dimension is the DragDrop item group, the second the DragDrop
17552 * @type {string: string}
17559 * Array of element ids defined as drag handles. Used to determine
17560 * if the element that generated the mousedown event is actually the
17561 * handle and not the html element itself.
17562 * @property handleIds
17563 * @type {string: string}
17570 * the DragDrop object that is currently being dragged
17571 * @property dragCurrent
17579 * the DragDrop object(s) that are being hovered over
17580 * @property dragOvers
17588 * the X distance between the cursor and the object being dragged
17597 * the Y distance between the cursor and the object being dragged
17606 * Flag to determine if we should prevent the default behavior of the
17607 * events we define. By default this is true, but this can be set to
17608 * false if you need the default behavior (not recommended)
17609 * @property preventDefault
17613 preventDefault: true,
17616 * Flag to determine if we should stop the propagation of the events
17617 * we generate. This is true by default but you may want to set it to
17618 * false if the html element contains other features that require the
17620 * @property stopPropagation
17624 stopPropagation: true,
17627 * Internal flag that is set to true when drag and drop has been
17629 * @property initialized
17636 * All drag and drop can be disabled.
17644 * Called the first time an element is registered.
17650 this.initialized = true;
17654 * In point mode, drag and drop interaction is defined by the
17655 * location of the cursor during the drag/drop
17663 * In intersect mode, drag and drop interactio nis defined by the
17664 * overlap of two or more drag and drop objects.
17665 * @property INTERSECT
17672 * The current drag and drop mode. Default: POINT
17680 * Runs method on all drag and drop objects
17681 * @method _execOnAll
17685 _execOnAll: function(sMethod, args) {
17686 for (var i in this.ids) {
17687 for (var j in this.ids[i]) {
17688 var oDD = this.ids[i][j];
17689 if (! this.isTypeOfDD(oDD)) {
17692 oDD[sMethod].apply(oDD, args);
17698 * Drag and drop initialization. Sets up the global event handlers
17703 _onLoad: function() {
17707 if (!Roo.isTouch) {
17708 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17709 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17711 Event.on(document, "touchend", this.handleMouseUp, this, true);
17712 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17714 Event.on(window, "unload", this._onUnload, this, true);
17715 Event.on(window, "resize", this._onResize, this, true);
17716 // Event.on(window, "mouseout", this._test);
17721 * Reset constraints on all drag and drop objs
17722 * @method _onResize
17726 _onResize: function(e) {
17727 this._execOnAll("resetConstraints", []);
17731 * Lock all drag and drop functionality
17735 lock: function() { this.locked = true; },
17738 * Unlock all drag and drop functionality
17742 unlock: function() { this.locked = false; },
17745 * Is drag and drop locked?
17747 * @return {boolean} True if drag and drop is locked, false otherwise.
17750 isLocked: function() { return this.locked; },
17753 * Location cache that is set for all drag drop objects when a drag is
17754 * initiated, cleared when the drag is finished.
17755 * @property locationCache
17762 * Set useCache to false if you want to force object the lookup of each
17763 * drag and drop linked element constantly during a drag.
17764 * @property useCache
17771 * The number of pixels that the mouse needs to move after the
17772 * mousedown before the drag is initiated. Default=3;
17773 * @property clickPixelThresh
17777 clickPixelThresh: 3,
17780 * The number of milliseconds after the mousedown event to initiate the
17781 * drag if we don't get a mouseup event. Default=1000
17782 * @property clickTimeThresh
17786 clickTimeThresh: 350,
17789 * Flag that indicates that either the drag pixel threshold or the
17790 * mousdown time threshold has been met
17791 * @property dragThreshMet
17796 dragThreshMet: false,
17799 * Timeout used for the click time threshold
17800 * @property clickTimeout
17805 clickTimeout: null,
17808 * The X position of the mousedown event stored for later use when a
17809 * drag threshold is met.
17818 * The Y position of the mousedown event stored for later use when a
17819 * drag threshold is met.
17828 * Each DragDrop instance must be registered with the DragDropMgr.
17829 * This is executed in DragDrop.init()
17830 * @method regDragDrop
17831 * @param {DragDrop} oDD the DragDrop object to register
17832 * @param {String} sGroup the name of the group this element belongs to
17835 regDragDrop: function(oDD, sGroup) {
17836 if (!this.initialized) { this.init(); }
17838 if (!this.ids[sGroup]) {
17839 this.ids[sGroup] = {};
17841 this.ids[sGroup][oDD.id] = oDD;
17845 * Removes the supplied dd instance from the supplied group. Executed
17846 * by DragDrop.removeFromGroup, so don't call this function directly.
17847 * @method removeDDFromGroup
17851 removeDDFromGroup: function(oDD, sGroup) {
17852 if (!this.ids[sGroup]) {
17853 this.ids[sGroup] = {};
17856 var obj = this.ids[sGroup];
17857 if (obj && obj[oDD.id]) {
17858 delete obj[oDD.id];
17863 * Unregisters a drag and drop item. This is executed in
17864 * DragDrop.unreg, use that method instead of calling this directly.
17869 _remove: function(oDD) {
17870 for (var g in oDD.groups) {
17871 if (g && this.ids[g][oDD.id]) {
17872 delete this.ids[g][oDD.id];
17875 delete this.handleIds[oDD.id];
17879 * Each DragDrop handle element must be registered. This is done
17880 * automatically when executing DragDrop.setHandleElId()
17881 * @method regHandle
17882 * @param {String} sDDId the DragDrop id this element is a handle for
17883 * @param {String} sHandleId the id of the element that is the drag
17887 regHandle: function(sDDId, sHandleId) {
17888 if (!this.handleIds[sDDId]) {
17889 this.handleIds[sDDId] = {};
17891 this.handleIds[sDDId][sHandleId] = sHandleId;
17895 * Utility function to determine if a given element has been
17896 * registered as a drag drop item.
17897 * @method isDragDrop
17898 * @param {String} id the element id to check
17899 * @return {boolean} true if this element is a DragDrop item,
17903 isDragDrop: function(id) {
17904 return ( this.getDDById(id) ) ? true : false;
17908 * Returns the drag and drop instances that are in all groups the
17909 * passed in instance belongs to.
17910 * @method getRelated
17911 * @param {DragDrop} p_oDD the obj to get related data for
17912 * @param {boolean} bTargetsOnly if true, only return targetable objs
17913 * @return {DragDrop[]} the related instances
17916 getRelated: function(p_oDD, bTargetsOnly) {
17918 for (var i in p_oDD.groups) {
17919 for (j in this.ids[i]) {
17920 var dd = this.ids[i][j];
17921 if (! this.isTypeOfDD(dd)) {
17924 if (!bTargetsOnly || dd.isTarget) {
17925 oDDs[oDDs.length] = dd;
17934 * Returns true if the specified dd target is a legal target for
17935 * the specifice drag obj
17936 * @method isLegalTarget
17937 * @param {DragDrop} the drag obj
17938 * @param {DragDrop} the target
17939 * @return {boolean} true if the target is a legal target for the
17943 isLegalTarget: function (oDD, oTargetDD) {
17944 var targets = this.getRelated(oDD, true);
17945 for (var i=0, len=targets.length;i<len;++i) {
17946 if (targets[i].id == oTargetDD.id) {
17955 * My goal is to be able to transparently determine if an object is
17956 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17957 * returns "object", oDD.constructor.toString() always returns
17958 * "DragDrop" and not the name of the subclass. So for now it just
17959 * evaluates a well-known variable in DragDrop.
17960 * @method isTypeOfDD
17961 * @param {Object} the object to evaluate
17962 * @return {boolean} true if typeof oDD = DragDrop
17965 isTypeOfDD: function (oDD) {
17966 return (oDD && oDD.__ygDragDrop);
17970 * Utility function to determine if a given element has been
17971 * registered as a drag drop handle for the given Drag Drop object.
17973 * @param {String} id the element id to check
17974 * @return {boolean} true if this element is a DragDrop handle, false
17978 isHandle: function(sDDId, sHandleId) {
17979 return ( this.handleIds[sDDId] &&
17980 this.handleIds[sDDId][sHandleId] );
17984 * Returns the DragDrop instance for a given id
17985 * @method getDDById
17986 * @param {String} id the id of the DragDrop object
17987 * @return {DragDrop} the drag drop object, null if it is not found
17990 getDDById: function(id) {
17991 for (var i in this.ids) {
17992 if (this.ids[i][id]) {
17993 return this.ids[i][id];
18000 * Fired after a registered DragDrop object gets the mousedown event.
18001 * Sets up the events required to track the object being dragged
18002 * @method handleMouseDown
18003 * @param {Event} e the event
18004 * @param oDD the DragDrop object being dragged
18008 handleMouseDown: function(e, oDD) {
18010 Roo.QuickTips.disable();
18012 this.currentTarget = e.getTarget();
18014 this.dragCurrent = oDD;
18016 var el = oDD.getEl();
18018 // track start position
18019 this.startX = e.getPageX();
18020 this.startY = e.getPageY();
18022 this.deltaX = this.startX - el.offsetLeft;
18023 this.deltaY = this.startY - el.offsetTop;
18025 this.dragThreshMet = false;
18027 this.clickTimeout = setTimeout(
18029 var DDM = Roo.dd.DDM;
18030 DDM.startDrag(DDM.startX, DDM.startY);
18032 this.clickTimeThresh );
18036 * Fired when either the drag pixel threshol or the mousedown hold
18037 * time threshold has been met.
18038 * @method startDrag
18039 * @param x {int} the X position of the original mousedown
18040 * @param y {int} the Y position of the original mousedown
18043 startDrag: function(x, y) {
18044 clearTimeout(this.clickTimeout);
18045 if (this.dragCurrent) {
18046 this.dragCurrent.b4StartDrag(x, y);
18047 this.dragCurrent.startDrag(x, y);
18049 this.dragThreshMet = true;
18053 * Internal function to handle the mouseup event. Will be invoked
18054 * from the context of the document.
18055 * @method handleMouseUp
18056 * @param {Event} e the event
18060 handleMouseUp: function(e) {
18063 Roo.QuickTips.enable();
18065 if (! this.dragCurrent) {
18069 clearTimeout(this.clickTimeout);
18071 if (this.dragThreshMet) {
18072 this.fireEvents(e, true);
18082 * Utility to stop event propagation and event default, if these
18083 * features are turned on.
18084 * @method stopEvent
18085 * @param {Event} e the event as returned by this.getEvent()
18088 stopEvent: function(e){
18089 if(this.stopPropagation) {
18090 e.stopPropagation();
18093 if (this.preventDefault) {
18094 e.preventDefault();
18099 * Internal function to clean up event handlers after the drag
18100 * operation is complete
18102 * @param {Event} e the event
18106 stopDrag: function(e) {
18107 // Fire the drag end event for the item that was dragged
18108 if (this.dragCurrent) {
18109 if (this.dragThreshMet) {
18110 this.dragCurrent.b4EndDrag(e);
18111 this.dragCurrent.endDrag(e);
18114 this.dragCurrent.onMouseUp(e);
18117 this.dragCurrent = null;
18118 this.dragOvers = {};
18122 * Internal function to handle the mousemove event. Will be invoked
18123 * from the context of the html element.
18125 * @TODO figure out what we can do about mouse events lost when the
18126 * user drags objects beyond the window boundary. Currently we can
18127 * detect this in internet explorer by verifying that the mouse is
18128 * down during the mousemove event. Firefox doesn't give us the
18129 * button state on the mousemove event.
18130 * @method handleMouseMove
18131 * @param {Event} e the event
18135 handleMouseMove: function(e) {
18136 if (! this.dragCurrent) {
18140 // var button = e.which || e.button;
18142 // check for IE mouseup outside of page boundary
18143 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18145 return this.handleMouseUp(e);
18148 if (!this.dragThreshMet) {
18149 var diffX = Math.abs(this.startX - e.getPageX());
18150 var diffY = Math.abs(this.startY - e.getPageY());
18151 if (diffX > this.clickPixelThresh ||
18152 diffY > this.clickPixelThresh) {
18153 this.startDrag(this.startX, this.startY);
18157 if (this.dragThreshMet) {
18158 this.dragCurrent.b4Drag(e);
18159 this.dragCurrent.onDrag(e);
18160 if(!this.dragCurrent.moveOnly){
18161 this.fireEvents(e, false);
18171 * Iterates over all of the DragDrop elements to find ones we are
18172 * hovering over or dropping on
18173 * @method fireEvents
18174 * @param {Event} e the event
18175 * @param {boolean} isDrop is this a drop op or a mouseover op?
18179 fireEvents: function(e, isDrop) {
18180 var dc = this.dragCurrent;
18182 // If the user did the mouse up outside of the window, we could
18183 // get here even though we have ended the drag.
18184 if (!dc || dc.isLocked()) {
18188 var pt = e.getPoint();
18190 // cache the previous dragOver array
18196 var enterEvts = [];
18198 // Check to see if the object(s) we were hovering over is no longer
18199 // being hovered over so we can fire the onDragOut event
18200 for (var i in this.dragOvers) {
18202 var ddo = this.dragOvers[i];
18204 if (! this.isTypeOfDD(ddo)) {
18208 if (! this.isOverTarget(pt, ddo, this.mode)) {
18209 outEvts.push( ddo );
18212 oldOvers[i] = true;
18213 delete this.dragOvers[i];
18216 for (var sGroup in dc.groups) {
18218 if ("string" != typeof sGroup) {
18222 for (i in this.ids[sGroup]) {
18223 var oDD = this.ids[sGroup][i];
18224 if (! this.isTypeOfDD(oDD)) {
18228 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18229 if (this.isOverTarget(pt, oDD, this.mode)) {
18230 // look for drop interactions
18232 dropEvts.push( oDD );
18233 // look for drag enter and drag over interactions
18236 // initial drag over: dragEnter fires
18237 if (!oldOvers[oDD.id]) {
18238 enterEvts.push( oDD );
18239 // subsequent drag overs: dragOver fires
18241 overEvts.push( oDD );
18244 this.dragOvers[oDD.id] = oDD;
18252 if (outEvts.length) {
18253 dc.b4DragOut(e, outEvts);
18254 dc.onDragOut(e, outEvts);
18257 if (enterEvts.length) {
18258 dc.onDragEnter(e, enterEvts);
18261 if (overEvts.length) {
18262 dc.b4DragOver(e, overEvts);
18263 dc.onDragOver(e, overEvts);
18266 if (dropEvts.length) {
18267 dc.b4DragDrop(e, dropEvts);
18268 dc.onDragDrop(e, dropEvts);
18272 // fire dragout events
18274 for (i=0, len=outEvts.length; i<len; ++i) {
18275 dc.b4DragOut(e, outEvts[i].id);
18276 dc.onDragOut(e, outEvts[i].id);
18279 // fire enter events
18280 for (i=0,len=enterEvts.length; i<len; ++i) {
18281 // dc.b4DragEnter(e, oDD.id);
18282 dc.onDragEnter(e, enterEvts[i].id);
18285 // fire over events
18286 for (i=0,len=overEvts.length; i<len; ++i) {
18287 dc.b4DragOver(e, overEvts[i].id);
18288 dc.onDragOver(e, overEvts[i].id);
18291 // fire drop events
18292 for (i=0, len=dropEvts.length; i<len; ++i) {
18293 dc.b4DragDrop(e, dropEvts[i].id);
18294 dc.onDragDrop(e, dropEvts[i].id);
18299 // notify about a drop that did not find a target
18300 if (isDrop && !dropEvts.length) {
18301 dc.onInvalidDrop(e);
18307 * Helper function for getting the best match from the list of drag
18308 * and drop objects returned by the drag and drop events when we are
18309 * in INTERSECT mode. It returns either the first object that the
18310 * cursor is over, or the object that has the greatest overlap with
18311 * the dragged element.
18312 * @method getBestMatch
18313 * @param {DragDrop[]} dds The array of drag and drop objects
18315 * @return {DragDrop} The best single match
18318 getBestMatch: function(dds) {
18320 // Return null if the input is not what we expect
18321 //if (!dds || !dds.length || dds.length == 0) {
18323 // If there is only one item, it wins
18324 //} else if (dds.length == 1) {
18326 var len = dds.length;
18331 // Loop through the targeted items
18332 for (var i=0; i<len; ++i) {
18334 // If the cursor is over the object, it wins. If the
18335 // cursor is over multiple matches, the first one we come
18337 if (dd.cursorIsOver) {
18340 // Otherwise the object with the most overlap wins
18343 winner.overlap.getArea() < dd.overlap.getArea()) {
18354 * Refreshes the cache of the top-left and bottom-right points of the
18355 * drag and drop objects in the specified group(s). This is in the
18356 * format that is stored in the drag and drop instance, so typical
18359 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18363 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18365 * @TODO this really should be an indexed array. Alternatively this
18366 * method could accept both.
18367 * @method refreshCache
18368 * @param {Object} groups an associative array of groups to refresh
18371 refreshCache: function(groups) {
18372 for (var sGroup in groups) {
18373 if ("string" != typeof sGroup) {
18376 for (var i in this.ids[sGroup]) {
18377 var oDD = this.ids[sGroup][i];
18379 if (this.isTypeOfDD(oDD)) {
18380 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18381 var loc = this.getLocation(oDD);
18383 this.locationCache[oDD.id] = loc;
18385 delete this.locationCache[oDD.id];
18386 // this will unregister the drag and drop object if
18387 // the element is not in a usable state
18396 * This checks to make sure an element exists and is in the DOM. The
18397 * main purpose is to handle cases where innerHTML is used to remove
18398 * drag and drop objects from the DOM. IE provides an 'unspecified
18399 * error' when trying to access the offsetParent of such an element
18401 * @param {HTMLElement} el the element to check
18402 * @return {boolean} true if the element looks usable
18405 verifyEl: function(el) {
18410 parent = el.offsetParent;
18413 parent = el.offsetParent;
18424 * Returns a Region object containing the drag and drop element's position
18425 * and size, including the padding configured for it
18426 * @method getLocation
18427 * @param {DragDrop} oDD the drag and drop object to get the
18429 * @return {Roo.lib.Region} a Region object representing the total area
18430 * the element occupies, including any padding
18431 * the instance is configured for.
18434 getLocation: function(oDD) {
18435 if (! this.isTypeOfDD(oDD)) {
18439 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18442 pos= Roo.lib.Dom.getXY(el);
18450 x2 = x1 + el.offsetWidth;
18452 y2 = y1 + el.offsetHeight;
18454 t = y1 - oDD.padding[0];
18455 r = x2 + oDD.padding[1];
18456 b = y2 + oDD.padding[2];
18457 l = x1 - oDD.padding[3];
18459 return new Roo.lib.Region( t, r, b, l );
18463 * Checks the cursor location to see if it over the target
18464 * @method isOverTarget
18465 * @param {Roo.lib.Point} pt The point to evaluate
18466 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18467 * @return {boolean} true if the mouse is over the target
18471 isOverTarget: function(pt, oTarget, intersect) {
18472 // use cache if available
18473 var loc = this.locationCache[oTarget.id];
18474 if (!loc || !this.useCache) {
18475 loc = this.getLocation(oTarget);
18476 this.locationCache[oTarget.id] = loc;
18484 oTarget.cursorIsOver = loc.contains( pt );
18486 // DragDrop is using this as a sanity check for the initial mousedown
18487 // in this case we are done. In POINT mode, if the drag obj has no
18488 // contraints, we are also done. Otherwise we need to evaluate the
18489 // location of the target as related to the actual location of the
18490 // dragged element.
18491 var dc = this.dragCurrent;
18492 if (!dc || !dc.getTargetCoord ||
18493 (!intersect && !dc.constrainX && !dc.constrainY)) {
18494 return oTarget.cursorIsOver;
18497 oTarget.overlap = null;
18499 // Get the current location of the drag element, this is the
18500 // location of the mouse event less the delta that represents
18501 // where the original mousedown happened on the element. We
18502 // need to consider constraints and ticks as well.
18503 var pos = dc.getTargetCoord(pt.x, pt.y);
18505 var el = dc.getDragEl();
18506 var curRegion = new Roo.lib.Region( pos.y,
18507 pos.x + el.offsetWidth,
18508 pos.y + el.offsetHeight,
18511 var overlap = curRegion.intersect(loc);
18514 oTarget.overlap = overlap;
18515 return (intersect) ? true : oTarget.cursorIsOver;
18522 * unload event handler
18523 * @method _onUnload
18527 _onUnload: function(e, me) {
18528 Roo.dd.DragDropMgr.unregAll();
18532 * Cleans up the drag and drop events and objects.
18537 unregAll: function() {
18539 if (this.dragCurrent) {
18541 this.dragCurrent = null;
18544 this._execOnAll("unreg", []);
18546 for (i in this.elementCache) {
18547 delete this.elementCache[i];
18550 this.elementCache = {};
18555 * A cache of DOM elements
18556 * @property elementCache
18563 * Get the wrapper for the DOM element specified
18564 * @method getElWrapper
18565 * @param {String} id the id of the element to get
18566 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18568 * @deprecated This wrapper isn't that useful
18571 getElWrapper: function(id) {
18572 var oWrapper = this.elementCache[id];
18573 if (!oWrapper || !oWrapper.el) {
18574 oWrapper = this.elementCache[id] =
18575 new this.ElementWrapper(Roo.getDom(id));
18581 * Returns the actual DOM element
18582 * @method getElement
18583 * @param {String} id the id of the elment to get
18584 * @return {Object} The element
18585 * @deprecated use Roo.getDom instead
18588 getElement: function(id) {
18589 return Roo.getDom(id);
18593 * Returns the style property for the DOM element (i.e.,
18594 * document.getElById(id).style)
18596 * @param {String} id the id of the elment to get
18597 * @return {Object} The style property of the element
18598 * @deprecated use Roo.getDom instead
18601 getCss: function(id) {
18602 var el = Roo.getDom(id);
18603 return (el) ? el.style : null;
18607 * Inner class for cached elements
18608 * @class DragDropMgr.ElementWrapper
18613 ElementWrapper: function(el) {
18618 this.el = el || null;
18623 this.id = this.el && el.id;
18625 * A reference to the style property
18628 this.css = this.el && el.style;
18632 * Returns the X position of an html element
18634 * @param el the element for which to get the position
18635 * @return {int} the X coordinate
18637 * @deprecated use Roo.lib.Dom.getX instead
18640 getPosX: function(el) {
18641 return Roo.lib.Dom.getX(el);
18645 * Returns the Y position of an html element
18647 * @param el the element for which to get the position
18648 * @return {int} the Y coordinate
18649 * @deprecated use Roo.lib.Dom.getY instead
18652 getPosY: function(el) {
18653 return Roo.lib.Dom.getY(el);
18657 * Swap two nodes. In IE, we use the native method, for others we
18658 * emulate the IE behavior
18660 * @param n1 the first node to swap
18661 * @param n2 the other node to swap
18664 swapNode: function(n1, n2) {
18668 var p = n2.parentNode;
18669 var s = n2.nextSibling;
18672 p.insertBefore(n1, n2);
18673 } else if (n2 == n1.nextSibling) {
18674 p.insertBefore(n2, n1);
18676 n1.parentNode.replaceChild(n2, n1);
18677 p.insertBefore(n1, s);
18683 * Returns the current scroll position
18684 * @method getScroll
18688 getScroll: function () {
18689 var t, l, dde=document.documentElement, db=document.body;
18690 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18692 l = dde.scrollLeft;
18699 return { top: t, left: l };
18703 * Returns the specified element style property
18705 * @param {HTMLElement} el the element
18706 * @param {string} styleProp the style property
18707 * @return {string} The value of the style property
18708 * @deprecated use Roo.lib.Dom.getStyle
18711 getStyle: function(el, styleProp) {
18712 return Roo.fly(el).getStyle(styleProp);
18716 * Gets the scrollTop
18717 * @method getScrollTop
18718 * @return {int} the document's scrollTop
18721 getScrollTop: function () { return this.getScroll().top; },
18724 * Gets the scrollLeft
18725 * @method getScrollLeft
18726 * @return {int} the document's scrollTop
18729 getScrollLeft: function () { return this.getScroll().left; },
18732 * Sets the x/y position of an element to the location of the
18735 * @param {HTMLElement} moveEl The element to move
18736 * @param {HTMLElement} targetEl The position reference element
18739 moveToEl: function (moveEl, targetEl) {
18740 var aCoord = Roo.lib.Dom.getXY(targetEl);
18741 Roo.lib.Dom.setXY(moveEl, aCoord);
18745 * Numeric array sort function
18746 * @method numericSort
18749 numericSort: function(a, b) { return (a - b); },
18753 * @property _timeoutCount
18760 * Trying to make the load order less important. Without this we get
18761 * an error if this file is loaded before the Event Utility.
18762 * @method _addListeners
18766 _addListeners: function() {
18767 var DDM = Roo.dd.DDM;
18768 if ( Roo.lib.Event && document ) {
18771 if (DDM._timeoutCount > 2000) {
18773 setTimeout(DDM._addListeners, 10);
18774 if (document && document.body) {
18775 DDM._timeoutCount += 1;
18782 * Recursively searches the immediate parent and all child nodes for
18783 * the handle element in order to determine wheter or not it was
18785 * @method handleWasClicked
18786 * @param node the html element to inspect
18789 handleWasClicked: function(node, id) {
18790 if (this.isHandle(id, node.id)) {
18793 // check to see if this is a text node child of the one we want
18794 var p = node.parentNode;
18797 if (this.isHandle(id, p.id)) {
18812 // shorter alias, save a few bytes
18813 Roo.dd.DDM = Roo.dd.DragDropMgr;
18814 Roo.dd.DDM._addListeners();
18818 * Ext JS Library 1.1.1
18819 * Copyright(c) 2006-2007, Ext JS, LLC.
18821 * Originally Released Under LGPL - original licence link has changed is not relivant.
18824 * <script type="text/javascript">
18829 * A DragDrop implementation where the linked element follows the
18830 * mouse cursor during a drag.
18831 * @extends Roo.dd.DragDrop
18833 * @param {String} id the id of the linked element
18834 * @param {String} sGroup the group of related DragDrop items
18835 * @param {object} config an object containing configurable attributes
18836 * Valid properties for DD:
18839 Roo.dd.DD = function(id, sGroup, config) {
18841 this.init(id, sGroup, config);
18845 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18848 * When set to true, the utility automatically tries to scroll the browser
18849 * window wehn a drag and drop element is dragged near the viewport boundary.
18850 * Defaults to true.
18857 * Sets the pointer offset to the distance between the linked element's top
18858 * left corner and the location the element was clicked
18859 * @method autoOffset
18860 * @param {int} iPageX the X coordinate of the click
18861 * @param {int} iPageY the Y coordinate of the click
18863 autoOffset: function(iPageX, iPageY) {
18864 var x = iPageX - this.startPageX;
18865 var y = iPageY - this.startPageY;
18866 this.setDelta(x, y);
18870 * Sets the pointer offset. You can call this directly to force the
18871 * offset to be in a particular location (e.g., pass in 0,0 to set it
18872 * to the center of the object)
18874 * @param {int} iDeltaX the distance from the left
18875 * @param {int} iDeltaY the distance from the top
18877 setDelta: function(iDeltaX, iDeltaY) {
18878 this.deltaX = iDeltaX;
18879 this.deltaY = iDeltaY;
18883 * Sets the drag element to the location of the mousedown or click event,
18884 * maintaining the cursor location relative to the location on the element
18885 * that was clicked. Override this if you want to place the element in a
18886 * location other than where the cursor is.
18887 * @method setDragElPos
18888 * @param {int} iPageX the X coordinate of the mousedown or drag event
18889 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18891 setDragElPos: function(iPageX, iPageY) {
18892 // the first time we do this, we are going to check to make sure
18893 // the element has css positioning
18895 var el = this.getDragEl();
18896 this.alignElWithMouse(el, iPageX, iPageY);
18900 * Sets the element to the location of the mousedown or click event,
18901 * maintaining the cursor location relative to the location on the element
18902 * that was clicked. Override this if you want to place the element in a
18903 * location other than where the cursor is.
18904 * @method alignElWithMouse
18905 * @param {HTMLElement} el the element to move
18906 * @param {int} iPageX the X coordinate of the mousedown or drag event
18907 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18909 alignElWithMouse: function(el, iPageX, iPageY) {
18910 var oCoord = this.getTargetCoord(iPageX, iPageY);
18911 var fly = el.dom ? el : Roo.fly(el);
18912 if (!this.deltaSetXY) {
18913 var aCoord = [oCoord.x, oCoord.y];
18915 var newLeft = fly.getLeft(true);
18916 var newTop = fly.getTop(true);
18917 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18919 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18922 this.cachePosition(oCoord.x, oCoord.y);
18923 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18928 * Saves the most recent position so that we can reset the constraints and
18929 * tick marks on-demand. We need to know this so that we can calculate the
18930 * number of pixels the element is offset from its original position.
18931 * @method cachePosition
18932 * @param iPageX the current x position (optional, this just makes it so we
18933 * don't have to look it up again)
18934 * @param iPageY the current y position (optional, this just makes it so we
18935 * don't have to look it up again)
18937 cachePosition: function(iPageX, iPageY) {
18939 this.lastPageX = iPageX;
18940 this.lastPageY = iPageY;
18942 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18943 this.lastPageX = aCoord[0];
18944 this.lastPageY = aCoord[1];
18949 * Auto-scroll the window if the dragged object has been moved beyond the
18950 * visible window boundary.
18951 * @method autoScroll
18952 * @param {int} x the drag element's x position
18953 * @param {int} y the drag element's y position
18954 * @param {int} h the height of the drag element
18955 * @param {int} w the width of the drag element
18958 autoScroll: function(x, y, h, w) {
18961 // The client height
18962 var clientH = Roo.lib.Dom.getViewWidth();
18964 // The client width
18965 var clientW = Roo.lib.Dom.getViewHeight();
18967 // The amt scrolled down
18968 var st = this.DDM.getScrollTop();
18970 // The amt scrolled right
18971 var sl = this.DDM.getScrollLeft();
18973 // Location of the bottom of the element
18976 // Location of the right of the element
18979 // The distance from the cursor to the bottom of the visible area,
18980 // adjusted so that we don't scroll if the cursor is beyond the
18981 // element drag constraints
18982 var toBot = (clientH + st - y - this.deltaY);
18984 // The distance from the cursor to the right of the visible area
18985 var toRight = (clientW + sl - x - this.deltaX);
18988 // How close to the edge the cursor must be before we scroll
18989 // var thresh = (document.all) ? 100 : 40;
18992 // How many pixels to scroll per autoscroll op. This helps to reduce
18993 // clunky scrolling. IE is more sensitive about this ... it needs this
18994 // value to be higher.
18995 var scrAmt = (document.all) ? 80 : 30;
18997 // Scroll down if we are near the bottom of the visible page and the
18998 // obj extends below the crease
18999 if ( bot > clientH && toBot < thresh ) {
19000 window.scrollTo(sl, st + scrAmt);
19003 // Scroll up if the window is scrolled down and the top of the object
19004 // goes above the top border
19005 if ( y < st && st > 0 && y - st < thresh ) {
19006 window.scrollTo(sl, st - scrAmt);
19009 // Scroll right if the obj is beyond the right border and the cursor is
19010 // near the border.
19011 if ( right > clientW && toRight < thresh ) {
19012 window.scrollTo(sl + scrAmt, st);
19015 // Scroll left if the window has been scrolled to the right and the obj
19016 // extends past the left border
19017 if ( x < sl && sl > 0 && x - sl < thresh ) {
19018 window.scrollTo(sl - scrAmt, st);
19024 * Finds the location the element should be placed if we want to move
19025 * it to where the mouse location less the click offset would place us.
19026 * @method getTargetCoord
19027 * @param {int} iPageX the X coordinate of the click
19028 * @param {int} iPageY the Y coordinate of the click
19029 * @return an object that contains the coordinates (Object.x and Object.y)
19032 getTargetCoord: function(iPageX, iPageY) {
19035 var x = iPageX - this.deltaX;
19036 var y = iPageY - this.deltaY;
19038 if (this.constrainX) {
19039 if (x < this.minX) { x = this.minX; }
19040 if (x > this.maxX) { x = this.maxX; }
19043 if (this.constrainY) {
19044 if (y < this.minY) { y = this.minY; }
19045 if (y > this.maxY) { y = this.maxY; }
19048 x = this.getTick(x, this.xTicks);
19049 y = this.getTick(y, this.yTicks);
19056 * Sets up config options specific to this class. Overrides
19057 * Roo.dd.DragDrop, but all versions of this method through the
19058 * inheritance chain are called
19060 applyConfig: function() {
19061 Roo.dd.DD.superclass.applyConfig.call(this);
19062 this.scroll = (this.config.scroll !== false);
19066 * Event that fires prior to the onMouseDown event. Overrides
19069 b4MouseDown: function(e) {
19070 // this.resetConstraints();
19071 this.autoOffset(e.getPageX(),
19076 * Event that fires prior to the onDrag event. Overrides
19079 b4Drag: function(e) {
19080 this.setDragElPos(e.getPageX(),
19084 toString: function() {
19085 return ("DD " + this.id);
19088 //////////////////////////////////////////////////////////////////////////
19089 // Debugging ygDragDrop events that can be overridden
19090 //////////////////////////////////////////////////////////////////////////
19092 startDrag: function(x, y) {
19095 onDrag: function(e) {
19098 onDragEnter: function(e, id) {
19101 onDragOver: function(e, id) {
19104 onDragOut: function(e, id) {
19107 onDragDrop: function(e, id) {
19110 endDrag: function(e) {
19117 * Ext JS Library 1.1.1
19118 * Copyright(c) 2006-2007, Ext JS, LLC.
19120 * Originally Released Under LGPL - original licence link has changed is not relivant.
19123 * <script type="text/javascript">
19127 * @class Roo.dd.DDProxy
19128 * A DragDrop implementation that inserts an empty, bordered div into
19129 * the document that follows the cursor during drag operations. At the time of
19130 * the click, the frame div is resized to the dimensions of the linked html
19131 * element, and moved to the exact location of the linked element.
19133 * References to the "frame" element refer to the single proxy element that
19134 * was created to be dragged in place of all DDProxy elements on the
19137 * @extends Roo.dd.DD
19139 * @param {String} id the id of the linked html element
19140 * @param {String} sGroup the group of related DragDrop objects
19141 * @param {object} config an object containing configurable attributes
19142 * Valid properties for DDProxy in addition to those in DragDrop:
19143 * resizeFrame, centerFrame, dragElId
19145 Roo.dd.DDProxy = function(id, sGroup, config) {
19147 this.init(id, sGroup, config);
19153 * The default drag frame div id
19154 * @property Roo.dd.DDProxy.dragElId
19158 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19160 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19163 * By default we resize the drag frame to be the same size as the element
19164 * we want to drag (this is to get the frame effect). We can turn it off
19165 * if we want a different behavior.
19166 * @property resizeFrame
19172 * By default the frame is positioned exactly where the drag element is, so
19173 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19174 * you do not have constraints on the obj is to have the drag frame centered
19175 * around the cursor. Set centerFrame to true for this effect.
19176 * @property centerFrame
19179 centerFrame: false,
19182 * Creates the proxy element if it does not yet exist
19183 * @method createFrame
19185 createFrame: function() {
19187 var body = document.body;
19189 if (!body || !body.firstChild) {
19190 setTimeout( function() { self.createFrame(); }, 50 );
19194 var div = this.getDragEl();
19197 div = document.createElement("div");
19198 div.id = this.dragElId;
19201 s.position = "absolute";
19202 s.visibility = "hidden";
19204 s.border = "2px solid #aaa";
19207 // appendChild can blow up IE if invoked prior to the window load event
19208 // while rendering a table. It is possible there are other scenarios
19209 // that would cause this to happen as well.
19210 body.insertBefore(div, body.firstChild);
19215 * Initialization for the drag frame element. Must be called in the
19216 * constructor of all subclasses
19217 * @method initFrame
19219 initFrame: function() {
19220 this.createFrame();
19223 applyConfig: function() {
19224 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19226 this.resizeFrame = (this.config.resizeFrame !== false);
19227 this.centerFrame = (this.config.centerFrame);
19228 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19232 * Resizes the drag frame to the dimensions of the clicked object, positions
19233 * it over the object, and finally displays it
19234 * @method showFrame
19235 * @param {int} iPageX X click position
19236 * @param {int} iPageY Y click position
19239 showFrame: function(iPageX, iPageY) {
19240 var el = this.getEl();
19241 var dragEl = this.getDragEl();
19242 var s = dragEl.style;
19244 this._resizeProxy();
19246 if (this.centerFrame) {
19247 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19248 Math.round(parseInt(s.height, 10)/2) );
19251 this.setDragElPos(iPageX, iPageY);
19253 Roo.fly(dragEl).show();
19257 * The proxy is automatically resized to the dimensions of the linked
19258 * element when a drag is initiated, unless resizeFrame is set to false
19259 * @method _resizeProxy
19262 _resizeProxy: function() {
19263 if (this.resizeFrame) {
19264 var el = this.getEl();
19265 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19269 // overrides Roo.dd.DragDrop
19270 b4MouseDown: function(e) {
19271 var x = e.getPageX();
19272 var y = e.getPageY();
19273 this.autoOffset(x, y);
19274 this.setDragElPos(x, y);
19277 // overrides Roo.dd.DragDrop
19278 b4StartDrag: function(x, y) {
19279 // show the drag frame
19280 this.showFrame(x, y);
19283 // overrides Roo.dd.DragDrop
19284 b4EndDrag: function(e) {
19285 Roo.fly(this.getDragEl()).hide();
19288 // overrides Roo.dd.DragDrop
19289 // By default we try to move the element to the last location of the frame.
19290 // This is so that the default behavior mirrors that of Roo.dd.DD.
19291 endDrag: function(e) {
19293 var lel = this.getEl();
19294 var del = this.getDragEl();
19296 // Show the drag frame briefly so we can get its position
19297 del.style.visibility = "";
19300 // Hide the linked element before the move to get around a Safari
19302 lel.style.visibility = "hidden";
19303 Roo.dd.DDM.moveToEl(lel, del);
19304 del.style.visibility = "hidden";
19305 lel.style.visibility = "";
19310 beforeMove : function(){
19314 afterDrag : function(){
19318 toString: function() {
19319 return ("DDProxy " + this.id);
19325 * Ext JS Library 1.1.1
19326 * Copyright(c) 2006-2007, Ext JS, LLC.
19328 * Originally Released Under LGPL - original licence link has changed is not relivant.
19331 * <script type="text/javascript">
19335 * @class Roo.dd.DDTarget
19336 * A DragDrop implementation that does not move, but can be a drop
19337 * target. You would get the same result by simply omitting implementation
19338 * for the event callbacks, but this way we reduce the processing cost of the
19339 * event listener and the callbacks.
19340 * @extends Roo.dd.DragDrop
19342 * @param {String} id the id of the element that is a drop target
19343 * @param {String} sGroup the group of related DragDrop objects
19344 * @param {object} config an object containing configurable attributes
19345 * Valid properties for DDTarget in addition to those in
19349 Roo.dd.DDTarget = function(id, sGroup, config) {
19351 this.initTarget(id, sGroup, config);
19353 if (config.listeners || config.events) {
19354 Roo.dd.DragDrop.superclass.constructor.call(this, {
19355 listeners : config.listeners || {},
19356 events : config.events || {}
19361 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19362 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19363 toString: function() {
19364 return ("DDTarget " + this.id);
19369 * Ext JS Library 1.1.1
19370 * Copyright(c) 2006-2007, Ext JS, LLC.
19372 * Originally Released Under LGPL - original licence link has changed is not relivant.
19375 * <script type="text/javascript">
19380 * @class Roo.dd.ScrollManager
19381 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19382 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19385 Roo.dd.ScrollManager = function(){
19386 var ddm = Roo.dd.DragDropMgr;
19393 var onStop = function(e){
19398 var triggerRefresh = function(){
19399 if(ddm.dragCurrent){
19400 ddm.refreshCache(ddm.dragCurrent.groups);
19404 var doScroll = function(){
19405 if(ddm.dragCurrent){
19406 var dds = Roo.dd.ScrollManager;
19408 if(proc.el.scroll(proc.dir, dds.increment)){
19412 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19417 var clearProc = function(){
19419 clearInterval(proc.id);
19426 var startProc = function(el, dir){
19427 Roo.log('scroll startproc');
19431 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19434 var onFire = function(e, isDrop){
19436 if(isDrop || !ddm.dragCurrent){ return; }
19437 var dds = Roo.dd.ScrollManager;
19438 if(!dragEl || dragEl != ddm.dragCurrent){
19439 dragEl = ddm.dragCurrent;
19440 // refresh regions on drag start
19441 dds.refreshCache();
19444 var xy = Roo.lib.Event.getXY(e);
19445 var pt = new Roo.lib.Point(xy[0], xy[1]);
19446 for(var id in els){
19447 var el = els[id], r = el._region;
19448 if(r && r.contains(pt) && el.isScrollable()){
19449 if(r.bottom - pt.y <= dds.thresh){
19451 startProc(el, "down");
19454 }else if(r.right - pt.x <= dds.thresh){
19456 startProc(el, "left");
19459 }else if(pt.y - r.top <= dds.thresh){
19461 startProc(el, "up");
19464 }else if(pt.x - r.left <= dds.thresh){
19466 startProc(el, "right");
19475 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19476 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19480 * Registers new overflow element(s) to auto scroll
19481 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19483 register : function(el){
19484 if(el instanceof Array){
19485 for(var i = 0, len = el.length; i < len; i++) {
19486 this.register(el[i]);
19492 Roo.dd.ScrollManager.els = els;
19496 * Unregisters overflow element(s) so they are no longer scrolled
19497 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19499 unregister : function(el){
19500 if(el instanceof Array){
19501 for(var i = 0, len = el.length; i < len; i++) {
19502 this.unregister(el[i]);
19511 * The number of pixels from the edge of a container the pointer needs to be to
19512 * trigger scrolling (defaults to 25)
19518 * The number of pixels to scroll in each scroll increment (defaults to 50)
19524 * The frequency of scrolls in milliseconds (defaults to 500)
19530 * True to animate the scroll (defaults to true)
19536 * The animation duration in seconds -
19537 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19543 * Manually trigger a cache refresh.
19545 refreshCache : function(){
19546 for(var id in els){
19547 if(typeof els[id] == 'object'){ // for people extending the object prototype
19548 els[id]._region = els[id].getRegion();
19555 * Ext JS Library 1.1.1
19556 * Copyright(c) 2006-2007, Ext JS, LLC.
19558 * Originally Released Under LGPL - original licence link has changed is not relivant.
19561 * <script type="text/javascript">
19566 * @class Roo.dd.Registry
19567 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19568 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19571 Roo.dd.Registry = function(){
19574 var autoIdSeed = 0;
19576 var getId = function(el, autogen){
19577 if(typeof el == "string"){
19581 if(!id && autogen !== false){
19582 id = "roodd-" + (++autoIdSeed);
19590 * Register a drag drop element
19591 * @param {String|HTMLElement} element The id or DOM node to register
19592 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19593 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19594 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19595 * populated in the data object (if applicable):
19597 Value Description<br />
19598 --------- ------------------------------------------<br />
19599 handles Array of DOM nodes that trigger dragging<br />
19600 for the element being registered<br />
19601 isHandle True if the element passed in triggers<br />
19602 dragging itself, else false
19605 register : function(el, data){
19607 if(typeof el == "string"){
19608 el = document.getElementById(el);
19611 elements[getId(el)] = data;
19612 if(data.isHandle !== false){
19613 handles[data.ddel.id] = data;
19616 var hs = data.handles;
19617 for(var i = 0, len = hs.length; i < len; i++){
19618 handles[getId(hs[i])] = data;
19624 * Unregister a drag drop element
19625 * @param {String|HTMLElement} element The id or DOM node to unregister
19627 unregister : function(el){
19628 var id = getId(el, false);
19629 var data = elements[id];
19631 delete elements[id];
19633 var hs = data.handles;
19634 for(var i = 0, len = hs.length; i < len; i++){
19635 delete handles[getId(hs[i], false)];
19642 * Returns the handle registered for a DOM Node by id
19643 * @param {String|HTMLElement} id The DOM node or id to look up
19644 * @return {Object} handle The custom handle data
19646 getHandle : function(id){
19647 if(typeof id != "string"){ // must be element?
19650 return handles[id];
19654 * Returns the handle that is registered for the DOM node that is the target of the event
19655 * @param {Event} e The event
19656 * @return {Object} handle The custom handle data
19658 getHandleFromEvent : function(e){
19659 var t = Roo.lib.Event.getTarget(e);
19660 return t ? handles[t.id] : null;
19664 * Returns a custom data object that is registered for a DOM node by id
19665 * @param {String|HTMLElement} id The DOM node or id to look up
19666 * @return {Object} data The custom data
19668 getTarget : function(id){
19669 if(typeof id != "string"){ // must be element?
19672 return elements[id];
19676 * Returns a custom data object that is registered for the DOM node that is the target of the event
19677 * @param {Event} e The event
19678 * @return {Object} data The custom data
19680 getTargetFromEvent : function(e){
19681 var t = Roo.lib.Event.getTarget(e);
19682 return t ? elements[t.id] || handles[t.id] : null;
19687 * Ext JS Library 1.1.1
19688 * Copyright(c) 2006-2007, Ext JS, LLC.
19690 * Originally Released Under LGPL - original licence link has changed is not relivant.
19693 * <script type="text/javascript">
19698 * @class Roo.dd.StatusProxy
19699 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19700 * default drag proxy used by all Roo.dd components.
19702 * @param {Object} config
19704 Roo.dd.StatusProxy = function(config){
19705 Roo.apply(this, config);
19706 this.id = this.id || Roo.id();
19707 this.el = new Roo.Layer({
19709 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19710 {tag: "div", cls: "x-dd-drop-icon"},
19711 {tag: "div", cls: "x-dd-drag-ghost"}
19714 shadow: !config || config.shadow !== false
19716 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19717 this.dropStatus = this.dropNotAllowed;
19720 Roo.dd.StatusProxy.prototype = {
19722 * @cfg {String} dropAllowed
19723 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19725 dropAllowed : "x-dd-drop-ok",
19727 * @cfg {String} dropNotAllowed
19728 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19730 dropNotAllowed : "x-dd-drop-nodrop",
19733 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19734 * over the current target element.
19735 * @param {String} cssClass The css class for the new drop status indicator image
19737 setStatus : function(cssClass){
19738 cssClass = cssClass || this.dropNotAllowed;
19739 if(this.dropStatus != cssClass){
19740 this.el.replaceClass(this.dropStatus, cssClass);
19741 this.dropStatus = cssClass;
19746 * Resets the status indicator to the default dropNotAllowed value
19747 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19749 reset : function(clearGhost){
19750 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19751 this.dropStatus = this.dropNotAllowed;
19753 this.ghost.update("");
19758 * Updates the contents of the ghost element
19759 * @param {String} html The html that will replace the current innerHTML of the ghost element
19761 update : function(html){
19762 if(typeof html == "string"){
19763 this.ghost.update(html);
19765 this.ghost.update("");
19766 html.style.margin = "0";
19767 this.ghost.dom.appendChild(html);
19769 // ensure float = none set?? cant remember why though.
19770 var el = this.ghost.dom.firstChild;
19772 Roo.fly(el).setStyle('float', 'none');
19777 * Returns the underlying proxy {@link Roo.Layer}
19778 * @return {Roo.Layer} el
19780 getEl : function(){
19785 * Returns the ghost element
19786 * @return {Roo.Element} el
19788 getGhost : function(){
19794 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19796 hide : function(clear){
19804 * Stops the repair animation if it's currently running
19807 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19813 * Displays this proxy
19820 * Force the Layer to sync its shadow and shim positions to the element
19827 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19828 * invalid drop operation by the item being dragged.
19829 * @param {Array} xy The XY position of the element ([x, y])
19830 * @param {Function} callback The function to call after the repair is complete
19831 * @param {Object} scope The scope in which to execute the callback
19833 repair : function(xy, callback, scope){
19834 this.callback = callback;
19835 this.scope = scope;
19836 if(xy && this.animRepair !== false){
19837 this.el.addClass("x-dd-drag-repair");
19838 this.el.hideUnders(true);
19839 this.anim = this.el.shift({
19840 duration: this.repairDuration || .5,
19844 callback: this.afterRepair,
19848 this.afterRepair();
19853 afterRepair : function(){
19855 if(typeof this.callback == "function"){
19856 this.callback.call(this.scope || this);
19858 this.callback = null;
19863 * Ext JS Library 1.1.1
19864 * Copyright(c) 2006-2007, Ext JS, LLC.
19866 * Originally Released Under LGPL - original licence link has changed is not relivant.
19869 * <script type="text/javascript">
19873 * @class Roo.dd.DragSource
19874 * @extends Roo.dd.DDProxy
19875 * A simple class that provides the basic implementation needed to make any element draggable.
19877 * @param {String/HTMLElement/Element} el The container element
19878 * @param {Object} config
19880 Roo.dd.DragSource = function(el, config){
19881 this.el = Roo.get(el);
19882 this.dragData = {};
19884 Roo.apply(this, config);
19887 this.proxy = new Roo.dd.StatusProxy();
19890 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19891 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19893 this.dragging = false;
19896 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19898 * @cfg {String} dropAllowed
19899 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19901 dropAllowed : "x-dd-drop-ok",
19903 * @cfg {String} dropNotAllowed
19904 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19906 dropNotAllowed : "x-dd-drop-nodrop",
19909 * Returns the data object associated with this drag source
19910 * @return {Object} data An object containing arbitrary data
19912 getDragData : function(e){
19913 return this.dragData;
19917 onDragEnter : function(e, id){
19918 var target = Roo.dd.DragDropMgr.getDDById(id);
19919 this.cachedTarget = target;
19920 if(this.beforeDragEnter(target, e, id) !== false){
19921 if(target.isNotifyTarget){
19922 var status = target.notifyEnter(this, e, this.dragData);
19923 this.proxy.setStatus(status);
19925 this.proxy.setStatus(this.dropAllowed);
19928 if(this.afterDragEnter){
19930 * An empty function by default, but provided so that you can perform a custom action
19931 * when the dragged item enters the drop target by providing an implementation.
19932 * @param {Roo.dd.DragDrop} target The drop target
19933 * @param {Event} e The event object
19934 * @param {String} id The id of the dragged element
19935 * @method afterDragEnter
19937 this.afterDragEnter(target, e, id);
19943 * An empty function by default, but provided so that you can perform a custom action
19944 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19945 * @param {Roo.dd.DragDrop} target The drop target
19946 * @param {Event} e The event object
19947 * @param {String} id The id of the dragged element
19948 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19950 beforeDragEnter : function(target, e, id){
19955 alignElWithMouse: function() {
19956 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19961 onDragOver : function(e, id){
19962 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19963 if(this.beforeDragOver(target, e, id) !== false){
19964 if(target.isNotifyTarget){
19965 var status = target.notifyOver(this, e, this.dragData);
19966 this.proxy.setStatus(status);
19969 if(this.afterDragOver){
19971 * An empty function by default, but provided so that you can perform a custom action
19972 * while the dragged item is over the drop target by providing an implementation.
19973 * @param {Roo.dd.DragDrop} target The drop target
19974 * @param {Event} e The event object
19975 * @param {String} id The id of the dragged element
19976 * @method afterDragOver
19978 this.afterDragOver(target, e, id);
19984 * An empty function by default, but provided so that you can perform a custom action
19985 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19986 * @param {Roo.dd.DragDrop} target The drop target
19987 * @param {Event} e The event object
19988 * @param {String} id The id of the dragged element
19989 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19991 beforeDragOver : function(target, e, id){
19996 onDragOut : function(e, id){
19997 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19998 if(this.beforeDragOut(target, e, id) !== false){
19999 if(target.isNotifyTarget){
20000 target.notifyOut(this, e, this.dragData);
20002 this.proxy.reset();
20003 if(this.afterDragOut){
20005 * An empty function by default, but provided so that you can perform a custom action
20006 * after the dragged item is dragged out of the target without dropping.
20007 * @param {Roo.dd.DragDrop} target The drop target
20008 * @param {Event} e The event object
20009 * @param {String} id The id of the dragged element
20010 * @method afterDragOut
20012 this.afterDragOut(target, e, id);
20015 this.cachedTarget = null;
20019 * An empty function by default, but provided so that you can perform a custom action before the dragged
20020 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20021 * @param {Roo.dd.DragDrop} target The drop target
20022 * @param {Event} e The event object
20023 * @param {String} id The id of the dragged element
20024 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20026 beforeDragOut : function(target, e, id){
20031 onDragDrop : function(e, id){
20032 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20033 if(this.beforeDragDrop(target, e, id) !== false){
20034 if(target.isNotifyTarget){
20035 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20036 this.onValidDrop(target, e, id);
20038 this.onInvalidDrop(target, e, id);
20041 this.onValidDrop(target, e, id);
20044 if(this.afterDragDrop){
20046 * An empty function by default, but provided so that you can perform a custom action
20047 * after a valid drag drop has occurred by providing an implementation.
20048 * @param {Roo.dd.DragDrop} target The drop target
20049 * @param {Event} e The event object
20050 * @param {String} id The id of the dropped element
20051 * @method afterDragDrop
20053 this.afterDragDrop(target, e, id);
20056 delete this.cachedTarget;
20060 * An empty function by default, but provided so that you can perform a custom action before the dragged
20061 * item is dropped onto the target and optionally cancel the onDragDrop.
20062 * @param {Roo.dd.DragDrop} target The drop target
20063 * @param {Event} e The event object
20064 * @param {String} id The id of the dragged element
20065 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20067 beforeDragDrop : function(target, e, id){
20072 onValidDrop : function(target, e, id){
20074 if(this.afterValidDrop){
20076 * An empty function by default, but provided so that you can perform a custom action
20077 * after a valid drop has occurred by providing an implementation.
20078 * @param {Object} target The target DD
20079 * @param {Event} e The event object
20080 * @param {String} id The id of the dropped element
20081 * @method afterInvalidDrop
20083 this.afterValidDrop(target, e, id);
20088 getRepairXY : function(e, data){
20089 return this.el.getXY();
20093 onInvalidDrop : function(target, e, id){
20094 this.beforeInvalidDrop(target, e, id);
20095 if(this.cachedTarget){
20096 if(this.cachedTarget.isNotifyTarget){
20097 this.cachedTarget.notifyOut(this, e, this.dragData);
20099 this.cacheTarget = null;
20101 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20103 if(this.afterInvalidDrop){
20105 * An empty function by default, but provided so that you can perform a custom action
20106 * after an invalid drop has occurred by providing an implementation.
20107 * @param {Event} e The event object
20108 * @param {String} id The id of the dropped element
20109 * @method afterInvalidDrop
20111 this.afterInvalidDrop(e, id);
20116 afterRepair : function(){
20118 this.el.highlight(this.hlColor || "c3daf9");
20120 this.dragging = false;
20124 * An empty function by default, but provided so that you can perform a custom action after an invalid
20125 * drop has occurred.
20126 * @param {Roo.dd.DragDrop} target The drop target
20127 * @param {Event} e The event object
20128 * @param {String} id The id of the dragged element
20129 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20131 beforeInvalidDrop : function(target, e, id){
20136 handleMouseDown : function(e){
20137 if(this.dragging) {
20140 var data = this.getDragData(e);
20141 if(data && this.onBeforeDrag(data, e) !== false){
20142 this.dragData = data;
20144 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20149 * An empty function by default, but provided so that you can perform a custom action before the initial
20150 * drag event begins and optionally cancel it.
20151 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20152 * @param {Event} e The event object
20153 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20155 onBeforeDrag : function(data, e){
20160 * An empty function by default, but provided so that you can perform a custom action once the initial
20161 * drag event has begun. The drag cannot be canceled from this function.
20162 * @param {Number} x The x position of the click on the dragged object
20163 * @param {Number} y The y position of the click on the dragged object
20165 onStartDrag : Roo.emptyFn,
20167 // private - YUI override
20168 startDrag : function(x, y){
20169 this.proxy.reset();
20170 this.dragging = true;
20171 this.proxy.update("");
20172 this.onInitDrag(x, y);
20177 onInitDrag : function(x, y){
20178 var clone = this.el.dom.cloneNode(true);
20179 clone.id = Roo.id(); // prevent duplicate ids
20180 this.proxy.update(clone);
20181 this.onStartDrag(x, y);
20186 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20187 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20189 getProxy : function(){
20194 * Hides the drag source's {@link Roo.dd.StatusProxy}
20196 hideProxy : function(){
20198 this.proxy.reset(true);
20199 this.dragging = false;
20203 triggerCacheRefresh : function(){
20204 Roo.dd.DDM.refreshCache(this.groups);
20207 // private - override to prevent hiding
20208 b4EndDrag: function(e) {
20211 // private - override to prevent moving
20212 endDrag : function(e){
20213 this.onEndDrag(this.dragData, e);
20217 onEndDrag : function(data, e){
20220 // private - pin to cursor
20221 autoOffset : function(x, y) {
20222 this.setDelta(-12, -20);
20226 * Ext JS Library 1.1.1
20227 * Copyright(c) 2006-2007, Ext JS, LLC.
20229 * Originally Released Under LGPL - original licence link has changed is not relivant.
20232 * <script type="text/javascript">
20237 * @class Roo.dd.DropTarget
20238 * @extends Roo.dd.DDTarget
20239 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20240 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20242 * @param {String/HTMLElement/Element} el The container element
20243 * @param {Object} config
20245 Roo.dd.DropTarget = function(el, config){
20246 this.el = Roo.get(el);
20248 var listeners = false; ;
20249 if (config && config.listeners) {
20250 listeners= config.listeners;
20251 delete config.listeners;
20253 Roo.apply(this, config);
20255 if(this.containerScroll){
20256 Roo.dd.ScrollManager.register(this.el);
20260 * @scope Roo.dd.DropTarget
20265 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20266 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20267 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20269 * IMPORTANT : it should set this.overClass and this.dropAllowed
20271 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20272 * @param {Event} e The event
20273 * @param {Object} data An object containing arbitrary data supplied by the drag source
20279 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20280 * This method will be called on every mouse movement while the drag source is over the drop target.
20281 * This default implementation simply returns the dropAllowed config value.
20283 * IMPORTANT : it should set this.dropAllowed
20285 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20286 * @param {Event} e The event
20287 * @param {Object} data An object containing arbitrary data supplied by the drag source
20293 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20294 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20295 * overClass (if any) from the drop element.
20297 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20298 * @param {Event} e The event
20299 * @param {Object} data An object containing arbitrary data supplied by the drag source
20305 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20306 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20307 * implementation that does something to process the drop event and returns true so that the drag source's
20308 * repair action does not run.
20310 * IMPORTANT : it should set this.success
20312 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20313 * @param {Event} e The event
20314 * @param {Object} data An object containing arbitrary data supplied by the drag source
20320 Roo.dd.DropTarget.superclass.constructor.call( this,
20322 this.ddGroup || this.group,
20325 listeners : listeners || {}
20333 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20335 * @cfg {String} overClass
20336 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20339 * @cfg {String} ddGroup
20340 * The drag drop group to handle drop events for
20344 * @cfg {String} dropAllowed
20345 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20347 dropAllowed : "x-dd-drop-ok",
20349 * @cfg {String} dropNotAllowed
20350 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20352 dropNotAllowed : "x-dd-drop-nodrop",
20354 * @cfg {boolean} success
20355 * set this after drop listener..
20359 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20360 * if the drop point is valid for over/enter..
20367 isNotifyTarget : true,
20372 notifyEnter : function(dd, e, data)
20375 this.fireEvent('enter', dd, e, data);
20376 if(this.overClass){
20377 this.el.addClass(this.overClass);
20379 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20380 this.valid ? this.dropAllowed : this.dropNotAllowed
20387 notifyOver : function(dd, e, data)
20390 this.fireEvent('over', dd, e, data);
20391 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20392 this.valid ? this.dropAllowed : this.dropNotAllowed
20399 notifyOut : function(dd, e, data)
20401 this.fireEvent('out', dd, e, data);
20402 if(this.overClass){
20403 this.el.removeClass(this.overClass);
20410 notifyDrop : function(dd, e, data)
20412 this.success = false;
20413 this.fireEvent('drop', dd, e, data);
20414 return this.success;
20418 * Ext JS Library 1.1.1
20419 * Copyright(c) 2006-2007, Ext JS, LLC.
20421 * Originally Released Under LGPL - original licence link has changed is not relivant.
20424 * <script type="text/javascript">
20429 * @class Roo.dd.DragZone
20430 * @extends Roo.dd.DragSource
20431 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20432 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20434 * @param {String/HTMLElement/Element} el The container element
20435 * @param {Object} config
20437 Roo.dd.DragZone = function(el, config){
20438 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20439 if(this.containerScroll){
20440 Roo.dd.ScrollManager.register(this.el);
20444 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20446 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20447 * for auto scrolling during drag operations.
20450 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20451 * method after a failed drop (defaults to "c3daf9" - light blue)
20455 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20456 * for a valid target to drag based on the mouse down. Override this method
20457 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20458 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20459 * @param {EventObject} e The mouse down event
20460 * @return {Object} The dragData
20462 getDragData : function(e){
20463 return Roo.dd.Registry.getHandleFromEvent(e);
20467 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20468 * this.dragData.ddel
20469 * @param {Number} x The x position of the click on the dragged object
20470 * @param {Number} y The y position of the click on the dragged object
20471 * @return {Boolean} true to continue the drag, false to cancel
20473 onInitDrag : function(x, y){
20474 this.proxy.update(this.dragData.ddel.cloneNode(true));
20475 this.onStartDrag(x, y);
20480 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20482 afterRepair : function(){
20484 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20486 this.dragging = false;
20490 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20491 * the XY of this.dragData.ddel
20492 * @param {EventObject} e The mouse up event
20493 * @return {Array} The xy location (e.g. [100, 200])
20495 getRepairXY : function(e){
20496 return Roo.Element.fly(this.dragData.ddel).getXY();
20500 * Ext JS Library 1.1.1
20501 * Copyright(c) 2006-2007, Ext JS, LLC.
20503 * Originally Released Under LGPL - original licence link has changed is not relivant.
20506 * <script type="text/javascript">
20509 * @class Roo.dd.DropZone
20510 * @extends Roo.dd.DropTarget
20511 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20512 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20514 * @param {String/HTMLElement/Element} el The container element
20515 * @param {Object} config
20517 Roo.dd.DropZone = function(el, config){
20518 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20521 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20523 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20524 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20525 * provide your own custom lookup.
20526 * @param {Event} e The event
20527 * @return {Object} data The custom data
20529 getTargetFromEvent : function(e){
20530 return Roo.dd.Registry.getTargetFromEvent(e);
20534 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20535 * that it has registered. This method has no default implementation and should be overridden to provide
20536 * node-specific processing if necessary.
20537 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20538 * {@link #getTargetFromEvent} for this node)
20539 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20540 * @param {Event} e The event
20541 * @param {Object} data An object containing arbitrary data supplied by the drag source
20543 onNodeEnter : function(n, dd, e, data){
20548 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20549 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20550 * overridden to provide the proper feedback.
20551 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20552 * {@link #getTargetFromEvent} for this node)
20553 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20554 * @param {Event} e The event
20555 * @param {Object} data An object containing arbitrary data supplied by the drag source
20556 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20557 * underlying {@link Roo.dd.StatusProxy} can be updated
20559 onNodeOver : function(n, dd, e, data){
20560 return this.dropAllowed;
20564 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20565 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20566 * node-specific processing if necessary.
20567 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20568 * {@link #getTargetFromEvent} for this node)
20569 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20570 * @param {Event} e The event
20571 * @param {Object} data An object containing arbitrary data supplied by the drag source
20573 onNodeOut : function(n, dd, e, data){
20578 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20579 * the drop node. The default implementation returns false, so it should be overridden to provide the
20580 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20581 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20582 * {@link #getTargetFromEvent} for this node)
20583 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20584 * @param {Event} e The event
20585 * @param {Object} data An object containing arbitrary data supplied by the drag source
20586 * @return {Boolean} True if the drop was valid, else false
20588 onNodeDrop : function(n, dd, e, data){
20593 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20594 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20595 * it should be overridden to provide the proper feedback if necessary.
20596 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20597 * @param {Event} e The event
20598 * @param {Object} data An object containing arbitrary data supplied by the drag source
20599 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20600 * underlying {@link Roo.dd.StatusProxy} can be updated
20602 onContainerOver : function(dd, e, data){
20603 return this.dropNotAllowed;
20607 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20608 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20609 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20610 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20611 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20612 * @param {Event} e The event
20613 * @param {Object} data An object containing arbitrary data supplied by the drag source
20614 * @return {Boolean} True if the drop was valid, else false
20616 onContainerDrop : function(dd, e, data){
20621 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20622 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20623 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20624 * you should override this method and provide a custom implementation.
20625 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20626 * @param {Event} e The event
20627 * @param {Object} data An object containing arbitrary data supplied by the drag source
20628 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20629 * underlying {@link Roo.dd.StatusProxy} can be updated
20631 notifyEnter : function(dd, e, data){
20632 return this.dropNotAllowed;
20636 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20637 * This method will be called on every mouse movement while the drag source is over the drop zone.
20638 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20639 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20640 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20641 * registered node, it will call {@link #onContainerOver}.
20642 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20643 * @param {Event} e The event
20644 * @param {Object} data An object containing arbitrary data supplied by the drag source
20645 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20646 * underlying {@link Roo.dd.StatusProxy} can be updated
20648 notifyOver : function(dd, e, data){
20649 var n = this.getTargetFromEvent(e);
20650 if(!n){ // not over valid drop target
20651 if(this.lastOverNode){
20652 this.onNodeOut(this.lastOverNode, dd, e, data);
20653 this.lastOverNode = null;
20655 return this.onContainerOver(dd, e, data);
20657 if(this.lastOverNode != n){
20658 if(this.lastOverNode){
20659 this.onNodeOut(this.lastOverNode, dd, e, data);
20661 this.onNodeEnter(n, dd, e, data);
20662 this.lastOverNode = n;
20664 return this.onNodeOver(n, dd, e, data);
20668 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20669 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20670 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20671 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20672 * @param {Event} e The event
20673 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20675 notifyOut : function(dd, e, data){
20676 if(this.lastOverNode){
20677 this.onNodeOut(this.lastOverNode, dd, e, data);
20678 this.lastOverNode = null;
20683 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20684 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20685 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20686 * otherwise it will call {@link #onContainerDrop}.
20687 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20688 * @param {Event} e The event
20689 * @param {Object} data An object containing arbitrary data supplied by the drag source
20690 * @return {Boolean} True if the drop was valid, else false
20692 notifyDrop : function(dd, e, data){
20693 if(this.lastOverNode){
20694 this.onNodeOut(this.lastOverNode, dd, e, data);
20695 this.lastOverNode = null;
20697 var n = this.getTargetFromEvent(e);
20699 this.onNodeDrop(n, dd, e, data) :
20700 this.onContainerDrop(dd, e, data);
20704 triggerCacheRefresh : function(){
20705 Roo.dd.DDM.refreshCache(this.groups);
20709 * Ext JS Library 1.1.1
20710 * Copyright(c) 2006-2007, Ext JS, LLC.
20712 * Originally Released Under LGPL - original licence link has changed is not relivant.
20715 * <script type="text/javascript">
20720 * @class Roo.data.SortTypes
20722 * Defines the default sorting (casting?) comparison functions used when sorting data.
20724 Roo.data.SortTypes = {
20726 * Default sort that does nothing
20727 * @param {Mixed} s The value being converted
20728 * @return {Mixed} The comparison value
20730 none : function(s){
20735 * The regular expression used to strip tags
20739 stripTagsRE : /<\/?[^>]+>/gi,
20742 * Strips all HTML tags to sort on text only
20743 * @param {Mixed} s The value being converted
20744 * @return {String} The comparison value
20746 asText : function(s){
20747 return String(s).replace(this.stripTagsRE, "");
20751 * Strips all HTML tags to sort on text only - Case insensitive
20752 * @param {Mixed} s The value being converted
20753 * @return {String} The comparison value
20755 asUCText : function(s){
20756 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20760 * Case insensitive string
20761 * @param {Mixed} s The value being converted
20762 * @return {String} The comparison value
20764 asUCString : function(s) {
20765 return String(s).toUpperCase();
20770 * @param {Mixed} s The value being converted
20771 * @return {Number} The comparison value
20773 asDate : function(s) {
20777 if(s instanceof Date){
20778 return s.getTime();
20780 return Date.parse(String(s));
20785 * @param {Mixed} s The value being converted
20786 * @return {Float} The comparison value
20788 asFloat : function(s) {
20789 var val = parseFloat(String(s).replace(/,/g, ""));
20790 if(isNaN(val)) val = 0;
20796 * @param {Mixed} s The value being converted
20797 * @return {Number} The comparison value
20799 asInt : function(s) {
20800 var val = parseInt(String(s).replace(/,/g, ""));
20801 if(isNaN(val)) val = 0;
20806 * Ext JS Library 1.1.1
20807 * Copyright(c) 2006-2007, Ext JS, LLC.
20809 * Originally Released Under LGPL - original licence link has changed is not relivant.
20812 * <script type="text/javascript">
20816 * @class Roo.data.Record
20817 * Instances of this class encapsulate both record <em>definition</em> information, and record
20818 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20819 * to access Records cached in an {@link Roo.data.Store} object.<br>
20821 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20822 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20825 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20827 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20828 * {@link #create}. The parameters are the same.
20829 * @param {Array} data An associative Array of data values keyed by the field name.
20830 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20831 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20832 * not specified an integer id is generated.
20834 Roo.data.Record = function(data, id){
20835 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20840 * Generate a constructor for a specific record layout.
20841 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20842 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20843 * Each field definition object may contain the following properties: <ul>
20844 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
20845 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20846 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20847 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20848 * is being used, then this is a string containing the javascript expression to reference the data relative to
20849 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20850 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20851 * this may be omitted.</p></li>
20852 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20853 * <ul><li>auto (Default, implies no conversion)</li>
20858 * <li>date</li></ul></p></li>
20859 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20860 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20861 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20862 * by the Reader into an object that will be stored in the Record. It is passed the
20863 * following parameters:<ul>
20864 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20866 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20868 * <br>usage:<br><pre><code>
20869 var TopicRecord = Roo.data.Record.create(
20870 {name: 'title', mapping: 'topic_title'},
20871 {name: 'author', mapping: 'username'},
20872 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20873 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20874 {name: 'lastPoster', mapping: 'user2'},
20875 {name: 'excerpt', mapping: 'post_text'}
20878 var myNewRecord = new TopicRecord({
20879 title: 'Do my job please',
20882 lastPost: new Date(),
20883 lastPoster: 'Animal',
20884 excerpt: 'No way dude!'
20886 myStore.add(myNewRecord);
20891 Roo.data.Record.create = function(o){
20892 var f = function(){
20893 f.superclass.constructor.apply(this, arguments);
20895 Roo.extend(f, Roo.data.Record);
20896 var p = f.prototype;
20897 p.fields = new Roo.util.MixedCollection(false, function(field){
20900 for(var i = 0, len = o.length; i < len; i++){
20901 p.fields.add(new Roo.data.Field(o[i]));
20903 f.getField = function(name){
20904 return p.fields.get(name);
20909 Roo.data.Record.AUTO_ID = 1000;
20910 Roo.data.Record.EDIT = 'edit';
20911 Roo.data.Record.REJECT = 'reject';
20912 Roo.data.Record.COMMIT = 'commit';
20914 Roo.data.Record.prototype = {
20916 * Readonly flag - true if this record has been modified.
20925 join : function(store){
20926 this.store = store;
20930 * Set the named field to the specified value.
20931 * @param {String} name The name of the field to set.
20932 * @param {Object} value The value to set the field to.
20934 set : function(name, value){
20935 if(this.data[name] == value){
20939 if(!this.modified){
20940 this.modified = {};
20942 if(typeof this.modified[name] == 'undefined'){
20943 this.modified[name] = this.data[name];
20945 this.data[name] = value;
20946 if(!this.editing && this.store){
20947 this.store.afterEdit(this);
20952 * Get the value of the named field.
20953 * @param {String} name The name of the field to get the value of.
20954 * @return {Object} The value of the field.
20956 get : function(name){
20957 return this.data[name];
20961 beginEdit : function(){
20962 this.editing = true;
20963 this.modified = {};
20967 cancelEdit : function(){
20968 this.editing = false;
20969 delete this.modified;
20973 endEdit : function(){
20974 this.editing = false;
20975 if(this.dirty && this.store){
20976 this.store.afterEdit(this);
20981 * Usually called by the {@link Roo.data.Store} which owns the Record.
20982 * Rejects all changes made to the Record since either creation, or the last commit operation.
20983 * Modified fields are reverted to their original values.
20985 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20986 * of reject operations.
20988 reject : function(){
20989 var m = this.modified;
20991 if(typeof m[n] != "function"){
20992 this.data[n] = m[n];
20995 this.dirty = false;
20996 delete this.modified;
20997 this.editing = false;
20999 this.store.afterReject(this);
21004 * Usually called by the {@link Roo.data.Store} which owns the Record.
21005 * Commits all changes made to the Record since either creation, or the last commit operation.
21007 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21008 * of commit operations.
21010 commit : function(){
21011 this.dirty = false;
21012 delete this.modified;
21013 this.editing = false;
21015 this.store.afterCommit(this);
21020 hasError : function(){
21021 return this.error != null;
21025 clearError : function(){
21030 * Creates a copy of this record.
21031 * @param {String} id (optional) A new record id if you don't want to use this record's id
21034 copy : function(newId) {
21035 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21039 * Ext JS Library 1.1.1
21040 * Copyright(c) 2006-2007, Ext JS, LLC.
21042 * Originally Released Under LGPL - original licence link has changed is not relivant.
21045 * <script type="text/javascript">
21051 * @class Roo.data.Store
21052 * @extends Roo.util.Observable
21053 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21054 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21056 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
21057 * has no knowledge of the format of the data returned by the Proxy.<br>
21059 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21060 * instances from the data object. These records are cached and made available through accessor functions.
21062 * Creates a new Store.
21063 * @param {Object} config A config object containing the objects needed for the Store to access data,
21064 * and read the data into Records.
21066 Roo.data.Store = function(config){
21067 this.data = new Roo.util.MixedCollection(false);
21068 this.data.getKey = function(o){
21071 this.baseParams = {};
21073 this.paramNames = {
21078 "multisort" : "_multisort"
21081 if(config && config.data){
21082 this.inlineData = config.data;
21083 delete config.data;
21086 Roo.apply(this, config);
21088 if(this.reader){ // reader passed
21089 this.reader = Roo.factory(this.reader, Roo.data);
21090 this.reader.xmodule = this.xmodule || false;
21091 if(!this.recordType){
21092 this.recordType = this.reader.recordType;
21094 if(this.reader.onMetaChange){
21095 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21099 if(this.recordType){
21100 this.fields = this.recordType.prototype.fields;
21102 this.modified = [];
21106 * @event datachanged
21107 * Fires when the data cache has changed, and a widget which is using this Store
21108 * as a Record cache should refresh its view.
21109 * @param {Store} this
21111 datachanged : true,
21113 * @event metachange
21114 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21115 * @param {Store} this
21116 * @param {Object} meta The JSON metadata
21121 * Fires when Records have been added to the Store
21122 * @param {Store} this
21123 * @param {Roo.data.Record[]} records The array of Records added
21124 * @param {Number} index The index at which the record(s) were added
21129 * Fires when a Record has been removed from the Store
21130 * @param {Store} this
21131 * @param {Roo.data.Record} record The Record that was removed
21132 * @param {Number} index The index at which the record was removed
21137 * Fires when a Record has been updated
21138 * @param {Store} this
21139 * @param {Roo.data.Record} record The Record that was updated
21140 * @param {String} operation The update operation being performed. Value may be one of:
21142 Roo.data.Record.EDIT
21143 Roo.data.Record.REJECT
21144 Roo.data.Record.COMMIT
21150 * Fires when the data cache has been cleared.
21151 * @param {Store} this
21155 * @event beforeload
21156 * Fires before a request is made for a new data object. If the beforeload handler returns false
21157 * the load action will be canceled.
21158 * @param {Store} this
21159 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21163 * @event beforeloadadd
21164 * Fires after a new set of Records has been loaded.
21165 * @param {Store} this
21166 * @param {Roo.data.Record[]} records The Records that were loaded
21167 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21169 beforeloadadd : true,
21172 * Fires after a new set of Records has been loaded, before they are added to the store.
21173 * @param {Store} this
21174 * @param {Roo.data.Record[]} records The Records that were loaded
21175 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21176 * @params {Object} return from reader
21180 * @event loadexception
21181 * Fires if an exception occurs in the Proxy during loading.
21182 * Called with the signature of the Proxy's "loadexception" event.
21183 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21186 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21187 * @param {Object} load options
21188 * @param {Object} jsonData from your request (normally this contains the Exception)
21190 loadexception : true
21194 this.proxy = Roo.factory(this.proxy, Roo.data);
21195 this.proxy.xmodule = this.xmodule || false;
21196 this.relayEvents(this.proxy, ["loadexception"]);
21198 this.sortToggle = {};
21199 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21201 Roo.data.Store.superclass.constructor.call(this);
21203 if(this.inlineData){
21204 this.loadData(this.inlineData);
21205 delete this.inlineData;
21209 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21211 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21212 * without a remote query - used by combo/forms at present.
21216 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21219 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21222 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21223 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21226 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21227 * on any HTTP request
21230 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21233 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21237 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21238 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21240 remoteSort : false,
21243 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21244 * loaded or when a record is removed. (defaults to false).
21246 pruneModifiedRecords : false,
21249 lastOptions : null,
21252 * Add Records to the Store and fires the add event.
21253 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21255 add : function(records){
21256 records = [].concat(records);
21257 for(var i = 0, len = records.length; i < len; i++){
21258 records[i].join(this);
21260 var index = this.data.length;
21261 this.data.addAll(records);
21262 this.fireEvent("add", this, records, index);
21266 * Remove a Record from the Store and fires the remove event.
21267 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21269 remove : function(record){
21270 var index = this.data.indexOf(record);
21271 this.data.removeAt(index);
21272 if(this.pruneModifiedRecords){
21273 this.modified.remove(record);
21275 this.fireEvent("remove", this, record, index);
21279 * Remove all Records from the Store and fires the clear event.
21281 removeAll : function(){
21283 if(this.pruneModifiedRecords){
21284 this.modified = [];
21286 this.fireEvent("clear", this);
21290 * Inserts Records to the Store at the given index and fires the add event.
21291 * @param {Number} index The start index at which to insert the passed Records.
21292 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21294 insert : function(index, records){
21295 records = [].concat(records);
21296 for(var i = 0, len = records.length; i < len; i++){
21297 this.data.insert(index, records[i]);
21298 records[i].join(this);
21300 this.fireEvent("add", this, records, index);
21304 * Get the index within the cache of the passed Record.
21305 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21306 * @return {Number} The index of the passed Record. Returns -1 if not found.
21308 indexOf : function(record){
21309 return this.data.indexOf(record);
21313 * Get the index within the cache of the Record with the passed id.
21314 * @param {String} id The id of the Record to find.
21315 * @return {Number} The index of the Record. Returns -1 if not found.
21317 indexOfId : function(id){
21318 return this.data.indexOfKey(id);
21322 * Get the Record with the specified id.
21323 * @param {String} id The id of the Record to find.
21324 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21326 getById : function(id){
21327 return this.data.key(id);
21331 * Get the Record at the specified index.
21332 * @param {Number} index The index of the Record to find.
21333 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21335 getAt : function(index){
21336 return this.data.itemAt(index);
21340 * Returns a range of Records between specified indices.
21341 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21342 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21343 * @return {Roo.data.Record[]} An array of Records
21345 getRange : function(start, end){
21346 return this.data.getRange(start, end);
21350 storeOptions : function(o){
21351 o = Roo.apply({}, o);
21354 this.lastOptions = o;
21358 * Loads the Record cache from the configured Proxy using the configured Reader.
21360 * If using remote paging, then the first load call must specify the <em>start</em>
21361 * and <em>limit</em> properties in the options.params property to establish the initial
21362 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21364 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21365 * and this call will return before the new data has been loaded. Perform any post-processing
21366 * in a callback function, or in a "load" event handler.</strong>
21368 * @param {Object} options An object containing properties which control loading options:<ul>
21369 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21370 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21371 * passed the following arguments:<ul>
21372 * <li>r : Roo.data.Record[]</li>
21373 * <li>options: Options object from the load call</li>
21374 * <li>success: Boolean success indicator</li></ul></li>
21375 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21376 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21379 load : function(options){
21380 options = options || {};
21381 if(this.fireEvent("beforeload", this, options) !== false){
21382 this.storeOptions(options);
21383 var p = Roo.apply(options.params || {}, this.baseParams);
21384 // if meta was not loaded from remote source.. try requesting it.
21385 if (!this.reader.metaFromRemote) {
21386 p._requestMeta = 1;
21388 if(this.sortInfo && this.remoteSort){
21389 var pn = this.paramNames;
21390 p[pn["sort"]] = this.sortInfo.field;
21391 p[pn["dir"]] = this.sortInfo.direction;
21393 if (this.multiSort) {
21394 var pn = this.paramNames;
21395 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21398 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21403 * Reloads the Record cache from the configured Proxy using the configured Reader and
21404 * the options from the last load operation performed.
21405 * @param {Object} options (optional) An object containing properties which may override the options
21406 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21407 * the most recently used options are reused).
21409 reload : function(options){
21410 this.load(Roo.applyIf(options||{}, this.lastOptions));
21414 // Called as a callback by the Reader during a load operation.
21415 loadRecords : function(o, options, success){
21416 if(!o || success === false){
21417 if(success !== false){
21418 this.fireEvent("load", this, [], options, o);
21420 if(options.callback){
21421 options.callback.call(options.scope || this, [], options, false);
21425 // if data returned failure - throw an exception.
21426 if (o.success === false) {
21427 // show a message if no listener is registered.
21428 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21429 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21431 // loadmask wil be hooked into this..
21432 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21435 var r = o.records, t = o.totalRecords || r.length;
21437 this.fireEvent("beforeloadadd", this, r, options, o);
21439 if(!options || options.add !== true){
21440 if(this.pruneModifiedRecords){
21441 this.modified = [];
21443 for(var i = 0, len = r.length; i < len; i++){
21447 this.data = this.snapshot;
21448 delete this.snapshot;
21451 this.data.addAll(r);
21452 this.totalLength = t;
21454 this.fireEvent("datachanged", this);
21456 this.totalLength = Math.max(t, this.data.length+r.length);
21459 this.fireEvent("load", this, r, options, o);
21460 if(options.callback){
21461 options.callback.call(options.scope || this, r, options, true);
21467 * Loads data from a passed data block. A Reader which understands the format of the data
21468 * must have been configured in the constructor.
21469 * @param {Object} data The data block from which to read the Records. The format of the data expected
21470 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21471 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21473 loadData : function(o, append){
21474 var r = this.reader.readRecords(o);
21475 this.loadRecords(r, {add: append}, true);
21479 * Gets the number of cached records.
21481 * <em>If using paging, this may not be the total size of the dataset. If the data object
21482 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21483 * the data set size</em>
21485 getCount : function(){
21486 return this.data.length || 0;
21490 * Gets the total number of records in the dataset as returned by the server.
21492 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21493 * the dataset size</em>
21495 getTotalCount : function(){
21496 return this.totalLength || 0;
21500 * Returns the sort state of the Store as an object with two properties:
21502 field {String} The name of the field by which the Records are sorted
21503 direction {String} The sort order, "ASC" or "DESC"
21506 getSortState : function(){
21507 return this.sortInfo;
21511 applySort : function(){
21512 if(this.sortInfo && !this.remoteSort){
21513 var s = this.sortInfo, f = s.field;
21514 var st = this.fields.get(f).sortType;
21515 var fn = function(r1, r2){
21516 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21517 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21519 this.data.sort(s.direction, fn);
21520 if(this.snapshot && this.snapshot != this.data){
21521 this.snapshot.sort(s.direction, fn);
21527 * Sets the default sort column and order to be used by the next load operation.
21528 * @param {String} fieldName The name of the field to sort by.
21529 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21531 setDefaultSort : function(field, dir){
21532 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21536 * Sort the Records.
21537 * If remote sorting is used, the sort is performed on the server, and the cache is
21538 * reloaded. If local sorting is used, the cache is sorted internally.
21539 * @param {String} fieldName The name of the field to sort by.
21540 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21542 sort : function(fieldName, dir){
21543 var f = this.fields.get(fieldName);
21545 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21547 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21548 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21553 this.sortToggle[f.name] = dir;
21554 this.sortInfo = {field: f.name, direction: dir};
21555 if(!this.remoteSort){
21557 this.fireEvent("datachanged", this);
21559 this.load(this.lastOptions);
21564 * Calls the specified function for each of the Records in the cache.
21565 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21566 * Returning <em>false</em> aborts and exits the iteration.
21567 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21569 each : function(fn, scope){
21570 this.data.each(fn, scope);
21574 * Gets all records modified since the last commit. Modified records are persisted across load operations
21575 * (e.g., during paging).
21576 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21578 getModifiedRecords : function(){
21579 return this.modified;
21583 createFilterFn : function(property, value, anyMatch){
21584 if(!value.exec){ // not a regex
21585 value = String(value);
21586 if(value.length == 0){
21589 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21591 return function(r){
21592 return value.test(r.data[property]);
21597 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21598 * @param {String} property A field on your records
21599 * @param {Number} start The record index to start at (defaults to 0)
21600 * @param {Number} end The last record index to include (defaults to length - 1)
21601 * @return {Number} The sum
21603 sum : function(property, start, end){
21604 var rs = this.data.items, v = 0;
21605 start = start || 0;
21606 end = (end || end === 0) ? end : rs.length-1;
21608 for(var i = start; i <= end; i++){
21609 v += (rs[i].data[property] || 0);
21615 * Filter the records by a specified property.
21616 * @param {String} field A field on your records
21617 * @param {String/RegExp} value Either a string that the field
21618 * should start with or a RegExp to test against the field
21619 * @param {Boolean} anyMatch True to match any part not just the beginning
21621 filter : function(property, value, anyMatch){
21622 var fn = this.createFilterFn(property, value, anyMatch);
21623 return fn ? this.filterBy(fn) : this.clearFilter();
21627 * Filter by a function. The specified function will be called with each
21628 * record in this data source. If the function returns true the record is included,
21629 * otherwise it is filtered.
21630 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21631 * @param {Object} scope (optional) The scope of the function (defaults to this)
21633 filterBy : function(fn, scope){
21634 this.snapshot = this.snapshot || this.data;
21635 this.data = this.queryBy(fn, scope||this);
21636 this.fireEvent("datachanged", this);
21640 * Query the records by a specified property.
21641 * @param {String} field A field on your records
21642 * @param {String/RegExp} value Either a string that the field
21643 * should start with or a RegExp to test against the field
21644 * @param {Boolean} anyMatch True to match any part not just the beginning
21645 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21647 query : function(property, value, anyMatch){
21648 var fn = this.createFilterFn(property, value, anyMatch);
21649 return fn ? this.queryBy(fn) : this.data.clone();
21653 * Query by a function. The specified function will be called with each
21654 * record in this data source. If the function returns true the record is included
21656 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21657 * @param {Object} scope (optional) The scope of the function (defaults to this)
21658 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21660 queryBy : function(fn, scope){
21661 var data = this.snapshot || this.data;
21662 return data.filterBy(fn, scope||this);
21666 * Collects unique values for a particular dataIndex from this store.
21667 * @param {String} dataIndex The property to collect
21668 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21669 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21670 * @return {Array} An array of the unique values
21672 collect : function(dataIndex, allowNull, bypassFilter){
21673 var d = (bypassFilter === true && this.snapshot) ?
21674 this.snapshot.items : this.data.items;
21675 var v, sv, r = [], l = {};
21676 for(var i = 0, len = d.length; i < len; i++){
21677 v = d[i].data[dataIndex];
21679 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21688 * Revert to a view of the Record cache with no filtering applied.
21689 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21691 clearFilter : function(suppressEvent){
21692 if(this.snapshot && this.snapshot != this.data){
21693 this.data = this.snapshot;
21694 delete this.snapshot;
21695 if(suppressEvent !== true){
21696 this.fireEvent("datachanged", this);
21702 afterEdit : function(record){
21703 if(this.modified.indexOf(record) == -1){
21704 this.modified.push(record);
21706 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21710 afterReject : function(record){
21711 this.modified.remove(record);
21712 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21716 afterCommit : function(record){
21717 this.modified.remove(record);
21718 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21722 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21723 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21725 commitChanges : function(){
21726 var m = this.modified.slice(0);
21727 this.modified = [];
21728 for(var i = 0, len = m.length; i < len; i++){
21734 * Cancel outstanding changes on all changed records.
21736 rejectChanges : function(){
21737 var m = this.modified.slice(0);
21738 this.modified = [];
21739 for(var i = 0, len = m.length; i < len; i++){
21744 onMetaChange : function(meta, rtype, o){
21745 this.recordType = rtype;
21746 this.fields = rtype.prototype.fields;
21747 delete this.snapshot;
21748 this.sortInfo = meta.sortInfo || this.sortInfo;
21749 this.modified = [];
21750 this.fireEvent('metachange', this, this.reader.meta);
21753 moveIndex : function(data, type)
21755 var index = this.indexOf(data);
21757 var newIndex = index + type;
21761 this.insert(newIndex, data);
21766 * Ext JS Library 1.1.1
21767 * Copyright(c) 2006-2007, Ext JS, LLC.
21769 * Originally Released Under LGPL - original licence link has changed is not relivant.
21772 * <script type="text/javascript">
21776 * @class Roo.data.SimpleStore
21777 * @extends Roo.data.Store
21778 * Small helper class to make creating Stores from Array data easier.
21779 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21780 * @cfg {Array} fields An array of field definition objects, or field name strings.
21781 * @cfg {Array} data The multi-dimensional array of data
21783 * @param {Object} config
21785 Roo.data.SimpleStore = function(config){
21786 Roo.data.SimpleStore.superclass.constructor.call(this, {
21788 reader: new Roo.data.ArrayReader({
21791 Roo.data.Record.create(config.fields)
21793 proxy : new Roo.data.MemoryProxy(config.data)
21797 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21799 * Ext JS Library 1.1.1
21800 * Copyright(c) 2006-2007, Ext JS, LLC.
21802 * Originally Released Under LGPL - original licence link has changed is not relivant.
21805 * <script type="text/javascript">
21810 * @extends Roo.data.Store
21811 * @class Roo.data.JsonStore
21812 * Small helper class to make creating Stores for JSON data easier. <br/>
21814 var store = new Roo.data.JsonStore({
21815 url: 'get-images.php',
21817 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21820 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21821 * JsonReader and HttpProxy (unless inline data is provided).</b>
21822 * @cfg {Array} fields An array of field definition objects, or field name strings.
21824 * @param {Object} config
21826 Roo.data.JsonStore = function(c){
21827 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21828 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21829 reader: new Roo.data.JsonReader(c, c.fields)
21832 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21834 * Ext JS Library 1.1.1
21835 * Copyright(c) 2006-2007, Ext JS, LLC.
21837 * Originally Released Under LGPL - original licence link has changed is not relivant.
21840 * <script type="text/javascript">
21844 Roo.data.Field = function(config){
21845 if(typeof config == "string"){
21846 config = {name: config};
21848 Roo.apply(this, config);
21851 this.type = "auto";
21854 var st = Roo.data.SortTypes;
21855 // named sortTypes are supported, here we look them up
21856 if(typeof this.sortType == "string"){
21857 this.sortType = st[this.sortType];
21860 // set default sortType for strings and dates
21861 if(!this.sortType){
21864 this.sortType = st.asUCString;
21867 this.sortType = st.asDate;
21870 this.sortType = st.none;
21875 var stripRe = /[\$,%]/g;
21877 // prebuilt conversion function for this field, instead of
21878 // switching every time we're reading a value
21880 var cv, dateFormat = this.dateFormat;
21885 cv = function(v){ return v; };
21888 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21892 return v !== undefined && v !== null && v !== '' ?
21893 parseInt(String(v).replace(stripRe, ""), 10) : '';
21898 return v !== undefined && v !== null && v !== '' ?
21899 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21904 cv = function(v){ return v === true || v === "true" || v == 1; };
21911 if(v instanceof Date){
21915 if(dateFormat == "timestamp"){
21916 return new Date(v*1000);
21918 return Date.parseDate(v, dateFormat);
21920 var parsed = Date.parse(v);
21921 return parsed ? new Date(parsed) : null;
21930 Roo.data.Field.prototype = {
21938 * Ext JS Library 1.1.1
21939 * Copyright(c) 2006-2007, Ext JS, LLC.
21941 * Originally Released Under LGPL - original licence link has changed is not relivant.
21944 * <script type="text/javascript">
21947 // Base class for reading structured data from a data source. This class is intended to be
21948 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21951 * @class Roo.data.DataReader
21952 * Base class for reading structured data from a data source. This class is intended to be
21953 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21956 Roo.data.DataReader = function(meta, recordType){
21960 this.recordType = recordType instanceof Array ?
21961 Roo.data.Record.create(recordType) : recordType;
21964 Roo.data.DataReader.prototype = {
21966 * Create an empty record
21967 * @param {Object} data (optional) - overlay some values
21968 * @return {Roo.data.Record} record created.
21970 newRow : function(d) {
21972 this.recordType.prototype.fields.each(function(c) {
21974 case 'int' : da[c.name] = 0; break;
21975 case 'date' : da[c.name] = new Date(); break;
21976 case 'float' : da[c.name] = 0.0; break;
21977 case 'boolean' : da[c.name] = false; break;
21978 default : da[c.name] = ""; break;
21982 return new this.recordType(Roo.apply(da, d));
21987 * Ext JS Library 1.1.1
21988 * Copyright(c) 2006-2007, Ext JS, LLC.
21990 * Originally Released Under LGPL - original licence link has changed is not relivant.
21993 * <script type="text/javascript">
21997 * @class Roo.data.DataProxy
21998 * @extends Roo.data.Observable
21999 * This class is an abstract base class for implementations which provide retrieval of
22000 * unformatted data objects.<br>
22002 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22003 * (of the appropriate type which knows how to parse the data object) to provide a block of
22004 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22006 * Custom implementations must implement the load method as described in
22007 * {@link Roo.data.HttpProxy#load}.
22009 Roo.data.DataProxy = function(){
22012 * @event beforeload
22013 * Fires before a network request is made to retrieve a data object.
22014 * @param {Object} This DataProxy object.
22015 * @param {Object} params The params parameter to the load function.
22020 * Fires before the load method's callback is called.
22021 * @param {Object} This DataProxy object.
22022 * @param {Object} o The data object.
22023 * @param {Object} arg The callback argument object passed to the load function.
22027 * @event loadexception
22028 * Fires if an Exception occurs during data retrieval.
22029 * @param {Object} This DataProxy object.
22030 * @param {Object} o The data object.
22031 * @param {Object} arg The callback argument object passed to the load function.
22032 * @param {Object} e The Exception.
22034 loadexception : true
22036 Roo.data.DataProxy.superclass.constructor.call(this);
22039 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22042 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22046 * Ext JS Library 1.1.1
22047 * Copyright(c) 2006-2007, Ext JS, LLC.
22049 * Originally Released Under LGPL - original licence link has changed is not relivant.
22052 * <script type="text/javascript">
22055 * @class Roo.data.MemoryProxy
22056 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22057 * to the Reader when its load method is called.
22059 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22061 Roo.data.MemoryProxy = function(data){
22065 Roo.data.MemoryProxy.superclass.constructor.call(this);
22069 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22071 * Load data from the requested source (in this case an in-memory
22072 * data object passed to the constructor), read the data object into
22073 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22074 * process that block using the passed callback.
22075 * @param {Object} params This parameter is not used by the MemoryProxy class.
22076 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22077 * object into a block of Roo.data.Records.
22078 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22079 * The function must be passed <ul>
22080 * <li>The Record block object</li>
22081 * <li>The "arg" argument from the load function</li>
22082 * <li>A boolean success indicator</li>
22084 * @param {Object} scope The scope in which to call the callback
22085 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22087 load : function(params, reader, callback, scope, arg){
22088 params = params || {};
22091 result = reader.readRecords(this.data);
22093 this.fireEvent("loadexception", this, arg, null, e);
22094 callback.call(scope, null, arg, false);
22097 callback.call(scope, result, arg, true);
22101 update : function(params, records){
22106 * Ext JS Library 1.1.1
22107 * Copyright(c) 2006-2007, Ext JS, LLC.
22109 * Originally Released Under LGPL - original licence link has changed is not relivant.
22112 * <script type="text/javascript">
22115 * @class Roo.data.HttpProxy
22116 * @extends Roo.data.DataProxy
22117 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22118 * configured to reference a certain URL.<br><br>
22120 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22121 * from which the running page was served.<br><br>
22123 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22125 * Be aware that to enable the browser to parse an XML document, the server must set
22126 * the Content-Type header in the HTTP response to "text/xml".
22128 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22129 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22130 * will be used to make the request.
22132 Roo.data.HttpProxy = function(conn){
22133 Roo.data.HttpProxy.superclass.constructor.call(this);
22134 // is conn a conn config or a real conn?
22136 this.useAjax = !conn || !conn.events;
22140 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22141 // thse are take from connection...
22144 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22147 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22148 * extra parameters to each request made by this object. (defaults to undefined)
22151 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22152 * to each request made by this object. (defaults to undefined)
22155 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
22158 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22161 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22167 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22171 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22172 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22173 * a finer-grained basis than the DataProxy events.
22175 getConnection : function(){
22176 return this.useAjax ? Roo.Ajax : this.conn;
22180 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22181 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22182 * process that block using the passed callback.
22183 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22184 * for the request to the remote server.
22185 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22186 * object into a block of Roo.data.Records.
22187 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22188 * The function must be passed <ul>
22189 * <li>The Record block object</li>
22190 * <li>The "arg" argument from the load function</li>
22191 * <li>A boolean success indicator</li>
22193 * @param {Object} scope The scope in which to call the callback
22194 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22196 load : function(params, reader, callback, scope, arg){
22197 if(this.fireEvent("beforeload", this, params) !== false){
22199 params : params || {},
22201 callback : callback,
22206 callback : this.loadResponse,
22210 Roo.applyIf(o, this.conn);
22211 if(this.activeRequest){
22212 Roo.Ajax.abort(this.activeRequest);
22214 this.activeRequest = Roo.Ajax.request(o);
22216 this.conn.request(o);
22219 callback.call(scope||this, null, arg, false);
22224 loadResponse : function(o, success, response){
22225 delete this.activeRequest;
22227 this.fireEvent("loadexception", this, o, response);
22228 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22233 result = o.reader.read(response);
22235 this.fireEvent("loadexception", this, o, response, e);
22236 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22240 this.fireEvent("load", this, o, o.request.arg);
22241 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22245 update : function(dataSet){
22250 updateResponse : function(dataSet){
22255 * Ext JS Library 1.1.1
22256 * Copyright(c) 2006-2007, Ext JS, LLC.
22258 * Originally Released Under LGPL - original licence link has changed is not relivant.
22261 * <script type="text/javascript">
22265 * @class Roo.data.ScriptTagProxy
22266 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22267 * other than the originating domain of the running page.<br><br>
22269 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
22270 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22272 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22273 * source code that is used as the source inside a <script> tag.<br><br>
22275 * In order for the browser to process the returned data, the server must wrap the data object
22276 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22277 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22278 * depending on whether the callback name was passed:
22281 boolean scriptTag = false;
22282 String cb = request.getParameter("callback");
22285 response.setContentType("text/javascript");
22287 response.setContentType("application/x-json");
22289 Writer out = response.getWriter();
22291 out.write(cb + "(");
22293 out.print(dataBlock.toJsonString());
22300 * @param {Object} config A configuration object.
22302 Roo.data.ScriptTagProxy = function(config){
22303 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22304 Roo.apply(this, config);
22305 this.head = document.getElementsByTagName("head")[0];
22308 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22310 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22312 * @cfg {String} url The URL from which to request the data object.
22315 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22319 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22320 * the server the name of the callback function set up by the load call to process the returned data object.
22321 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22322 * javascript output which calls this named function passing the data object as its only parameter.
22324 callbackParam : "callback",
22326 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22327 * name to the request.
22332 * Load data from the configured URL, read the data object into
22333 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22334 * process that block using the passed callback.
22335 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22336 * for the request to the remote server.
22337 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22338 * object into a block of Roo.data.Records.
22339 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22340 * The function must be passed <ul>
22341 * <li>The Record block object</li>
22342 * <li>The "arg" argument from the load function</li>
22343 * <li>A boolean success indicator</li>
22345 * @param {Object} scope The scope in which to call the callback
22346 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22348 load : function(params, reader, callback, scope, arg){
22349 if(this.fireEvent("beforeload", this, params) !== false){
22351 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22353 var url = this.url;
22354 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22356 url += "&_dc=" + (new Date().getTime());
22358 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22361 cb : "stcCallback"+transId,
22362 scriptId : "stcScript"+transId,
22366 callback : callback,
22372 window[trans.cb] = function(o){
22373 conn.handleResponse(o, trans);
22376 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22378 if(this.autoAbort !== false){
22382 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22384 var script = document.createElement("script");
22385 script.setAttribute("src", url);
22386 script.setAttribute("type", "text/javascript");
22387 script.setAttribute("id", trans.scriptId);
22388 this.head.appendChild(script);
22390 this.trans = trans;
22392 callback.call(scope||this, null, arg, false);
22397 isLoading : function(){
22398 return this.trans ? true : false;
22402 * Abort the current server request.
22404 abort : function(){
22405 if(this.isLoading()){
22406 this.destroyTrans(this.trans);
22411 destroyTrans : function(trans, isLoaded){
22412 this.head.removeChild(document.getElementById(trans.scriptId));
22413 clearTimeout(trans.timeoutId);
22415 window[trans.cb] = undefined;
22417 delete window[trans.cb];
22420 // if hasn't been loaded, wait for load to remove it to prevent script error
22421 window[trans.cb] = function(){
22422 window[trans.cb] = undefined;
22424 delete window[trans.cb];
22431 handleResponse : function(o, trans){
22432 this.trans = false;
22433 this.destroyTrans(trans, true);
22436 result = trans.reader.readRecords(o);
22438 this.fireEvent("loadexception", this, o, trans.arg, e);
22439 trans.callback.call(trans.scope||window, null, trans.arg, false);
22442 this.fireEvent("load", this, o, trans.arg);
22443 trans.callback.call(trans.scope||window, result, trans.arg, true);
22447 handleFailure : function(trans){
22448 this.trans = false;
22449 this.destroyTrans(trans, false);
22450 this.fireEvent("loadexception", this, null, trans.arg);
22451 trans.callback.call(trans.scope||window, null, trans.arg, false);
22455 * Ext JS Library 1.1.1
22456 * Copyright(c) 2006-2007, Ext JS, LLC.
22458 * Originally Released Under LGPL - original licence link has changed is not relivant.
22461 * <script type="text/javascript">
22465 * @class Roo.data.JsonReader
22466 * @extends Roo.data.DataReader
22467 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22468 * based on mappings in a provided Roo.data.Record constructor.
22470 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22471 * in the reply previously.
22476 var RecordDef = Roo.data.Record.create([
22477 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22478 {name: 'occupation'} // This field will use "occupation" as the mapping.
22480 var myReader = new Roo.data.JsonReader({
22481 totalProperty: "results", // The property which contains the total dataset size (optional)
22482 root: "rows", // The property which contains an Array of row objects
22483 id: "id" // The property within each row object that provides an ID for the record (optional)
22487 * This would consume a JSON file like this:
22489 { 'results': 2, 'rows': [
22490 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22491 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22494 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22495 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22496 * paged from the remote server.
22497 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22498 * @cfg {String} root name of the property which contains the Array of row objects.
22499 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22501 * Create a new JsonReader
22502 * @param {Object} meta Metadata configuration options
22503 * @param {Object} recordType Either an Array of field definition objects,
22504 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22506 Roo.data.JsonReader = function(meta, recordType){
22509 // set some defaults:
22510 Roo.applyIf(meta, {
22511 totalProperty: 'total',
22512 successProperty : 'success',
22517 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22519 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22522 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22523 * Used by Store query builder to append _requestMeta to params.
22526 metaFromRemote : false,
22528 * This method is only used by a DataProxy which has retrieved data from a remote server.
22529 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22530 * @return {Object} data A data block which is used by an Roo.data.Store object as
22531 * a cache of Roo.data.Records.
22533 read : function(response){
22534 var json = response.responseText;
22536 var o = /* eval:var:o */ eval("("+json+")");
22538 throw {message: "JsonReader.read: Json object not found"};
22544 this.metaFromRemote = true;
22545 this.meta = o.metaData;
22546 this.recordType = Roo.data.Record.create(o.metaData.fields);
22547 this.onMetaChange(this.meta, this.recordType, o);
22549 return this.readRecords(o);
22552 // private function a store will implement
22553 onMetaChange : function(meta, recordType, o){
22560 simpleAccess: function(obj, subsc) {
22567 getJsonAccessor: function(){
22569 return function(expr) {
22571 return(re.test(expr))
22572 ? new Function("obj", "return obj." + expr)
22577 return Roo.emptyFn;
22582 * Create a data block containing Roo.data.Records from an XML document.
22583 * @param {Object} o An object which contains an Array of row objects in the property specified
22584 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22585 * which contains the total size of the dataset.
22586 * @return {Object} data A data block which is used by an Roo.data.Store object as
22587 * a cache of Roo.data.Records.
22589 readRecords : function(o){
22591 * After any data loads, the raw JSON data is available for further custom processing.
22595 var s = this.meta, Record = this.recordType,
22596 f = Record.prototype.fields, fi = f.items, fl = f.length;
22598 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22600 if(s.totalProperty) {
22601 this.getTotal = this.getJsonAccessor(s.totalProperty);
22603 if(s.successProperty) {
22604 this.getSuccess = this.getJsonAccessor(s.successProperty);
22606 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22608 var g = this.getJsonAccessor(s.id);
22609 this.getId = function(rec) {
22611 return (r === undefined || r === "") ? null : r;
22614 this.getId = function(){return null;};
22617 for(var jj = 0; jj < fl; jj++){
22619 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22620 this.ef[jj] = this.getJsonAccessor(map);
22624 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22625 if(s.totalProperty){
22626 var vt = parseInt(this.getTotal(o), 10);
22631 if(s.successProperty){
22632 var vs = this.getSuccess(o);
22633 if(vs === false || vs === 'false'){
22638 for(var i = 0; i < c; i++){
22641 var id = this.getId(n);
22642 for(var j = 0; j < fl; j++){
22644 var v = this.ef[j](n);
22646 Roo.log('missing convert for ' + f.name);
22650 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22652 var record = new Record(values, id);
22654 records[i] = record;
22660 totalRecords : totalRecords
22665 * Ext JS Library 1.1.1
22666 * Copyright(c) 2006-2007, Ext JS, LLC.
22668 * Originally Released Under LGPL - original licence link has changed is not relivant.
22671 * <script type="text/javascript">
22675 * @class Roo.data.XmlReader
22676 * @extends Roo.data.DataReader
22677 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22678 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22680 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22681 * header in the HTTP response must be set to "text/xml".</em>
22685 var RecordDef = Roo.data.Record.create([
22686 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22687 {name: 'occupation'} // This field will use "occupation" as the mapping.
22689 var myReader = new Roo.data.XmlReader({
22690 totalRecords: "results", // The element which contains the total dataset size (optional)
22691 record: "row", // The repeated element which contains row information
22692 id: "id" // The element within the row that provides an ID for the record (optional)
22696 * This would consume an XML file like this:
22700 <results>2</results>
22703 <name>Bill</name>
22704 <occupation>Gardener</occupation>
22708 <name>Ben</name>
22709 <occupation>Horticulturalist</occupation>
22713 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22714 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22715 * paged from the remote server.
22716 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22717 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22718 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22719 * a record identifier value.
22721 * Create a new XmlReader
22722 * @param {Object} meta Metadata configuration options
22723 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22724 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22725 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22727 Roo.data.XmlReader = function(meta, recordType){
22729 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22731 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22733 * This method is only used by a DataProxy which has retrieved data from a remote server.
22734 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22735 * to contain a method called 'responseXML' that returns an XML document object.
22736 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22737 * a cache of Roo.data.Records.
22739 read : function(response){
22740 var doc = response.responseXML;
22742 throw {message: "XmlReader.read: XML Document not available"};
22744 return this.readRecords(doc);
22748 * Create a data block containing Roo.data.Records from an XML document.
22749 * @param {Object} doc A parsed XML document.
22750 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22751 * a cache of Roo.data.Records.
22753 readRecords : function(doc){
22755 * After any data loads/reads, the raw XML Document is available for further custom processing.
22756 * @type XMLDocument
22758 this.xmlData = doc;
22759 var root = doc.documentElement || doc;
22760 var q = Roo.DomQuery;
22761 var recordType = this.recordType, fields = recordType.prototype.fields;
22762 var sid = this.meta.id;
22763 var totalRecords = 0, success = true;
22764 if(this.meta.totalRecords){
22765 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22768 if(this.meta.success){
22769 var sv = q.selectValue(this.meta.success, root, true);
22770 success = sv !== false && sv !== 'false';
22773 var ns = q.select(this.meta.record, root);
22774 for(var i = 0, len = ns.length; i < len; i++) {
22777 var id = sid ? q.selectValue(sid, n) : undefined;
22778 for(var j = 0, jlen = fields.length; j < jlen; j++){
22779 var f = fields.items[j];
22780 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22782 values[f.name] = v;
22784 var record = new recordType(values, id);
22786 records[records.length] = record;
22792 totalRecords : totalRecords || records.length
22797 * Ext JS Library 1.1.1
22798 * Copyright(c) 2006-2007, Ext JS, LLC.
22800 * Originally Released Under LGPL - original licence link has changed is not relivant.
22803 * <script type="text/javascript">
22807 * @class Roo.data.ArrayReader
22808 * @extends Roo.data.DataReader
22809 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22810 * Each element of that Array represents a row of data fields. The
22811 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22812 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22816 var RecordDef = Roo.data.Record.create([
22817 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22818 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22820 var myReader = new Roo.data.ArrayReader({
22821 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22825 * This would consume an Array like this:
22827 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22829 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22831 * Create a new JsonReader
22832 * @param {Object} meta Metadata configuration options.
22833 * @param {Object} recordType Either an Array of field definition objects
22834 * as specified to {@link Roo.data.Record#create},
22835 * or an {@link Roo.data.Record} object
22836 * created using {@link Roo.data.Record#create}.
22838 Roo.data.ArrayReader = function(meta, recordType){
22839 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22842 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22844 * Create a data block containing Roo.data.Records from an XML document.
22845 * @param {Object} o An Array of row objects which represents the dataset.
22846 * @return {Object} data A data block which is used by an Roo.data.Store object as
22847 * a cache of Roo.data.Records.
22849 readRecords : function(o){
22850 var sid = this.meta ? this.meta.id : null;
22851 var recordType = this.recordType, fields = recordType.prototype.fields;
22854 for(var i = 0; i < root.length; i++){
22857 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22858 for(var j = 0, jlen = fields.length; j < jlen; j++){
22859 var f = fields.items[j];
22860 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22861 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22863 values[f.name] = v;
22865 var record = new recordType(values, id);
22867 records[records.length] = record;
22871 totalRecords : records.length
22876 * Ext JS Library 1.1.1
22877 * Copyright(c) 2006-2007, Ext JS, LLC.
22879 * Originally Released Under LGPL - original licence link has changed is not relivant.
22882 * <script type="text/javascript">
22887 * @class Roo.data.Tree
22888 * @extends Roo.util.Observable
22889 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22890 * in the tree have most standard DOM functionality.
22892 * @param {Node} root (optional) The root node
22894 Roo.data.Tree = function(root){
22895 this.nodeHash = {};
22897 * The root node for this tree
22902 this.setRootNode(root);
22907 * Fires when a new child node is appended to a node in this tree.
22908 * @param {Tree} tree The owner tree
22909 * @param {Node} parent The parent node
22910 * @param {Node} node The newly appended node
22911 * @param {Number} index The index of the newly appended node
22916 * Fires when a child node is removed from a node in this tree.
22917 * @param {Tree} tree The owner tree
22918 * @param {Node} parent The parent node
22919 * @param {Node} node The child node removed
22924 * Fires when a node is moved to a new location in the tree
22925 * @param {Tree} tree The owner tree
22926 * @param {Node} node The node moved
22927 * @param {Node} oldParent The old parent of this node
22928 * @param {Node} newParent The new parent of this node
22929 * @param {Number} index The index it was moved to
22934 * Fires when a new child node is inserted in a node in this tree.
22935 * @param {Tree} tree The owner tree
22936 * @param {Node} parent The parent node
22937 * @param {Node} node The child node inserted
22938 * @param {Node} refNode The child node the node was inserted before
22942 * @event beforeappend
22943 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22944 * @param {Tree} tree The owner tree
22945 * @param {Node} parent The parent node
22946 * @param {Node} node The child node to be appended
22948 "beforeappend" : true,
22950 * @event beforeremove
22951 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22952 * @param {Tree} tree The owner tree
22953 * @param {Node} parent The parent node
22954 * @param {Node} node The child node to be removed
22956 "beforeremove" : true,
22958 * @event beforemove
22959 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22960 * @param {Tree} tree The owner tree
22961 * @param {Node} node The node being moved
22962 * @param {Node} oldParent The parent of the node
22963 * @param {Node} newParent The new parent the node is moving to
22964 * @param {Number} index The index it is being moved to
22966 "beforemove" : true,
22968 * @event beforeinsert
22969 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22970 * @param {Tree} tree The owner tree
22971 * @param {Node} parent The parent node
22972 * @param {Node} node The child node to be inserted
22973 * @param {Node} refNode The child node the node is being inserted before
22975 "beforeinsert" : true
22978 Roo.data.Tree.superclass.constructor.call(this);
22981 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22982 pathSeparator: "/",
22984 proxyNodeEvent : function(){
22985 return this.fireEvent.apply(this, arguments);
22989 * Returns the root node for this tree.
22992 getRootNode : function(){
22997 * Sets the root node for this tree.
22998 * @param {Node} node
23001 setRootNode : function(node){
23003 node.ownerTree = this;
23004 node.isRoot = true;
23005 this.registerNode(node);
23010 * Gets a node in this tree by its id.
23011 * @param {String} id
23014 getNodeById : function(id){
23015 return this.nodeHash[id];
23018 registerNode : function(node){
23019 this.nodeHash[node.id] = node;
23022 unregisterNode : function(node){
23023 delete this.nodeHash[node.id];
23026 toString : function(){
23027 return "[Tree"+(this.id?" "+this.id:"")+"]";
23032 * @class Roo.data.Node
23033 * @extends Roo.util.Observable
23034 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23035 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23037 * @param {Object} attributes The attributes/config for the node
23039 Roo.data.Node = function(attributes){
23041 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23044 this.attributes = attributes || {};
23045 this.leaf = this.attributes.leaf;
23047 * The node id. @type String
23049 this.id = this.attributes.id;
23051 this.id = Roo.id(null, "ynode-");
23052 this.attributes.id = this.id;
23057 * All child nodes of this node. @type Array
23059 this.childNodes = [];
23060 if(!this.childNodes.indexOf){ // indexOf is a must
23061 this.childNodes.indexOf = function(o){
23062 for(var i = 0, len = this.length; i < len; i++){
23071 * The parent node for this node. @type Node
23073 this.parentNode = null;
23075 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23077 this.firstChild = null;
23079 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23081 this.lastChild = null;
23083 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23085 this.previousSibling = null;
23087 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23089 this.nextSibling = null;
23094 * Fires when a new child node is appended
23095 * @param {Tree} tree The owner tree
23096 * @param {Node} this This node
23097 * @param {Node} node The newly appended node
23098 * @param {Number} index The index of the newly appended node
23103 * Fires when a child node is removed
23104 * @param {Tree} tree The owner tree
23105 * @param {Node} this This node
23106 * @param {Node} node The removed node
23111 * Fires when this node is moved to a new location in the tree
23112 * @param {Tree} tree The owner tree
23113 * @param {Node} this This node
23114 * @param {Node} oldParent The old parent of this node
23115 * @param {Node} newParent The new parent of this node
23116 * @param {Number} index The index it was moved to
23121 * Fires when a new child node is inserted.
23122 * @param {Tree} tree The owner tree
23123 * @param {Node} this This node
23124 * @param {Node} node The child node inserted
23125 * @param {Node} refNode The child node the node was inserted before
23129 * @event beforeappend
23130 * Fires before a new child is appended, return false to cancel the append.
23131 * @param {Tree} tree The owner tree
23132 * @param {Node} this This node
23133 * @param {Node} node The child node to be appended
23135 "beforeappend" : true,
23137 * @event beforeremove
23138 * Fires before a child is removed, return false to cancel the remove.
23139 * @param {Tree} tree The owner tree
23140 * @param {Node} this This node
23141 * @param {Node} node The child node to be removed
23143 "beforeremove" : true,
23145 * @event beforemove
23146 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23147 * @param {Tree} tree The owner tree
23148 * @param {Node} this This node
23149 * @param {Node} oldParent The parent of this node
23150 * @param {Node} newParent The new parent this node is moving to
23151 * @param {Number} index The index it is being moved to
23153 "beforemove" : true,
23155 * @event beforeinsert
23156 * Fires before a new child is inserted, return false to cancel the insert.
23157 * @param {Tree} tree The owner tree
23158 * @param {Node} this This node
23159 * @param {Node} node The child node to be inserted
23160 * @param {Node} refNode The child node the node is being inserted before
23162 "beforeinsert" : true
23164 this.listeners = this.attributes.listeners;
23165 Roo.data.Node.superclass.constructor.call(this);
23168 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23169 fireEvent : function(evtName){
23170 // first do standard event for this node
23171 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23174 // then bubble it up to the tree if the event wasn't cancelled
23175 var ot = this.getOwnerTree();
23177 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23185 * Returns true if this node is a leaf
23186 * @return {Boolean}
23188 isLeaf : function(){
23189 return this.leaf === true;
23193 setFirstChild : function(node){
23194 this.firstChild = node;
23198 setLastChild : function(node){
23199 this.lastChild = node;
23204 * Returns true if this node is the last child of its parent
23205 * @return {Boolean}
23207 isLast : function(){
23208 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23212 * Returns true if this node is the first child of its parent
23213 * @return {Boolean}
23215 isFirst : function(){
23216 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23219 hasChildNodes : function(){
23220 return !this.isLeaf() && this.childNodes.length > 0;
23224 * Insert node(s) as the last child node of this node.
23225 * @param {Node/Array} node The node or Array of nodes to append
23226 * @return {Node} The appended node if single append, or null if an array was passed
23228 appendChild : function(node){
23230 if(node instanceof Array){
23232 }else if(arguments.length > 1){
23235 // if passed an array or multiple args do them one by one
23237 for(var i = 0, len = multi.length; i < len; i++) {
23238 this.appendChild(multi[i]);
23241 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23244 var index = this.childNodes.length;
23245 var oldParent = node.parentNode;
23246 // it's a move, make sure we move it cleanly
23248 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23251 oldParent.removeChild(node);
23253 index = this.childNodes.length;
23255 this.setFirstChild(node);
23257 this.childNodes.push(node);
23258 node.parentNode = this;
23259 var ps = this.childNodes[index-1];
23261 node.previousSibling = ps;
23262 ps.nextSibling = node;
23264 node.previousSibling = null;
23266 node.nextSibling = null;
23267 this.setLastChild(node);
23268 node.setOwnerTree(this.getOwnerTree());
23269 this.fireEvent("append", this.ownerTree, this, node, index);
23271 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23278 * Removes a child node from this node.
23279 * @param {Node} node The node to remove
23280 * @return {Node} The removed node
23282 removeChild : function(node){
23283 var index = this.childNodes.indexOf(node);
23287 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23291 // remove it from childNodes collection
23292 this.childNodes.splice(index, 1);
23295 if(node.previousSibling){
23296 node.previousSibling.nextSibling = node.nextSibling;
23298 if(node.nextSibling){
23299 node.nextSibling.previousSibling = node.previousSibling;
23302 // update child refs
23303 if(this.firstChild == node){
23304 this.setFirstChild(node.nextSibling);
23306 if(this.lastChild == node){
23307 this.setLastChild(node.previousSibling);
23310 node.setOwnerTree(null);
23311 // clear any references from the node
23312 node.parentNode = null;
23313 node.previousSibling = null;
23314 node.nextSibling = null;
23315 this.fireEvent("remove", this.ownerTree, this, node);
23320 * Inserts the first node before the second node in this nodes childNodes collection.
23321 * @param {Node} node The node to insert
23322 * @param {Node} refNode The node to insert before (if null the node is appended)
23323 * @return {Node} The inserted node
23325 insertBefore : function(node, refNode){
23326 if(!refNode){ // like standard Dom, refNode can be null for append
23327 return this.appendChild(node);
23330 if(node == refNode){
23334 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23337 var index = this.childNodes.indexOf(refNode);
23338 var oldParent = node.parentNode;
23339 var refIndex = index;
23341 // when moving internally, indexes will change after remove
23342 if(oldParent == this && this.childNodes.indexOf(node) < index){
23346 // it's a move, make sure we move it cleanly
23348 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23351 oldParent.removeChild(node);
23354 this.setFirstChild(node);
23356 this.childNodes.splice(refIndex, 0, node);
23357 node.parentNode = this;
23358 var ps = this.childNodes[refIndex-1];
23360 node.previousSibling = ps;
23361 ps.nextSibling = node;
23363 node.previousSibling = null;
23365 node.nextSibling = refNode;
23366 refNode.previousSibling = node;
23367 node.setOwnerTree(this.getOwnerTree());
23368 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23370 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23376 * Returns the child node at the specified index.
23377 * @param {Number} index
23380 item : function(index){
23381 return this.childNodes[index];
23385 * Replaces one child node in this node with another.
23386 * @param {Node} newChild The replacement node
23387 * @param {Node} oldChild The node to replace
23388 * @return {Node} The replaced node
23390 replaceChild : function(newChild, oldChild){
23391 this.insertBefore(newChild, oldChild);
23392 this.removeChild(oldChild);
23397 * Returns the index of a child node
23398 * @param {Node} node
23399 * @return {Number} The index of the node or -1 if it was not found
23401 indexOf : function(child){
23402 return this.childNodes.indexOf(child);
23406 * Returns the tree this node is in.
23409 getOwnerTree : function(){
23410 // if it doesn't have one, look for one
23411 if(!this.ownerTree){
23415 this.ownerTree = p.ownerTree;
23421 return this.ownerTree;
23425 * Returns depth of this node (the root node has a depth of 0)
23428 getDepth : function(){
23431 while(p.parentNode){
23439 setOwnerTree : function(tree){
23440 // if it's move, we need to update everyone
23441 if(tree != this.ownerTree){
23442 if(this.ownerTree){
23443 this.ownerTree.unregisterNode(this);
23445 this.ownerTree = tree;
23446 var cs = this.childNodes;
23447 for(var i = 0, len = cs.length; i < len; i++) {
23448 cs[i].setOwnerTree(tree);
23451 tree.registerNode(this);
23457 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23458 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23459 * @return {String} The path
23461 getPath : function(attr){
23462 attr = attr || "id";
23463 var p = this.parentNode;
23464 var b = [this.attributes[attr]];
23466 b.unshift(p.attributes[attr]);
23469 var sep = this.getOwnerTree().pathSeparator;
23470 return sep + b.join(sep);
23474 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23475 * function call will be the scope provided or the current node. The arguments to the function
23476 * will be the args provided or the current node. If the function returns false at any point,
23477 * the bubble is stopped.
23478 * @param {Function} fn The function to call
23479 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23480 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23482 bubble : function(fn, scope, args){
23485 if(fn.call(scope || p, args || p) === false){
23493 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23494 * function call will be the scope provided or the current node. The arguments to the function
23495 * will be the args provided or the current node. If the function returns false at any point,
23496 * the cascade is stopped on that branch.
23497 * @param {Function} fn The function to call
23498 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23499 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23501 cascade : function(fn, scope, args){
23502 if(fn.call(scope || this, args || this) !== false){
23503 var cs = this.childNodes;
23504 for(var i = 0, len = cs.length; i < len; i++) {
23505 cs[i].cascade(fn, scope, args);
23511 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23512 * function call will be the scope provided or the current node. The arguments to the function
23513 * will be the args provided or the current node. If the function returns false at any point,
23514 * the iteration stops.
23515 * @param {Function} fn The function to call
23516 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23517 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23519 eachChild : function(fn, scope, args){
23520 var cs = this.childNodes;
23521 for(var i = 0, len = cs.length; i < len; i++) {
23522 if(fn.call(scope || this, args || cs[i]) === false){
23529 * Finds the first child that has the attribute with the specified value.
23530 * @param {String} attribute The attribute name
23531 * @param {Mixed} value The value to search for
23532 * @return {Node} The found child or null if none was found
23534 findChild : function(attribute, value){
23535 var cs = this.childNodes;
23536 for(var i = 0, len = cs.length; i < len; i++) {
23537 if(cs[i].attributes[attribute] == value){
23545 * Finds the first child by a custom function. The child matches if the function passed
23547 * @param {Function} fn
23548 * @param {Object} scope (optional)
23549 * @return {Node} The found child or null if none was found
23551 findChildBy : function(fn, scope){
23552 var cs = this.childNodes;
23553 for(var i = 0, len = cs.length; i < len; i++) {
23554 if(fn.call(scope||cs[i], cs[i]) === true){
23562 * Sorts this nodes children using the supplied sort function
23563 * @param {Function} fn
23564 * @param {Object} scope (optional)
23566 sort : function(fn, scope){
23567 var cs = this.childNodes;
23568 var len = cs.length;
23570 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23572 for(var i = 0; i < len; i++){
23574 n.previousSibling = cs[i-1];
23575 n.nextSibling = cs[i+1];
23577 this.setFirstChild(n);
23580 this.setLastChild(n);
23587 * Returns true if this node is an ancestor (at any point) of the passed node.
23588 * @param {Node} node
23589 * @return {Boolean}
23591 contains : function(node){
23592 return node.isAncestor(this);
23596 * Returns true if the passed node is an ancestor (at any point) of this node.
23597 * @param {Node} node
23598 * @return {Boolean}
23600 isAncestor : function(node){
23601 var p = this.parentNode;
23611 toString : function(){
23612 return "[Node"+(this.id?" "+this.id:"")+"]";
23616 * Ext JS Library 1.1.1
23617 * Copyright(c) 2006-2007, Ext JS, LLC.
23619 * Originally Released Under LGPL - original licence link has changed is not relivant.
23622 * <script type="text/javascript">
23627 * @extends Roo.Element
23628 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23629 * automatic maintaining of shadow/shim positions.
23630 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23631 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23632 * you can pass a string with a CSS class name. False turns off the shadow.
23633 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23634 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23635 * @cfg {String} cls CSS class to add to the element
23636 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23637 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23639 * @param {Object} config An object with config options.
23640 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23643 Roo.Layer = function(config, existingEl){
23644 config = config || {};
23645 var dh = Roo.DomHelper;
23646 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23648 this.dom = Roo.getDom(existingEl);
23651 var o = config.dh || {tag: "div", cls: "x-layer"};
23652 this.dom = dh.append(pel, o);
23655 this.addClass(config.cls);
23657 this.constrain = config.constrain !== false;
23658 this.visibilityMode = Roo.Element.VISIBILITY;
23660 this.id = this.dom.id = config.id;
23662 this.id = Roo.id(this.dom);
23664 this.zindex = config.zindex || this.getZIndex();
23665 this.position("absolute", this.zindex);
23667 this.shadowOffset = config.shadowOffset || 4;
23668 this.shadow = new Roo.Shadow({
23669 offset : this.shadowOffset,
23670 mode : config.shadow
23673 this.shadowOffset = 0;
23675 this.useShim = config.shim !== false && Roo.useShims;
23676 this.useDisplay = config.useDisplay;
23680 var supr = Roo.Element.prototype;
23682 // shims are shared among layer to keep from having 100 iframes
23685 Roo.extend(Roo.Layer, Roo.Element, {
23687 getZIndex : function(){
23688 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23691 getShim : function(){
23698 var shim = shims.shift();
23700 shim = this.createShim();
23701 shim.enableDisplayMode('block');
23702 shim.dom.style.display = 'none';
23703 shim.dom.style.visibility = 'visible';
23705 var pn = this.dom.parentNode;
23706 if(shim.dom.parentNode != pn){
23707 pn.insertBefore(shim.dom, this.dom);
23709 shim.setStyle('z-index', this.getZIndex()-2);
23714 hideShim : function(){
23716 this.shim.setDisplayed(false);
23717 shims.push(this.shim);
23722 disableShadow : function(){
23724 this.shadowDisabled = true;
23725 this.shadow.hide();
23726 this.lastShadowOffset = this.shadowOffset;
23727 this.shadowOffset = 0;
23731 enableShadow : function(show){
23733 this.shadowDisabled = false;
23734 this.shadowOffset = this.lastShadowOffset;
23735 delete this.lastShadowOffset;
23743 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23744 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23745 sync : function(doShow){
23746 var sw = this.shadow;
23747 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23748 var sh = this.getShim();
23750 var w = this.getWidth(),
23751 h = this.getHeight();
23753 var l = this.getLeft(true),
23754 t = this.getTop(true);
23756 if(sw && !this.shadowDisabled){
23757 if(doShow && !sw.isVisible()){
23760 sw.realign(l, t, w, h);
23766 // fit the shim behind the shadow, so it is shimmed too
23767 var a = sw.adjusts, s = sh.dom.style;
23768 s.left = (Math.min(l, l+a.l))+"px";
23769 s.top = (Math.min(t, t+a.t))+"px";
23770 s.width = (w+a.w)+"px";
23771 s.height = (h+a.h)+"px";
23778 sh.setLeftTop(l, t);
23785 destroy : function(){
23788 this.shadow.hide();
23790 this.removeAllListeners();
23791 var pn = this.dom.parentNode;
23793 pn.removeChild(this.dom);
23795 Roo.Element.uncache(this.id);
23798 remove : function(){
23803 beginUpdate : function(){
23804 this.updating = true;
23808 endUpdate : function(){
23809 this.updating = false;
23814 hideUnders : function(negOffset){
23816 this.shadow.hide();
23822 constrainXY : function(){
23823 if(this.constrain){
23824 var vw = Roo.lib.Dom.getViewWidth(),
23825 vh = Roo.lib.Dom.getViewHeight();
23826 var s = Roo.get(document).getScroll();
23828 var xy = this.getXY();
23829 var x = xy[0], y = xy[1];
23830 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23831 // only move it if it needs it
23833 // first validate right/bottom
23834 if((x + w) > vw+s.left){
23835 x = vw - w - this.shadowOffset;
23838 if((y + h) > vh+s.top){
23839 y = vh - h - this.shadowOffset;
23842 // then make sure top/left isn't negative
23853 var ay = this.avoidY;
23854 if(y <= ay && (y+h) >= ay){
23860 supr.setXY.call(this, xy);
23866 isVisible : function(){
23867 return this.visible;
23871 showAction : function(){
23872 this.visible = true; // track visibility to prevent getStyle calls
23873 if(this.useDisplay === true){
23874 this.setDisplayed("");
23875 }else if(this.lastXY){
23876 supr.setXY.call(this, this.lastXY);
23877 }else if(this.lastLT){
23878 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23883 hideAction : function(){
23884 this.visible = false;
23885 if(this.useDisplay === true){
23886 this.setDisplayed(false);
23888 this.setLeftTop(-10000,-10000);
23892 // overridden Element method
23893 setVisible : function(v, a, d, c, e){
23898 var cb = function(){
23903 }.createDelegate(this);
23904 supr.setVisible.call(this, true, true, d, cb, e);
23907 this.hideUnders(true);
23916 }.createDelegate(this);
23918 supr.setVisible.call(this, v, a, d, cb, e);
23927 storeXY : function(xy){
23928 delete this.lastLT;
23932 storeLeftTop : function(left, top){
23933 delete this.lastXY;
23934 this.lastLT = [left, top];
23938 beforeFx : function(){
23939 this.beforeAction();
23940 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23944 afterFx : function(){
23945 Roo.Layer.superclass.afterFx.apply(this, arguments);
23946 this.sync(this.isVisible());
23950 beforeAction : function(){
23951 if(!this.updating && this.shadow){
23952 this.shadow.hide();
23956 // overridden Element method
23957 setLeft : function(left){
23958 this.storeLeftTop(left, this.getTop(true));
23959 supr.setLeft.apply(this, arguments);
23963 setTop : function(top){
23964 this.storeLeftTop(this.getLeft(true), top);
23965 supr.setTop.apply(this, arguments);
23969 setLeftTop : function(left, top){
23970 this.storeLeftTop(left, top);
23971 supr.setLeftTop.apply(this, arguments);
23975 setXY : function(xy, a, d, c, e){
23977 this.beforeAction();
23979 var cb = this.createCB(c);
23980 supr.setXY.call(this, xy, a, d, cb, e);
23987 createCB : function(c){
23998 // overridden Element method
23999 setX : function(x, a, d, c, e){
24000 this.setXY([x, this.getY()], a, d, c, e);
24003 // overridden Element method
24004 setY : function(y, a, d, c, e){
24005 this.setXY([this.getX(), y], a, d, c, e);
24008 // overridden Element method
24009 setSize : function(w, h, a, d, c, e){
24010 this.beforeAction();
24011 var cb = this.createCB(c);
24012 supr.setSize.call(this, w, h, a, d, cb, e);
24018 // overridden Element method
24019 setWidth : function(w, a, d, c, e){
24020 this.beforeAction();
24021 var cb = this.createCB(c);
24022 supr.setWidth.call(this, w, a, d, cb, e);
24028 // overridden Element method
24029 setHeight : function(h, a, d, c, e){
24030 this.beforeAction();
24031 var cb = this.createCB(c);
24032 supr.setHeight.call(this, h, a, d, cb, e);
24038 // overridden Element method
24039 setBounds : function(x, y, w, h, a, d, c, e){
24040 this.beforeAction();
24041 var cb = this.createCB(c);
24043 this.storeXY([x, y]);
24044 supr.setXY.call(this, [x, y]);
24045 supr.setSize.call(this, w, h, a, d, cb, e);
24048 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24054 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24055 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24056 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24057 * @param {Number} zindex The new z-index to set
24058 * @return {this} The Layer
24060 setZIndex : function(zindex){
24061 this.zindex = zindex;
24062 this.setStyle("z-index", zindex + 2);
24064 this.shadow.setZIndex(zindex + 1);
24067 this.shim.setStyle("z-index", zindex);
24073 * Ext JS Library 1.1.1
24074 * Copyright(c) 2006-2007, Ext JS, LLC.
24076 * Originally Released Under LGPL - original licence link has changed is not relivant.
24079 * <script type="text/javascript">
24084 * @class Roo.Shadow
24085 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24086 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24087 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24089 * Create a new Shadow
24090 * @param {Object} config The config object
24092 Roo.Shadow = function(config){
24093 Roo.apply(this, config);
24094 if(typeof this.mode != "string"){
24095 this.mode = this.defaultMode;
24097 var o = this.offset, a = {h: 0};
24098 var rad = Math.floor(this.offset/2);
24099 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24105 a.l -= this.offset + rad;
24106 a.t -= this.offset + rad;
24117 a.l -= (this.offset - rad);
24118 a.t -= this.offset + rad;
24120 a.w -= (this.offset - rad)*2;
24131 a.l -= (this.offset - rad);
24132 a.t -= (this.offset - rad);
24134 a.w -= (this.offset + rad + 1);
24135 a.h -= (this.offset + rad);
24144 Roo.Shadow.prototype = {
24146 * @cfg {String} mode
24147 * The shadow display mode. Supports the following options:<br />
24148 * sides: Shadow displays on both sides and bottom only<br />
24149 * frame: Shadow displays equally on all four sides<br />
24150 * drop: Traditional bottom-right drop shadow (default)
24153 * @cfg {String} offset
24154 * The number of pixels to offset the shadow from the element (defaults to 4)
24159 defaultMode: "drop",
24162 * Displays the shadow under the target element
24163 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24165 show : function(target){
24166 target = Roo.get(target);
24168 this.el = Roo.Shadow.Pool.pull();
24169 if(this.el.dom.nextSibling != target.dom){
24170 this.el.insertBefore(target);
24173 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24175 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24178 target.getLeft(true),
24179 target.getTop(true),
24183 this.el.dom.style.display = "block";
24187 * Returns true if the shadow is visible, else false
24189 isVisible : function(){
24190 return this.el ? true : false;
24194 * Direct alignment when values are already available. Show must be called at least once before
24195 * calling this method to ensure it is initialized.
24196 * @param {Number} left The target element left position
24197 * @param {Number} top The target element top position
24198 * @param {Number} width The target element width
24199 * @param {Number} height The target element height
24201 realign : function(l, t, w, h){
24205 var a = this.adjusts, d = this.el.dom, s = d.style;
24207 s.left = (l+a.l)+"px";
24208 s.top = (t+a.t)+"px";
24209 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24211 if(s.width != sws || s.height != shs){
24215 var cn = d.childNodes;
24216 var sww = Math.max(0, (sw-12))+"px";
24217 cn[0].childNodes[1].style.width = sww;
24218 cn[1].childNodes[1].style.width = sww;
24219 cn[2].childNodes[1].style.width = sww;
24220 cn[1].style.height = Math.max(0, (sh-12))+"px";
24226 * Hides this shadow
24230 this.el.dom.style.display = "none";
24231 Roo.Shadow.Pool.push(this.el);
24237 * Adjust the z-index of this shadow
24238 * @param {Number} zindex The new z-index
24240 setZIndex : function(z){
24243 this.el.setStyle("z-index", z);
24248 // Private utility class that manages the internal Shadow cache
24249 Roo.Shadow.Pool = function(){
24251 var markup = Roo.isIE ?
24252 '<div class="x-ie-shadow"></div>' :
24253 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
24256 var sh = p.shift();
24258 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24259 sh.autoBoxAdjust = false;
24264 push : function(sh){
24270 * Ext JS Library 1.1.1
24271 * Copyright(c) 2006-2007, Ext JS, LLC.
24273 * Originally Released Under LGPL - original licence link has changed is not relivant.
24276 * <script type="text/javascript">
24281 * @class Roo.SplitBar
24282 * @extends Roo.util.Observable
24283 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24287 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24288 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24289 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24290 split.minSize = 100;
24291 split.maxSize = 600;
24292 split.animate = true;
24293 split.on('moved', splitterMoved);
24296 * Create a new SplitBar
24297 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24298 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24299 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24300 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24301 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24302 position of the SplitBar).
24304 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24307 this.el = Roo.get(dragElement, true);
24308 this.el.dom.unselectable = "on";
24310 this.resizingEl = Roo.get(resizingElement, true);
24314 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24315 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24318 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24321 * The minimum size of the resizing element. (Defaults to 0)
24327 * The maximum size of the resizing element. (Defaults to 2000)
24330 this.maxSize = 2000;
24333 * Whether to animate the transition to the new size
24336 this.animate = false;
24339 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24342 this.useShim = false;
24347 if(!existingProxy){
24349 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24351 this.proxy = Roo.get(existingProxy).dom;
24354 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24357 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24360 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24363 this.dragSpecs = {};
24366 * @private The adapter to use to positon and resize elements
24368 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24369 this.adapter.init(this);
24371 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24373 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24374 this.el.addClass("x-splitbar-h");
24377 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24378 this.el.addClass("x-splitbar-v");
24384 * Fires when the splitter is moved (alias for {@link #event-moved})
24385 * @param {Roo.SplitBar} this
24386 * @param {Number} newSize the new width or height
24391 * Fires when the splitter is moved
24392 * @param {Roo.SplitBar} this
24393 * @param {Number} newSize the new width or height
24397 * @event beforeresize
24398 * Fires before the splitter is dragged
24399 * @param {Roo.SplitBar} this
24401 "beforeresize" : true,
24403 "beforeapply" : true
24406 Roo.util.Observable.call(this);
24409 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24410 onStartProxyDrag : function(x, y){
24411 this.fireEvent("beforeresize", this);
24413 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24415 o.enableDisplayMode("block");
24416 // all splitbars share the same overlay
24417 Roo.SplitBar.prototype.overlay = o;
24419 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24420 this.overlay.show();
24421 Roo.get(this.proxy).setDisplayed("block");
24422 var size = this.adapter.getElementSize(this);
24423 this.activeMinSize = this.getMinimumSize();;
24424 this.activeMaxSize = this.getMaximumSize();;
24425 var c1 = size - this.activeMinSize;
24426 var c2 = Math.max(this.activeMaxSize - size, 0);
24427 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24428 this.dd.resetConstraints();
24429 this.dd.setXConstraint(
24430 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24431 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24433 this.dd.setYConstraint(0, 0);
24435 this.dd.resetConstraints();
24436 this.dd.setXConstraint(0, 0);
24437 this.dd.setYConstraint(
24438 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24439 this.placement == Roo.SplitBar.TOP ? c2 : c1
24442 this.dragSpecs.startSize = size;
24443 this.dragSpecs.startPoint = [x, y];
24444 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24448 * @private Called after the drag operation by the DDProxy
24450 onEndProxyDrag : function(e){
24451 Roo.get(this.proxy).setDisplayed(false);
24452 var endPoint = Roo.lib.Event.getXY(e);
24454 this.overlay.hide();
24457 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24458 newSize = this.dragSpecs.startSize +
24459 (this.placement == Roo.SplitBar.LEFT ?
24460 endPoint[0] - this.dragSpecs.startPoint[0] :
24461 this.dragSpecs.startPoint[0] - endPoint[0]
24464 newSize = this.dragSpecs.startSize +
24465 (this.placement == Roo.SplitBar.TOP ?
24466 endPoint[1] - this.dragSpecs.startPoint[1] :
24467 this.dragSpecs.startPoint[1] - endPoint[1]
24470 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24471 if(newSize != this.dragSpecs.startSize){
24472 if(this.fireEvent('beforeapply', this, newSize) !== false){
24473 this.adapter.setElementSize(this, newSize);
24474 this.fireEvent("moved", this, newSize);
24475 this.fireEvent("resize", this, newSize);
24481 * Get the adapter this SplitBar uses
24482 * @return The adapter object
24484 getAdapter : function(){
24485 return this.adapter;
24489 * Set the adapter this SplitBar uses
24490 * @param {Object} adapter A SplitBar adapter object
24492 setAdapter : function(adapter){
24493 this.adapter = adapter;
24494 this.adapter.init(this);
24498 * Gets the minimum size for the resizing element
24499 * @return {Number} The minimum size
24501 getMinimumSize : function(){
24502 return this.minSize;
24506 * Sets the minimum size for the resizing element
24507 * @param {Number} minSize The minimum size
24509 setMinimumSize : function(minSize){
24510 this.minSize = minSize;
24514 * Gets the maximum size for the resizing element
24515 * @return {Number} The maximum size
24517 getMaximumSize : function(){
24518 return this.maxSize;
24522 * Sets the maximum size for the resizing element
24523 * @param {Number} maxSize The maximum size
24525 setMaximumSize : function(maxSize){
24526 this.maxSize = maxSize;
24530 * Sets the initialize size for the resizing element
24531 * @param {Number} size The initial size
24533 setCurrentSize : function(size){
24534 var oldAnimate = this.animate;
24535 this.animate = false;
24536 this.adapter.setElementSize(this, size);
24537 this.animate = oldAnimate;
24541 * Destroy this splitbar.
24542 * @param {Boolean} removeEl True to remove the element
24544 destroy : function(removeEl){
24546 this.shim.remove();
24549 this.proxy.parentNode.removeChild(this.proxy);
24557 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
24559 Roo.SplitBar.createProxy = function(dir){
24560 var proxy = new Roo.Element(document.createElement("div"));
24561 proxy.unselectable();
24562 var cls = 'x-splitbar-proxy';
24563 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24564 document.body.appendChild(proxy.dom);
24569 * @class Roo.SplitBar.BasicLayoutAdapter
24570 * Default Adapter. It assumes the splitter and resizing element are not positioned
24571 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24573 Roo.SplitBar.BasicLayoutAdapter = function(){
24576 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24577 // do nothing for now
24578 init : function(s){
24582 * Called before drag operations to get the current size of the resizing element.
24583 * @param {Roo.SplitBar} s The SplitBar using this adapter
24585 getElementSize : function(s){
24586 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24587 return s.resizingEl.getWidth();
24589 return s.resizingEl.getHeight();
24594 * Called after drag operations to set the size of the resizing element.
24595 * @param {Roo.SplitBar} s The SplitBar using this adapter
24596 * @param {Number} newSize The new size to set
24597 * @param {Function} onComplete A function to be invoked when resizing is complete
24599 setElementSize : function(s, newSize, onComplete){
24600 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24602 s.resizingEl.setWidth(newSize);
24604 onComplete(s, newSize);
24607 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24612 s.resizingEl.setHeight(newSize);
24614 onComplete(s, newSize);
24617 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24624 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24625 * @extends Roo.SplitBar.BasicLayoutAdapter
24626 * Adapter that moves the splitter element to align with the resized sizing element.
24627 * Used with an absolute positioned SplitBar.
24628 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24629 * document.body, make sure you assign an id to the body element.
24631 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24632 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24633 this.container = Roo.get(container);
24636 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24637 init : function(s){
24638 this.basic.init(s);
24641 getElementSize : function(s){
24642 return this.basic.getElementSize(s);
24645 setElementSize : function(s, newSize, onComplete){
24646 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24649 moveSplitter : function(s){
24650 var yes = Roo.SplitBar;
24651 switch(s.placement){
24653 s.el.setX(s.resizingEl.getRight());
24656 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24659 s.el.setY(s.resizingEl.getBottom());
24662 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24669 * Orientation constant - Create a vertical SplitBar
24673 Roo.SplitBar.VERTICAL = 1;
24676 * Orientation constant - Create a horizontal SplitBar
24680 Roo.SplitBar.HORIZONTAL = 2;
24683 * Placement constant - The resizing element is to the left of the splitter element
24687 Roo.SplitBar.LEFT = 1;
24690 * Placement constant - The resizing element is to the right of the splitter element
24694 Roo.SplitBar.RIGHT = 2;
24697 * Placement constant - The resizing element is positioned above the splitter element
24701 Roo.SplitBar.TOP = 3;
24704 * Placement constant - The resizing element is positioned under splitter element
24708 Roo.SplitBar.BOTTOM = 4;
24711 * Ext JS Library 1.1.1
24712 * Copyright(c) 2006-2007, Ext JS, LLC.
24714 * Originally Released Under LGPL - original licence link has changed is not relivant.
24717 * <script type="text/javascript">
24722 * @extends Roo.util.Observable
24723 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24724 * This class also supports single and multi selection modes. <br>
24725 * Create a data model bound view:
24727 var store = new Roo.data.Store(...);
24729 var view = new Roo.View({
24731 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24733 singleSelect: true,
24734 selectedClass: "ydataview-selected",
24738 // listen for node click?
24739 view.on("click", function(vw, index, node, e){
24740 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24744 dataModel.load("foobar.xml");
24746 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24748 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24749 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24751 * Note: old style constructor is still suported (container, template, config)
24754 * Create a new View
24755 * @param {Object} config The config object
24758 Roo.View = function(config, depreciated_tpl, depreciated_config){
24760 if (typeof(depreciated_tpl) == 'undefined') {
24761 // new way.. - universal constructor.
24762 Roo.apply(this, config);
24763 this.el = Roo.get(this.el);
24766 this.el = Roo.get(config);
24767 this.tpl = depreciated_tpl;
24768 Roo.apply(this, depreciated_config);
24770 this.wrapEl = this.el.wrap().wrap();
24771 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24774 if(typeof(this.tpl) == "string"){
24775 this.tpl = new Roo.Template(this.tpl);
24777 // support xtype ctors..
24778 this.tpl = new Roo.factory(this.tpl, Roo);
24782 this.tpl.compile();
24790 * @event beforeclick
24791 * Fires before a click is processed. Returns false to cancel the default action.
24792 * @param {Roo.View} this
24793 * @param {Number} index The index of the target node
24794 * @param {HTMLElement} node The target node
24795 * @param {Roo.EventObject} e The raw event object
24797 "beforeclick" : true,
24800 * Fires when a template node is clicked.
24801 * @param {Roo.View} this
24802 * @param {Number} index The index of the target node
24803 * @param {HTMLElement} node The target node
24804 * @param {Roo.EventObject} e The raw event object
24809 * Fires when a template node is double clicked.
24810 * @param {Roo.View} this
24811 * @param {Number} index The index of the target node
24812 * @param {HTMLElement} node The target node
24813 * @param {Roo.EventObject} e The raw event object
24817 * @event contextmenu
24818 * Fires when a template node is right clicked.
24819 * @param {Roo.View} this
24820 * @param {Number} index The index of the target node
24821 * @param {HTMLElement} node The target node
24822 * @param {Roo.EventObject} e The raw event object
24824 "contextmenu" : true,
24826 * @event selectionchange
24827 * Fires when the selected nodes change.
24828 * @param {Roo.View} this
24829 * @param {Array} selections Array of the selected nodes
24831 "selectionchange" : true,
24834 * @event beforeselect
24835 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24836 * @param {Roo.View} this
24837 * @param {HTMLElement} node The node to be selected
24838 * @param {Array} selections Array of currently selected nodes
24840 "beforeselect" : true,
24842 * @event preparedata
24843 * Fires on every row to render, to allow you to change the data.
24844 * @param {Roo.View} this
24845 * @param {Object} data to be rendered (change this)
24847 "preparedata" : true
24855 "click": this.onClick,
24856 "dblclick": this.onDblClick,
24857 "contextmenu": this.onContextMenu,
24861 this.selections = [];
24863 this.cmp = new Roo.CompositeElementLite([]);
24865 this.store = Roo.factory(this.store, Roo.data);
24866 this.setStore(this.store, true);
24869 if ( this.footer && this.footer.xtype) {
24871 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24873 this.footer.dataSource = this.store
24874 this.footer.container = fctr;
24875 this.footer = Roo.factory(this.footer, Roo);
24876 fctr.insertFirst(this.el);
24878 // this is a bit insane - as the paging toolbar seems to detach the el..
24879 // dom.parentNode.parentNode.parentNode
24880 // they get detached?
24884 Roo.View.superclass.constructor.call(this);
24889 Roo.extend(Roo.View, Roo.util.Observable, {
24892 * @cfg {Roo.data.Store} store Data store to load data from.
24897 * @cfg {String|Roo.Element} el The container element.
24902 * @cfg {String|Roo.Template} tpl The template used by this View
24906 * @cfg {String} dataName the named area of the template to use as the data area
24907 * Works with domtemplates roo-name="name"
24911 * @cfg {String} selectedClass The css class to add to selected nodes
24913 selectedClass : "x-view-selected",
24915 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24920 * @cfg {String} text to display on mask (default Loading)
24924 * @cfg {Boolean} multiSelect Allow multiple selection
24926 multiSelect : false,
24928 * @cfg {Boolean} singleSelect Allow single selection
24930 singleSelect: false,
24933 * @cfg {Boolean} toggleSelect - selecting
24935 toggleSelect : false,
24938 * Returns the element this view is bound to.
24939 * @return {Roo.Element}
24941 getEl : function(){
24942 return this.wrapEl;
24948 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24950 refresh : function(){
24951 Roo.log('refresh');
24954 // if we are using something like 'domtemplate', then
24955 // the what gets used is:
24956 // t.applySubtemplate(NAME, data, wrapping data..)
24957 // the outer template then get' applied with
24958 // the store 'extra data'
24959 // and the body get's added to the
24960 // roo-name="data" node?
24961 // <span class='roo-tpl-{name}'></span> ?????
24965 this.clearSelections();
24966 this.el.update("");
24968 var records = this.store.getRange();
24969 if(records.length < 1) {
24971 // is this valid?? = should it render a template??
24973 this.el.update(this.emptyText);
24977 if (this.dataName) {
24978 this.el.update(t.apply(this.store.meta)); //????
24979 el = this.el.child('.roo-tpl-' + this.dataName);
24982 for(var i = 0, len = records.length; i < len; i++){
24983 var data = this.prepareData(records[i].data, i, records[i]);
24984 this.fireEvent("preparedata", this, data, i, records[i]);
24985 html[html.length] = Roo.util.Format.trim(
24987 t.applySubtemplate(this.dataName, data, this.store.meta) :
24994 el.update(html.join(""));
24995 this.nodes = el.dom.childNodes;
24996 this.updateIndexes(0);
25001 * Function to override to reformat the data that is sent to
25002 * the template for each node.
25003 * DEPRICATED - use the preparedata event handler.
25004 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25005 * a JSON object for an UpdateManager bound view).
25007 prepareData : function(data, index, record)
25009 this.fireEvent("preparedata", this, data, index, record);
25013 onUpdate : function(ds, record){
25014 Roo.log('on update');
25015 this.clearSelections();
25016 var index = this.store.indexOf(record);
25017 var n = this.nodes[index];
25018 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25019 n.parentNode.removeChild(n);
25020 this.updateIndexes(index, index);
25026 onAdd : function(ds, records, index)
25028 Roo.log(['on Add', ds, records, index] );
25029 this.clearSelections();
25030 if(this.nodes.length == 0){
25034 var n = this.nodes[index];
25035 for(var i = 0, len = records.length; i < len; i++){
25036 var d = this.prepareData(records[i].data, i, records[i]);
25038 this.tpl.insertBefore(n, d);
25041 this.tpl.append(this.el, d);
25044 this.updateIndexes(index);
25047 onRemove : function(ds, record, index){
25048 Roo.log('onRemove');
25049 this.clearSelections();
25050 var el = this.dataName ?
25051 this.el.child('.roo-tpl-' + this.dataName) :
25054 el.dom.removeChild(this.nodes[index]);
25055 this.updateIndexes(index);
25059 * Refresh an individual node.
25060 * @param {Number} index
25062 refreshNode : function(index){
25063 this.onUpdate(this.store, this.store.getAt(index));
25066 updateIndexes : function(startIndex, endIndex){
25067 var ns = this.nodes;
25068 startIndex = startIndex || 0;
25069 endIndex = endIndex || ns.length - 1;
25070 for(var i = startIndex; i <= endIndex; i++){
25071 ns[i].nodeIndex = i;
25076 * Changes the data store this view uses and refresh the view.
25077 * @param {Store} store
25079 setStore : function(store, initial){
25080 if(!initial && this.store){
25081 this.store.un("datachanged", this.refresh);
25082 this.store.un("add", this.onAdd);
25083 this.store.un("remove", this.onRemove);
25084 this.store.un("update", this.onUpdate);
25085 this.store.un("clear", this.refresh);
25086 this.store.un("beforeload", this.onBeforeLoad);
25087 this.store.un("load", this.onLoad);
25088 this.store.un("loadexception", this.onLoad);
25092 store.on("datachanged", this.refresh, this);
25093 store.on("add", this.onAdd, this);
25094 store.on("remove", this.onRemove, this);
25095 store.on("update", this.onUpdate, this);
25096 store.on("clear", this.refresh, this);
25097 store.on("beforeload", this.onBeforeLoad, this);
25098 store.on("load", this.onLoad, this);
25099 store.on("loadexception", this.onLoad, this);
25107 * onbeforeLoad - masks the loading area.
25110 onBeforeLoad : function(store,opts)
25112 Roo.log('onBeforeLoad');
25114 this.el.update("");
25116 this.el.mask(this.mask ? this.mask : "Loading" );
25118 onLoad : function ()
25125 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25126 * @param {HTMLElement} node
25127 * @return {HTMLElement} The template node
25129 findItemFromChild : function(node){
25130 var el = this.dataName ?
25131 this.el.child('.roo-tpl-' + this.dataName,true) :
25134 if(!node || node.parentNode == el){
25137 var p = node.parentNode;
25138 while(p && p != el){
25139 if(p.parentNode == el){
25148 onClick : function(e){
25149 var item = this.findItemFromChild(e.getTarget());
25151 var index = this.indexOf(item);
25152 if(this.onItemClick(item, index, e) !== false){
25153 this.fireEvent("click", this, index, item, e);
25156 this.clearSelections();
25161 onContextMenu : function(e){
25162 var item = this.findItemFromChild(e.getTarget());
25164 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25169 onDblClick : function(e){
25170 var item = this.findItemFromChild(e.getTarget());
25172 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25176 onItemClick : function(item, index, e)
25178 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25181 if (this.toggleSelect) {
25182 var m = this.isSelected(item) ? 'unselect' : 'select';
25185 _t[m](item, true, false);
25188 if(this.multiSelect || this.singleSelect){
25189 if(this.multiSelect && e.shiftKey && this.lastSelection){
25190 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25192 this.select(item, this.multiSelect && e.ctrlKey);
25193 this.lastSelection = item;
25195 e.preventDefault();
25201 * Get the number of selected nodes.
25204 getSelectionCount : function(){
25205 return this.selections.length;
25209 * Get the currently selected nodes.
25210 * @return {Array} An array of HTMLElements
25212 getSelectedNodes : function(){
25213 return this.selections;
25217 * Get the indexes of the selected nodes.
25220 getSelectedIndexes : function(){
25221 var indexes = [], s = this.selections;
25222 for(var i = 0, len = s.length; i < len; i++){
25223 indexes.push(s[i].nodeIndex);
25229 * Clear all selections
25230 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25232 clearSelections : function(suppressEvent){
25233 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25234 this.cmp.elements = this.selections;
25235 this.cmp.removeClass(this.selectedClass);
25236 this.selections = [];
25237 if(!suppressEvent){
25238 this.fireEvent("selectionchange", this, this.selections);
25244 * Returns true if the passed node is selected
25245 * @param {HTMLElement/Number} node The node or node index
25246 * @return {Boolean}
25248 isSelected : function(node){
25249 var s = this.selections;
25253 node = this.getNode(node);
25254 return s.indexOf(node) !== -1;
25259 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
25260 * @param {Boolean} keepExisting (optional) true to keep existing selections
25261 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25263 select : function(nodeInfo, keepExisting, suppressEvent){
25264 if(nodeInfo instanceof Array){
25266 this.clearSelections(true);
25268 for(var i = 0, len = nodeInfo.length; i < len; i++){
25269 this.select(nodeInfo[i], true, true);
25273 var node = this.getNode(nodeInfo);
25274 if(!node || this.isSelected(node)){
25275 return; // already selected.
25278 this.clearSelections(true);
25280 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25281 Roo.fly(node).addClass(this.selectedClass);
25282 this.selections.push(node);
25283 if(!suppressEvent){
25284 this.fireEvent("selectionchange", this, this.selections);
25292 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
25293 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25294 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25296 unselect : function(nodeInfo, keepExisting, suppressEvent)
25298 if(nodeInfo instanceof Array){
25299 Roo.each(this.selections, function(s) {
25300 this.unselect(s, nodeInfo);
25304 var node = this.getNode(nodeInfo);
25305 if(!node || !this.isSelected(node)){
25306 Roo.log("not selected");
25307 return; // not selected.
25311 Roo.each(this.selections, function(s) {
25313 Roo.fly(node).removeClass(this.selectedClass);
25320 this.selections= ns;
25321 this.fireEvent("selectionchange", this, this.selections);
25325 * Gets a template node.
25326 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25327 * @return {HTMLElement} The node or null if it wasn't found
25329 getNode : function(nodeInfo){
25330 if(typeof nodeInfo == "string"){
25331 return document.getElementById(nodeInfo);
25332 }else if(typeof nodeInfo == "number"){
25333 return this.nodes[nodeInfo];
25339 * Gets a range template nodes.
25340 * @param {Number} startIndex
25341 * @param {Number} endIndex
25342 * @return {Array} An array of nodes
25344 getNodes : function(start, end){
25345 var ns = this.nodes;
25346 start = start || 0;
25347 end = typeof end == "undefined" ? ns.length - 1 : end;
25350 for(var i = start; i <= end; i++){
25354 for(var i = start; i >= end; i--){
25362 * Finds the index of the passed node
25363 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25364 * @return {Number} The index of the node or -1
25366 indexOf : function(node){
25367 node = this.getNode(node);
25368 if(typeof node.nodeIndex == "number"){
25369 return node.nodeIndex;
25371 var ns = this.nodes;
25372 for(var i = 0, len = ns.length; i < len; i++){
25382 * Ext JS Library 1.1.1
25383 * Copyright(c) 2006-2007, Ext JS, LLC.
25385 * Originally Released Under LGPL - original licence link has changed is not relivant.
25388 * <script type="text/javascript">
25392 * @class Roo.JsonView
25393 * @extends Roo.View
25394 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25396 var view = new Roo.JsonView({
25397 container: "my-element",
25398 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25403 // listen for node click?
25404 view.on("click", function(vw, index, node, e){
25405 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25408 // direct load of JSON data
25409 view.load("foobar.php");
25411 // Example from my blog list
25412 var tpl = new Roo.Template(
25413 '<div class="entry">' +
25414 '<a class="entry-title" href="{link}">{title}</a>' +
25415 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25416 "</div><hr />"
25419 var moreView = new Roo.JsonView({
25420 container : "entry-list",
25424 moreView.on("beforerender", this.sortEntries, this);
25426 url: "/blog/get-posts.php",
25427 params: "allposts=true",
25428 text: "Loading Blog Entries..."
25432 * Note: old code is supported with arguments : (container, template, config)
25436 * Create a new JsonView
25438 * @param {Object} config The config object
25441 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25444 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25446 var um = this.el.getUpdateManager();
25447 um.setRenderer(this);
25448 um.on("update", this.onLoad, this);
25449 um.on("failure", this.onLoadException, this);
25452 * @event beforerender
25453 * Fires before rendering of the downloaded JSON data.
25454 * @param {Roo.JsonView} this
25455 * @param {Object} data The JSON data loaded
25459 * Fires when data is loaded.
25460 * @param {Roo.JsonView} this
25461 * @param {Object} data The JSON data loaded
25462 * @param {Object} response The raw Connect response object
25465 * @event loadexception
25466 * Fires when loading fails.
25467 * @param {Roo.JsonView} this
25468 * @param {Object} response The raw Connect response object
25471 'beforerender' : true,
25473 'loadexception' : true
25476 Roo.extend(Roo.JsonView, Roo.View, {
25478 * @type {String} The root property in the loaded JSON object that contains the data
25483 * Refreshes the view.
25485 refresh : function(){
25486 this.clearSelections();
25487 this.el.update("");
25489 var o = this.jsonData;
25490 if(o && o.length > 0){
25491 for(var i = 0, len = o.length; i < len; i++){
25492 var data = this.prepareData(o[i], i, o);
25493 html[html.length] = this.tpl.apply(data);
25496 html.push(this.emptyText);
25498 this.el.update(html.join(""));
25499 this.nodes = this.el.dom.childNodes;
25500 this.updateIndexes(0);
25504 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
25505 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
25508 url: "your-url.php",
25509 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25510 callback: yourFunction,
25511 scope: yourObject, //(optional scope)
25514 text: "Loading...",
25519 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25520 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
25521 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
25522 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25523 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
25526 var um = this.el.getUpdateManager();
25527 um.update.apply(um, arguments);
25530 render : function(el, response){
25531 this.clearSelections();
25532 this.el.update("");
25535 o = Roo.util.JSON.decode(response.responseText);
25538 o = o[this.jsonRoot];
25543 * The current JSON data or null
25546 this.beforeRender();
25551 * Get the number of records in the current JSON dataset
25554 getCount : function(){
25555 return this.jsonData ? this.jsonData.length : 0;
25559 * Returns the JSON object for the specified node(s)
25560 * @param {HTMLElement/Array} node The node or an array of nodes
25561 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25562 * you get the JSON object for the node
25564 getNodeData : function(node){
25565 if(node instanceof Array){
25567 for(var i = 0, len = node.length; i < len; i++){
25568 data.push(this.getNodeData(node[i]));
25572 return this.jsonData[this.indexOf(node)] || null;
25575 beforeRender : function(){
25576 this.snapshot = this.jsonData;
25578 this.sort.apply(this, this.sortInfo);
25580 this.fireEvent("beforerender", this, this.jsonData);
25583 onLoad : function(el, o){
25584 this.fireEvent("load", this, this.jsonData, o);
25587 onLoadException : function(el, o){
25588 this.fireEvent("loadexception", this, o);
25592 * Filter the data by a specific property.
25593 * @param {String} property A property on your JSON objects
25594 * @param {String/RegExp} value Either string that the property values
25595 * should start with, or a RegExp to test against the property
25597 filter : function(property, value){
25600 var ss = this.snapshot;
25601 if(typeof value == "string"){
25602 var vlen = value.length;
25604 this.clearFilter();
25607 value = value.toLowerCase();
25608 for(var i = 0, len = ss.length; i < len; i++){
25610 if(o[property].substr(0, vlen).toLowerCase() == value){
25614 } else if(value.exec){ // regex?
25615 for(var i = 0, len = ss.length; i < len; i++){
25617 if(value.test(o[property])){
25624 this.jsonData = data;
25630 * Filter by a function. The passed function will be called with each
25631 * object in the current dataset. If the function returns true the value is kept,
25632 * otherwise it is filtered.
25633 * @param {Function} fn
25634 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25636 filterBy : function(fn, scope){
25639 var ss = this.snapshot;
25640 for(var i = 0, len = ss.length; i < len; i++){
25642 if(fn.call(scope || this, o)){
25646 this.jsonData = data;
25652 * Clears the current filter.
25654 clearFilter : function(){
25655 if(this.snapshot && this.jsonData != this.snapshot){
25656 this.jsonData = this.snapshot;
25663 * Sorts the data for this view and refreshes it.
25664 * @param {String} property A property on your JSON objects to sort on
25665 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25666 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25668 sort : function(property, dir, sortType){
25669 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25672 var dsc = dir && dir.toLowerCase() == "desc";
25673 var f = function(o1, o2){
25674 var v1 = sortType ? sortType(o1[p]) : o1[p];
25675 var v2 = sortType ? sortType(o2[p]) : o2[p];
25678 return dsc ? +1 : -1;
25679 } else if(v1 > v2){
25680 return dsc ? -1 : +1;
25685 this.jsonData.sort(f);
25687 if(this.jsonData != this.snapshot){
25688 this.snapshot.sort(f);
25694 * Ext JS Library 1.1.1
25695 * Copyright(c) 2006-2007, Ext JS, LLC.
25697 * Originally Released Under LGPL - original licence link has changed is not relivant.
25700 * <script type="text/javascript">
25705 * @class Roo.ColorPalette
25706 * @extends Roo.Component
25707 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25708 * Here's an example of typical usage:
25710 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25711 cp.render('my-div');
25713 cp.on('select', function(palette, selColor){
25714 // do something with selColor
25718 * Create a new ColorPalette
25719 * @param {Object} config The config object
25721 Roo.ColorPalette = function(config){
25722 Roo.ColorPalette.superclass.constructor.call(this, config);
25726 * Fires when a color is selected
25727 * @param {ColorPalette} this
25728 * @param {String} color The 6-digit color hex code (without the # symbol)
25734 this.on("select", this.handler, this.scope, true);
25737 Roo.extend(Roo.ColorPalette, Roo.Component, {
25739 * @cfg {String} itemCls
25740 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25742 itemCls : "x-color-palette",
25744 * @cfg {String} value
25745 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25746 * the hex codes are case-sensitive.
25749 clickEvent:'click',
25751 ctype: "Roo.ColorPalette",
25754 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25756 allowReselect : false,
25759 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25760 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25761 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25762 * of colors with the width setting until the box is symmetrical.</p>
25763 * <p>You can override individual colors if needed:</p>
25765 var cp = new Roo.ColorPalette();
25766 cp.colors[0] = "FF0000"; // change the first box to red
25769 Or you can provide a custom array of your own for complete control:
25771 var cp = new Roo.ColorPalette();
25772 cp.colors = ["000000", "993300", "333300"];
25777 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25778 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25779 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25780 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25781 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25785 onRender : function(container, position){
25786 var t = new Roo.MasterTemplate(
25787 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25789 var c = this.colors;
25790 for(var i = 0, len = c.length; i < len; i++){
25793 var el = document.createElement("div");
25794 el.className = this.itemCls;
25796 container.dom.insertBefore(el, position);
25797 this.el = Roo.get(el);
25798 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25799 if(this.clickEvent != 'click'){
25800 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25805 afterRender : function(){
25806 Roo.ColorPalette.superclass.afterRender.call(this);
25808 var s = this.value;
25815 handleClick : function(e, t){
25816 e.preventDefault();
25817 if(!this.disabled){
25818 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25819 this.select(c.toUpperCase());
25824 * Selects the specified color in the palette (fires the select event)
25825 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25827 select : function(color){
25828 color = color.replace("#", "");
25829 if(color != this.value || this.allowReselect){
25832 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25834 el.child("a.color-"+color).addClass("x-color-palette-sel");
25835 this.value = color;
25836 this.fireEvent("select", this, color);
25841 * Ext JS Library 1.1.1
25842 * Copyright(c) 2006-2007, Ext JS, LLC.
25844 * Originally Released Under LGPL - original licence link has changed is not relivant.
25847 * <script type="text/javascript">
25851 * @class Roo.DatePicker
25852 * @extends Roo.Component
25853 * Simple date picker class.
25855 * Create a new DatePicker
25856 * @param {Object} config The config object
25858 Roo.DatePicker = function(config){
25859 Roo.DatePicker.superclass.constructor.call(this, config);
25861 this.value = config && config.value ?
25862 config.value.clearTime() : new Date().clearTime();
25867 * Fires when a date is selected
25868 * @param {DatePicker} this
25869 * @param {Date} date The selected date
25873 * @event monthchange
25874 * Fires when the displayed month changes
25875 * @param {DatePicker} this
25876 * @param {Date} date The selected month
25878 'monthchange': true
25882 this.on("select", this.handler, this.scope || this);
25884 // build the disabledDatesRE
25885 if(!this.disabledDatesRE && this.disabledDates){
25886 var dd = this.disabledDates;
25888 for(var i = 0; i < dd.length; i++){
25890 if(i != dd.length-1) re += "|";
25892 this.disabledDatesRE = new RegExp(re + ")");
25896 Roo.extend(Roo.DatePicker, Roo.Component, {
25898 * @cfg {String} todayText
25899 * The text to display on the button that selects the current date (defaults to "Today")
25901 todayText : "Today",
25903 * @cfg {String} okText
25904 * The text to display on the ok button
25906 okText : " OK ", //   to give the user extra clicking room
25908 * @cfg {String} cancelText
25909 * The text to display on the cancel button
25911 cancelText : "Cancel",
25913 * @cfg {String} todayTip
25914 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25916 todayTip : "{0} (Spacebar)",
25918 * @cfg {Date} minDate
25919 * Minimum allowable date (JavaScript date object, defaults to null)
25923 * @cfg {Date} maxDate
25924 * Maximum allowable date (JavaScript date object, defaults to null)
25928 * @cfg {String} minText
25929 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25931 minText : "This date is before the minimum date",
25933 * @cfg {String} maxText
25934 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25936 maxText : "This date is after the maximum date",
25938 * @cfg {String} format
25939 * The default date format string which can be overriden for localization support. The format must be
25940 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25944 * @cfg {Array} disabledDays
25945 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25947 disabledDays : null,
25949 * @cfg {String} disabledDaysText
25950 * The tooltip to display when the date falls on a disabled day (defaults to "")
25952 disabledDaysText : "",
25954 * @cfg {RegExp} disabledDatesRE
25955 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25957 disabledDatesRE : null,
25959 * @cfg {String} disabledDatesText
25960 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25962 disabledDatesText : "",
25964 * @cfg {Boolean} constrainToViewport
25965 * True to constrain the date picker to the viewport (defaults to true)
25967 constrainToViewport : true,
25969 * @cfg {Array} monthNames
25970 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25972 monthNames : Date.monthNames,
25974 * @cfg {Array} dayNames
25975 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25977 dayNames : Date.dayNames,
25979 * @cfg {String} nextText
25980 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25982 nextText: 'Next Month (Control+Right)',
25984 * @cfg {String} prevText
25985 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25987 prevText: 'Previous Month (Control+Left)',
25989 * @cfg {String} monthYearText
25990 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25992 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25994 * @cfg {Number} startDay
25995 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25999 * @cfg {Bool} showClear
26000 * Show a clear button (usefull for date form elements that can be blank.)
26006 * Sets the value of the date field
26007 * @param {Date} value The date to set
26009 setValue : function(value){
26010 var old = this.value;
26012 if (typeof(value) == 'string') {
26014 value = Date.parseDate(value, this.format);
26017 value = new Date();
26020 this.value = value.clearTime(true);
26022 this.update(this.value);
26027 * Gets the current selected value of the date field
26028 * @return {Date} The selected date
26030 getValue : function(){
26035 focus : function(){
26037 this.update(this.activeDate);
26042 onRender : function(container, position){
26045 '<table cellspacing="0">',
26046 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
26047 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26048 var dn = this.dayNames;
26049 for(var i = 0; i < 7; i++){
26050 var d = this.startDay+i;
26054 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26056 m[m.length] = "</tr></thead><tbody><tr>";
26057 for(var i = 0; i < 42; i++) {
26058 if(i % 7 == 0 && i != 0){
26059 m[m.length] = "</tr><tr>";
26061 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26063 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26064 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26066 var el = document.createElement("div");
26067 el.className = "x-date-picker";
26068 el.innerHTML = m.join("");
26070 container.dom.insertBefore(el, position);
26072 this.el = Roo.get(el);
26073 this.eventEl = Roo.get(el.firstChild);
26075 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26076 handler: this.showPrevMonth,
26078 preventDefault:true,
26082 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26083 handler: this.showNextMonth,
26085 preventDefault:true,
26089 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26091 this.monthPicker = this.el.down('div.x-date-mp');
26092 this.monthPicker.enableDisplayMode('block');
26094 var kn = new Roo.KeyNav(this.eventEl, {
26095 "left" : function(e){
26097 this.showPrevMonth() :
26098 this.update(this.activeDate.add("d", -1));
26101 "right" : function(e){
26103 this.showNextMonth() :
26104 this.update(this.activeDate.add("d", 1));
26107 "up" : function(e){
26109 this.showNextYear() :
26110 this.update(this.activeDate.add("d", -7));
26113 "down" : function(e){
26115 this.showPrevYear() :
26116 this.update(this.activeDate.add("d", 7));
26119 "pageUp" : function(e){
26120 this.showNextMonth();
26123 "pageDown" : function(e){
26124 this.showPrevMonth();
26127 "enter" : function(e){
26128 e.stopPropagation();
26135 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26137 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26139 this.el.unselectable();
26141 this.cells = this.el.select("table.x-date-inner tbody td");
26142 this.textNodes = this.el.query("table.x-date-inner tbody span");
26144 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26146 tooltip: this.monthYearText
26149 this.mbtn.on('click', this.showMonthPicker, this);
26150 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26153 var today = (new Date()).dateFormat(this.format);
26155 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26156 if (this.showClear) {
26157 baseTb.add( new Roo.Toolbar.Fill());
26160 text: String.format(this.todayText, today),
26161 tooltip: String.format(this.todayTip, today),
26162 handler: this.selectToday,
26166 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26169 if (this.showClear) {
26171 baseTb.add( new Roo.Toolbar.Fill());
26174 cls: 'x-btn-icon x-btn-clear',
26175 handler: function() {
26177 this.fireEvent("select", this, '');
26187 this.update(this.value);
26190 createMonthPicker : function(){
26191 if(!this.monthPicker.dom.firstChild){
26192 var buf = ['<table border="0" cellspacing="0">'];
26193 for(var i = 0; i < 6; i++){
26195 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26196 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26198 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
26199 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26203 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26205 '</button><button type="button" class="x-date-mp-cancel">',
26207 '</button></td></tr>',
26210 this.monthPicker.update(buf.join(''));
26211 this.monthPicker.on('click', this.onMonthClick, this);
26212 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26214 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26215 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26217 this.mpMonths.each(function(m, a, i){
26220 m.dom.xmonth = 5 + Math.round(i * .5);
26222 m.dom.xmonth = Math.round((i-1) * .5);
26228 showMonthPicker : function(){
26229 this.createMonthPicker();
26230 var size = this.el.getSize();
26231 this.monthPicker.setSize(size);
26232 this.monthPicker.child('table').setSize(size);
26234 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26235 this.updateMPMonth(this.mpSelMonth);
26236 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26237 this.updateMPYear(this.mpSelYear);
26239 this.monthPicker.slideIn('t', {duration:.2});
26242 updateMPYear : function(y){
26244 var ys = this.mpYears.elements;
26245 for(var i = 1; i <= 10; i++){
26246 var td = ys[i-1], y2;
26248 y2 = y + Math.round(i * .5);
26249 td.firstChild.innerHTML = y2;
26252 y2 = y - (5-Math.round(i * .5));
26253 td.firstChild.innerHTML = y2;
26256 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26260 updateMPMonth : function(sm){
26261 this.mpMonths.each(function(m, a, i){
26262 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26266 selectMPMonth: function(m){
26270 onMonthClick : function(e, t){
26272 var el = new Roo.Element(t), pn;
26273 if(el.is('button.x-date-mp-cancel')){
26274 this.hideMonthPicker();
26276 else if(el.is('button.x-date-mp-ok')){
26277 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26278 this.hideMonthPicker();
26280 else if(pn = el.up('td.x-date-mp-month', 2)){
26281 this.mpMonths.removeClass('x-date-mp-sel');
26282 pn.addClass('x-date-mp-sel');
26283 this.mpSelMonth = pn.dom.xmonth;
26285 else if(pn = el.up('td.x-date-mp-year', 2)){
26286 this.mpYears.removeClass('x-date-mp-sel');
26287 pn.addClass('x-date-mp-sel');
26288 this.mpSelYear = pn.dom.xyear;
26290 else if(el.is('a.x-date-mp-prev')){
26291 this.updateMPYear(this.mpyear-10);
26293 else if(el.is('a.x-date-mp-next')){
26294 this.updateMPYear(this.mpyear+10);
26298 onMonthDblClick : function(e, t){
26300 var el = new Roo.Element(t), pn;
26301 if(pn = el.up('td.x-date-mp-month', 2)){
26302 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26303 this.hideMonthPicker();
26305 else if(pn = el.up('td.x-date-mp-year', 2)){
26306 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26307 this.hideMonthPicker();
26311 hideMonthPicker : function(disableAnim){
26312 if(this.monthPicker){
26313 if(disableAnim === true){
26314 this.monthPicker.hide();
26316 this.monthPicker.slideOut('t', {duration:.2});
26322 showPrevMonth : function(e){
26323 this.update(this.activeDate.add("mo", -1));
26327 showNextMonth : function(e){
26328 this.update(this.activeDate.add("mo", 1));
26332 showPrevYear : function(){
26333 this.update(this.activeDate.add("y", -1));
26337 showNextYear : function(){
26338 this.update(this.activeDate.add("y", 1));
26342 handleMouseWheel : function(e){
26343 var delta = e.getWheelDelta();
26345 this.showPrevMonth();
26347 } else if(delta < 0){
26348 this.showNextMonth();
26354 handleDateClick : function(e, t){
26356 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26357 this.setValue(new Date(t.dateValue));
26358 this.fireEvent("select", this, this.value);
26363 selectToday : function(){
26364 this.setValue(new Date().clearTime());
26365 this.fireEvent("select", this, this.value);
26369 update : function(date)
26371 var vd = this.activeDate;
26372 this.activeDate = date;
26374 var t = date.getTime();
26375 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26376 this.cells.removeClass("x-date-selected");
26377 this.cells.each(function(c){
26378 if(c.dom.firstChild.dateValue == t){
26379 c.addClass("x-date-selected");
26380 setTimeout(function(){
26381 try{c.dom.firstChild.focus();}catch(e){}
26390 var days = date.getDaysInMonth();
26391 var firstOfMonth = date.getFirstDateOfMonth();
26392 var startingPos = firstOfMonth.getDay()-this.startDay;
26394 if(startingPos <= this.startDay){
26398 var pm = date.add("mo", -1);
26399 var prevStart = pm.getDaysInMonth()-startingPos;
26401 var cells = this.cells.elements;
26402 var textEls = this.textNodes;
26403 days += startingPos;
26405 // convert everything to numbers so it's fast
26406 var day = 86400000;
26407 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26408 var today = new Date().clearTime().getTime();
26409 var sel = date.clearTime().getTime();
26410 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26411 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26412 var ddMatch = this.disabledDatesRE;
26413 var ddText = this.disabledDatesText;
26414 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26415 var ddaysText = this.disabledDaysText;
26416 var format = this.format;
26418 var setCellClass = function(cal, cell){
26420 var t = d.getTime();
26421 cell.firstChild.dateValue = t;
26423 cell.className += " x-date-today";
26424 cell.title = cal.todayText;
26427 cell.className += " x-date-selected";
26428 setTimeout(function(){
26429 try{cell.firstChild.focus();}catch(e){}
26434 cell.className = " x-date-disabled";
26435 cell.title = cal.minText;
26439 cell.className = " x-date-disabled";
26440 cell.title = cal.maxText;
26444 if(ddays.indexOf(d.getDay()) != -1){
26445 cell.title = ddaysText;
26446 cell.className = " x-date-disabled";
26449 if(ddMatch && format){
26450 var fvalue = d.dateFormat(format);
26451 if(ddMatch.test(fvalue)){
26452 cell.title = ddText.replace("%0", fvalue);
26453 cell.className = " x-date-disabled";
26459 for(; i < startingPos; i++) {
26460 textEls[i].innerHTML = (++prevStart);
26461 d.setDate(d.getDate()+1);
26462 cells[i].className = "x-date-prevday";
26463 setCellClass(this, cells[i]);
26465 for(; i < days; i++){
26466 intDay = i - startingPos + 1;
26467 textEls[i].innerHTML = (intDay);
26468 d.setDate(d.getDate()+1);
26469 cells[i].className = "x-date-active";
26470 setCellClass(this, cells[i]);
26473 for(; i < 42; i++) {
26474 textEls[i].innerHTML = (++extraDays);
26475 d.setDate(d.getDate()+1);
26476 cells[i].className = "x-date-nextday";
26477 setCellClass(this, cells[i]);
26480 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26481 this.fireEvent('monthchange', this, date);
26483 if(!this.internalRender){
26484 var main = this.el.dom.firstChild;
26485 var w = main.offsetWidth;
26486 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26487 Roo.fly(main).setWidth(w);
26488 this.internalRender = true;
26489 // opera does not respect the auto grow header center column
26490 // then, after it gets a width opera refuses to recalculate
26491 // without a second pass
26492 if(Roo.isOpera && !this.secondPass){
26493 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26494 this.secondPass = true;
26495 this.update.defer(10, this, [date]);
26503 * Ext JS Library 1.1.1
26504 * Copyright(c) 2006-2007, Ext JS, LLC.
26506 * Originally Released Under LGPL - original licence link has changed is not relivant.
26509 * <script type="text/javascript">
26512 * @class Roo.TabPanel
26513 * @extends Roo.util.Observable
26514 * A lightweight tab container.
26518 // basic tabs 1, built from existing content
26519 var tabs = new Roo.TabPanel("tabs1");
26520 tabs.addTab("script", "View Script");
26521 tabs.addTab("markup", "View Markup");
26522 tabs.activate("script");
26524 // more advanced tabs, built from javascript
26525 var jtabs = new Roo.TabPanel("jtabs");
26526 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26528 // set up the UpdateManager
26529 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26530 var updater = tab2.getUpdateManager();
26531 updater.setDefaultUrl("ajax1.htm");
26532 tab2.on('activate', updater.refresh, updater, true);
26534 // Use setUrl for Ajax loading
26535 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26536 tab3.setUrl("ajax2.htm", null, true);
26539 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26542 jtabs.activate("jtabs-1");
26545 * Create a new TabPanel.
26546 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26547 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26549 Roo.TabPanel = function(container, config){
26551 * The container element for this TabPanel.
26552 * @type Roo.Element
26554 this.el = Roo.get(container, true);
26556 if(typeof config == "boolean"){
26557 this.tabPosition = config ? "bottom" : "top";
26559 Roo.apply(this, config);
26562 if(this.tabPosition == "bottom"){
26563 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26564 this.el.addClass("x-tabs-bottom");
26566 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26567 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26568 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26570 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26572 if(this.tabPosition != "bottom"){
26573 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26574 * @type Roo.Element
26576 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26577 this.el.addClass("x-tabs-top");
26581 this.bodyEl.setStyle("position", "relative");
26583 this.active = null;
26584 this.activateDelegate = this.activate.createDelegate(this);
26589 * Fires when the active tab changes
26590 * @param {Roo.TabPanel} this
26591 * @param {Roo.TabPanelItem} activePanel The new active tab
26595 * @event beforetabchange
26596 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26597 * @param {Roo.TabPanel} this
26598 * @param {Object} e Set cancel to true on this object to cancel the tab change
26599 * @param {Roo.TabPanelItem} tab The tab being changed to
26601 "beforetabchange" : true
26604 Roo.EventManager.onWindowResize(this.onResize, this);
26605 this.cpad = this.el.getPadding("lr");
26606 this.hiddenCount = 0;
26609 // toolbar on the tabbar support...
26610 if (this.toolbar) {
26611 var tcfg = this.toolbar;
26612 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26613 this.toolbar = new Roo.Toolbar(tcfg);
26614 if (Roo.isSafari) {
26615 var tbl = tcfg.container.child('table', true);
26616 tbl.setAttribute('width', '100%');
26623 Roo.TabPanel.superclass.constructor.call(this);
26626 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26628 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26630 tabPosition : "top",
26632 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26634 currentTabWidth : 0,
26636 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26640 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26644 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26646 preferredTabWidth : 175,
26648 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26650 resizeTabs : false,
26652 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26654 monitorResize : true,
26656 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26661 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26662 * @param {String} id The id of the div to use <b>or create</b>
26663 * @param {String} text The text for the tab
26664 * @param {String} content (optional) Content to put in the TabPanelItem body
26665 * @param {Boolean} closable (optional) True to create a close icon on the tab
26666 * @return {Roo.TabPanelItem} The created TabPanelItem
26668 addTab : function(id, text, content, closable){
26669 var item = new Roo.TabPanelItem(this, id, text, closable);
26670 this.addTabItem(item);
26672 item.setContent(content);
26678 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26679 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26680 * @return {Roo.TabPanelItem}
26682 getTab : function(id){
26683 return this.items[id];
26687 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26688 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26690 hideTab : function(id){
26691 var t = this.items[id];
26694 this.hiddenCount++;
26695 this.autoSizeTabs();
26700 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26701 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26703 unhideTab : function(id){
26704 var t = this.items[id];
26706 t.setHidden(false);
26707 this.hiddenCount--;
26708 this.autoSizeTabs();
26713 * Adds an existing {@link Roo.TabPanelItem}.
26714 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26716 addTabItem : function(item){
26717 this.items[item.id] = item;
26718 this.items.push(item);
26719 if(this.resizeTabs){
26720 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26721 this.autoSizeTabs();
26728 * Removes a {@link Roo.TabPanelItem}.
26729 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26731 removeTab : function(id){
26732 var items = this.items;
26733 var tab = items[id];
26734 if(!tab) { return; }
26735 var index = items.indexOf(tab);
26736 if(this.active == tab && items.length > 1){
26737 var newTab = this.getNextAvailable(index);
26742 this.stripEl.dom.removeChild(tab.pnode.dom);
26743 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26744 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26746 items.splice(index, 1);
26747 delete this.items[tab.id];
26748 tab.fireEvent("close", tab);
26749 tab.purgeListeners();
26750 this.autoSizeTabs();
26753 getNextAvailable : function(start){
26754 var items = this.items;
26756 // look for a next tab that will slide over to
26757 // replace the one being removed
26758 while(index < items.length){
26759 var item = items[++index];
26760 if(item && !item.isHidden()){
26764 // if one isn't found select the previous tab (on the left)
26767 var item = items[--index];
26768 if(item && !item.isHidden()){
26776 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26777 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26779 disableTab : function(id){
26780 var tab = this.items[id];
26781 if(tab && this.active != tab){
26787 * Enables a {@link Roo.TabPanelItem} that is disabled.
26788 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26790 enableTab : function(id){
26791 var tab = this.items[id];
26796 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26797 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26798 * @return {Roo.TabPanelItem} The TabPanelItem.
26800 activate : function(id){
26801 var tab = this.items[id];
26805 if(tab == this.active || tab.disabled){
26809 this.fireEvent("beforetabchange", this, e, tab);
26810 if(e.cancel !== true && !tab.disabled){
26812 this.active.hide();
26814 this.active = this.items[id];
26815 this.active.show();
26816 this.fireEvent("tabchange", this, this.active);
26822 * Gets the active {@link Roo.TabPanelItem}.
26823 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26825 getActiveTab : function(){
26826 return this.active;
26830 * Updates the tab body element to fit the height of the container element
26831 * for overflow scrolling
26832 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26834 syncHeight : function(targetHeight){
26835 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26836 var bm = this.bodyEl.getMargins();
26837 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26838 this.bodyEl.setHeight(newHeight);
26842 onResize : function(){
26843 if(this.monitorResize){
26844 this.autoSizeTabs();
26849 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26851 beginUpdate : function(){
26852 this.updating = true;
26856 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26858 endUpdate : function(){
26859 this.updating = false;
26860 this.autoSizeTabs();
26864 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26866 autoSizeTabs : function(){
26867 var count = this.items.length;
26868 var vcount = count - this.hiddenCount;
26869 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26870 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26871 var availWidth = Math.floor(w / vcount);
26872 var b = this.stripBody;
26873 if(b.getWidth() > w){
26874 var tabs = this.items;
26875 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26876 if(availWidth < this.minTabWidth){
26877 /*if(!this.sleft){ // incomplete scrolling code
26878 this.createScrollButtons();
26881 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26884 if(this.currentTabWidth < this.preferredTabWidth){
26885 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26891 * Returns the number of tabs in this TabPanel.
26894 getCount : function(){
26895 return this.items.length;
26899 * Resizes all the tabs to the passed width
26900 * @param {Number} The new width
26902 setTabWidth : function(width){
26903 this.currentTabWidth = width;
26904 for(var i = 0, len = this.items.length; i < len; i++) {
26905 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26910 * Destroys this TabPanel
26911 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26913 destroy : function(removeEl){
26914 Roo.EventManager.removeResizeListener(this.onResize, this);
26915 for(var i = 0, len = this.items.length; i < len; i++){
26916 this.items[i].purgeListeners();
26918 if(removeEl === true){
26919 this.el.update("");
26926 * @class Roo.TabPanelItem
26927 * @extends Roo.util.Observable
26928 * Represents an individual item (tab plus body) in a TabPanel.
26929 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26930 * @param {String} id The id of this TabPanelItem
26931 * @param {String} text The text for the tab of this TabPanelItem
26932 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26934 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26936 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26937 * @type Roo.TabPanel
26939 this.tabPanel = tabPanel;
26941 * The id for this TabPanelItem
26946 this.disabled = false;
26950 this.loaded = false;
26951 this.closable = closable;
26954 * The body element for this TabPanelItem.
26955 * @type Roo.Element
26957 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26958 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26959 this.bodyEl.setStyle("display", "block");
26960 this.bodyEl.setStyle("zoom", "1");
26963 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26965 this.el = Roo.get(els.el, true);
26966 this.inner = Roo.get(els.inner, true);
26967 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26968 this.pnode = Roo.get(els.el.parentNode, true);
26969 this.el.on("mousedown", this.onTabMouseDown, this);
26970 this.el.on("click", this.onTabClick, this);
26973 var c = Roo.get(els.close, true);
26974 c.dom.title = this.closeText;
26975 c.addClassOnOver("close-over");
26976 c.on("click", this.closeClick, this);
26982 * Fires when this tab becomes the active tab.
26983 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26984 * @param {Roo.TabPanelItem} this
26988 * @event beforeclose
26989 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26990 * @param {Roo.TabPanelItem} this
26991 * @param {Object} e Set cancel to true on this object to cancel the close.
26993 "beforeclose": true,
26996 * Fires when this tab is closed.
26997 * @param {Roo.TabPanelItem} this
27001 * @event deactivate
27002 * Fires when this tab is no longer the active tab.
27003 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27004 * @param {Roo.TabPanelItem} this
27006 "deactivate" : true
27008 this.hidden = false;
27010 Roo.TabPanelItem.superclass.constructor.call(this);
27013 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27014 purgeListeners : function(){
27015 Roo.util.Observable.prototype.purgeListeners.call(this);
27016 this.el.removeAllListeners();
27019 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27022 this.pnode.addClass("on");
27025 this.tabPanel.stripWrap.repaint();
27027 this.fireEvent("activate", this.tabPanel, this);
27031 * Returns true if this tab is the active tab.
27032 * @return {Boolean}
27034 isActive : function(){
27035 return this.tabPanel.getActiveTab() == this;
27039 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27042 this.pnode.removeClass("on");
27044 this.fireEvent("deactivate", this.tabPanel, this);
27047 hideAction : function(){
27048 this.bodyEl.hide();
27049 this.bodyEl.setStyle("position", "absolute");
27050 this.bodyEl.setLeft("-20000px");
27051 this.bodyEl.setTop("-20000px");
27054 showAction : function(){
27055 this.bodyEl.setStyle("position", "relative");
27056 this.bodyEl.setTop("");
27057 this.bodyEl.setLeft("");
27058 this.bodyEl.show();
27062 * Set the tooltip for the tab.
27063 * @param {String} tooltip The tab's tooltip
27065 setTooltip : function(text){
27066 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27067 this.textEl.dom.qtip = text;
27068 this.textEl.dom.removeAttribute('title');
27070 this.textEl.dom.title = text;
27074 onTabClick : function(e){
27075 e.preventDefault();
27076 this.tabPanel.activate(this.id);
27079 onTabMouseDown : function(e){
27080 e.preventDefault();
27081 this.tabPanel.activate(this.id);
27084 getWidth : function(){
27085 return this.inner.getWidth();
27088 setWidth : function(width){
27089 var iwidth = width - this.pnode.getPadding("lr");
27090 this.inner.setWidth(iwidth);
27091 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27092 this.pnode.setWidth(width);
27096 * Show or hide the tab
27097 * @param {Boolean} hidden True to hide or false to show.
27099 setHidden : function(hidden){
27100 this.hidden = hidden;
27101 this.pnode.setStyle("display", hidden ? "none" : "");
27105 * Returns true if this tab is "hidden"
27106 * @return {Boolean}
27108 isHidden : function(){
27109 return this.hidden;
27113 * Returns the text for this tab
27116 getText : function(){
27120 autoSize : function(){
27121 //this.el.beginMeasure();
27122 this.textEl.setWidth(1);
27124 * #2804 [new] Tabs in Roojs
27125 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27127 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27128 //this.el.endMeasure();
27132 * Sets the text for the tab (Note: this also sets the tooltip text)
27133 * @param {String} text The tab's text and tooltip
27135 setText : function(text){
27137 this.textEl.update(text);
27138 this.setTooltip(text);
27139 if(!this.tabPanel.resizeTabs){
27144 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27146 activate : function(){
27147 this.tabPanel.activate(this.id);
27151 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27153 disable : function(){
27154 if(this.tabPanel.active != this){
27155 this.disabled = true;
27156 this.pnode.addClass("disabled");
27161 * Enables this TabPanelItem if it was previously disabled.
27163 enable : function(){
27164 this.disabled = false;
27165 this.pnode.removeClass("disabled");
27169 * Sets the content for this TabPanelItem.
27170 * @param {String} content The content
27171 * @param {Boolean} loadScripts true to look for and load scripts
27173 setContent : function(content, loadScripts){
27174 this.bodyEl.update(content, loadScripts);
27178 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27179 * @return {Roo.UpdateManager} The UpdateManager
27181 getUpdateManager : function(){
27182 return this.bodyEl.getUpdateManager();
27186 * Set a URL to be used to load the content for this TabPanelItem.
27187 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27188 * @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)
27189 * @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)
27190 * @return {Roo.UpdateManager} The UpdateManager
27192 setUrl : function(url, params, loadOnce){
27193 if(this.refreshDelegate){
27194 this.un('activate', this.refreshDelegate);
27196 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27197 this.on("activate", this.refreshDelegate);
27198 return this.bodyEl.getUpdateManager();
27202 _handleRefresh : function(url, params, loadOnce){
27203 if(!loadOnce || !this.loaded){
27204 var updater = this.bodyEl.getUpdateManager();
27205 updater.update(url, params, this._setLoaded.createDelegate(this));
27210 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27211 * Will fail silently if the setUrl method has not been called.
27212 * This does not activate the panel, just updates its content.
27214 refresh : function(){
27215 if(this.refreshDelegate){
27216 this.loaded = false;
27217 this.refreshDelegate();
27222 _setLoaded : function(){
27223 this.loaded = true;
27227 closeClick : function(e){
27230 this.fireEvent("beforeclose", this, o);
27231 if(o.cancel !== true){
27232 this.tabPanel.removeTab(this.id);
27236 * The text displayed in the tooltip for the close icon.
27239 closeText : "Close this tab"
27243 Roo.TabPanel.prototype.createStrip = function(container){
27244 var strip = document.createElement("div");
27245 strip.className = "x-tabs-wrap";
27246 container.appendChild(strip);
27250 Roo.TabPanel.prototype.createStripList = function(strip){
27251 // div wrapper for retard IE
27252 // returns the "tr" element.
27253 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27254 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27255 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27256 return strip.firstChild.firstChild.firstChild.firstChild;
27259 Roo.TabPanel.prototype.createBody = function(container){
27260 var body = document.createElement("div");
27261 Roo.id(body, "tab-body");
27262 Roo.fly(body).addClass("x-tabs-body");
27263 container.appendChild(body);
27267 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27268 var body = Roo.getDom(id);
27270 body = document.createElement("div");
27273 Roo.fly(body).addClass("x-tabs-item-body");
27274 bodyEl.insertBefore(body, bodyEl.firstChild);
27278 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27279 var td = document.createElement("td");
27280 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27281 //stripEl.appendChild(td);
27283 td.className = "x-tabs-closable";
27284 if(!this.closeTpl){
27285 this.closeTpl = new Roo.Template(
27286 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27287 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27288 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27291 var el = this.closeTpl.overwrite(td, {"text": text});
27292 var close = el.getElementsByTagName("div")[0];
27293 var inner = el.getElementsByTagName("em")[0];
27294 return {"el": el, "close": close, "inner": inner};
27297 this.tabTpl = new Roo.Template(
27298 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27299 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27302 var el = this.tabTpl.overwrite(td, {"text": text});
27303 var inner = el.getElementsByTagName("em")[0];
27304 return {"el": el, "inner": inner};
27308 * Ext JS Library 1.1.1
27309 * Copyright(c) 2006-2007, Ext JS, LLC.
27311 * Originally Released Under LGPL - original licence link has changed is not relivant.
27314 * <script type="text/javascript">
27318 * @class Roo.Button
27319 * @extends Roo.util.Observable
27320 * Simple Button class
27321 * @cfg {String} text The button text
27322 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27323 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27324 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27325 * @cfg {Object} scope The scope of the handler
27326 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27327 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27328 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27329 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27330 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27331 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27332 applies if enableToggle = true)
27333 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27334 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27335 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27337 * Create a new button
27338 * @param {Object} config The config object
27340 Roo.Button = function(renderTo, config)
27344 renderTo = config.renderTo || false;
27347 Roo.apply(this, config);
27351 * Fires when this button is clicked
27352 * @param {Button} this
27353 * @param {EventObject} e The click event
27358 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27359 * @param {Button} this
27360 * @param {Boolean} pressed
27365 * Fires when the mouse hovers over the button
27366 * @param {Button} this
27367 * @param {Event} e The event object
27369 'mouseover' : true,
27372 * Fires when the mouse exits the button
27373 * @param {Button} this
27374 * @param {Event} e The event object
27379 * Fires when the button is rendered
27380 * @param {Button} this
27385 this.menu = Roo.menu.MenuMgr.get(this.menu);
27387 // register listeners first!! - so render can be captured..
27388 Roo.util.Observable.call(this);
27390 this.render(renderTo);
27396 Roo.extend(Roo.Button, Roo.util.Observable, {
27402 * Read-only. True if this button is hidden
27407 * Read-only. True if this button is disabled
27412 * Read-only. True if this button is pressed (only if enableToggle = true)
27418 * @cfg {Number} tabIndex
27419 * The DOM tabIndex for this button (defaults to undefined)
27421 tabIndex : undefined,
27424 * @cfg {Boolean} enableToggle
27425 * True to enable pressed/not pressed toggling (defaults to false)
27427 enableToggle: false,
27429 * @cfg {Mixed} menu
27430 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27434 * @cfg {String} menuAlign
27435 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27437 menuAlign : "tl-bl?",
27440 * @cfg {String} iconCls
27441 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27443 iconCls : undefined,
27445 * @cfg {String} type
27446 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27451 menuClassTarget: 'tr',
27454 * @cfg {String} clickEvent
27455 * The type of event to map to the button's event handler (defaults to 'click')
27457 clickEvent : 'click',
27460 * @cfg {Boolean} handleMouseEvents
27461 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27463 handleMouseEvents : true,
27466 * @cfg {String} tooltipType
27467 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27469 tooltipType : 'qtip',
27472 * @cfg {String} cls
27473 * A CSS class to apply to the button's main element.
27477 * @cfg {Roo.Template} template (Optional)
27478 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27479 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27480 * require code modifications if required elements (e.g. a button) aren't present.
27484 render : function(renderTo){
27486 if(this.hideParent){
27487 this.parentEl = Roo.get(renderTo);
27489 if(!this.dhconfig){
27490 if(!this.template){
27491 if(!Roo.Button.buttonTemplate){
27492 // hideous table template
27493 Roo.Button.buttonTemplate = new Roo.Template(
27494 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27495 '<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>',
27496 "</tr></tbody></table>");
27498 this.template = Roo.Button.buttonTemplate;
27500 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27501 var btnEl = btn.child("button:first");
27502 btnEl.on('focus', this.onFocus, this);
27503 btnEl.on('blur', this.onBlur, this);
27505 btn.addClass(this.cls);
27508 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27511 btnEl.addClass(this.iconCls);
27513 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27516 if(this.tabIndex !== undefined){
27517 btnEl.dom.tabIndex = this.tabIndex;
27520 if(typeof this.tooltip == 'object'){
27521 Roo.QuickTips.tips(Roo.apply({
27525 btnEl.dom[this.tooltipType] = this.tooltip;
27529 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27533 this.el.dom.id = this.el.id = this.id;
27536 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27537 this.menu.on("show", this.onMenuShow, this);
27538 this.menu.on("hide", this.onMenuHide, this);
27540 btn.addClass("x-btn");
27541 if(Roo.isIE && !Roo.isIE7){
27542 this.autoWidth.defer(1, this);
27546 if(this.handleMouseEvents){
27547 btn.on("mouseover", this.onMouseOver, this);
27548 btn.on("mouseout", this.onMouseOut, this);
27549 btn.on("mousedown", this.onMouseDown, this);
27551 btn.on(this.clickEvent, this.onClick, this);
27552 //btn.on("mouseup", this.onMouseUp, this);
27559 Roo.ButtonToggleMgr.register(this);
27561 this.el.addClass("x-btn-pressed");
27564 var repeater = new Roo.util.ClickRepeater(btn,
27565 typeof this.repeat == "object" ? this.repeat : {}
27567 repeater.on("click", this.onClick, this);
27570 this.fireEvent('render', this);
27574 * Returns the button's underlying element
27575 * @return {Roo.Element} The element
27577 getEl : function(){
27582 * Destroys this Button and removes any listeners.
27584 destroy : function(){
27585 Roo.ButtonToggleMgr.unregister(this);
27586 this.el.removeAllListeners();
27587 this.purgeListeners();
27592 autoWidth : function(){
27594 this.el.setWidth("auto");
27595 if(Roo.isIE7 && Roo.isStrict){
27596 var ib = this.el.child('button');
27597 if(ib && ib.getWidth() > 20){
27599 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27604 this.el.beginMeasure();
27606 if(this.el.getWidth() < this.minWidth){
27607 this.el.setWidth(this.minWidth);
27610 this.el.endMeasure();
27617 * Assigns this button's click handler
27618 * @param {Function} handler The function to call when the button is clicked
27619 * @param {Object} scope (optional) Scope for the function passed in
27621 setHandler : function(handler, scope){
27622 this.handler = handler;
27623 this.scope = scope;
27627 * Sets this button's text
27628 * @param {String} text The button text
27630 setText : function(text){
27633 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27639 * Gets the text for this button
27640 * @return {String} The button text
27642 getText : function(){
27650 this.hidden = false;
27652 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27660 this.hidden = true;
27662 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27667 * Convenience function for boolean show/hide
27668 * @param {Boolean} visible True to show, false to hide
27670 setVisible: function(visible){
27679 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27680 * @param {Boolean} state (optional) Force a particular state
27682 toggle : function(state){
27683 state = state === undefined ? !this.pressed : state;
27684 if(state != this.pressed){
27686 this.el.addClass("x-btn-pressed");
27687 this.pressed = true;
27688 this.fireEvent("toggle", this, true);
27690 this.el.removeClass("x-btn-pressed");
27691 this.pressed = false;
27692 this.fireEvent("toggle", this, false);
27694 if(this.toggleHandler){
27695 this.toggleHandler.call(this.scope || this, this, state);
27703 focus : function(){
27704 this.el.child('button:first').focus();
27708 * Disable this button
27710 disable : function(){
27712 this.el.addClass("x-btn-disabled");
27714 this.disabled = true;
27718 * Enable this button
27720 enable : function(){
27722 this.el.removeClass("x-btn-disabled");
27724 this.disabled = false;
27728 * Convenience function for boolean enable/disable
27729 * @param {Boolean} enabled True to enable, false to disable
27731 setDisabled : function(v){
27732 this[v !== true ? "enable" : "disable"]();
27736 onClick : function(e){
27738 e.preventDefault();
27743 if(!this.disabled){
27744 if(this.enableToggle){
27747 if(this.menu && !this.menu.isVisible()){
27748 this.menu.show(this.el, this.menuAlign);
27750 this.fireEvent("click", this, e);
27752 this.el.removeClass("x-btn-over");
27753 this.handler.call(this.scope || this, this, e);
27758 onMouseOver : function(e){
27759 if(!this.disabled){
27760 this.el.addClass("x-btn-over");
27761 this.fireEvent('mouseover', this, e);
27765 onMouseOut : function(e){
27766 if(!e.within(this.el, true)){
27767 this.el.removeClass("x-btn-over");
27768 this.fireEvent('mouseout', this, e);
27772 onFocus : function(e){
27773 if(!this.disabled){
27774 this.el.addClass("x-btn-focus");
27778 onBlur : function(e){
27779 this.el.removeClass("x-btn-focus");
27782 onMouseDown : function(e){
27783 if(!this.disabled && e.button == 0){
27784 this.el.addClass("x-btn-click");
27785 Roo.get(document).on('mouseup', this.onMouseUp, this);
27789 onMouseUp : function(e){
27791 this.el.removeClass("x-btn-click");
27792 Roo.get(document).un('mouseup', this.onMouseUp, this);
27796 onMenuShow : function(e){
27797 this.el.addClass("x-btn-menu-active");
27800 onMenuHide : function(e){
27801 this.el.removeClass("x-btn-menu-active");
27805 // Private utility class used by Button
27806 Roo.ButtonToggleMgr = function(){
27809 function toggleGroup(btn, state){
27811 var g = groups[btn.toggleGroup];
27812 for(var i = 0, l = g.length; i < l; i++){
27814 g[i].toggle(false);
27821 register : function(btn){
27822 if(!btn.toggleGroup){
27825 var g = groups[btn.toggleGroup];
27827 g = groups[btn.toggleGroup] = [];
27830 btn.on("toggle", toggleGroup);
27833 unregister : function(btn){
27834 if(!btn.toggleGroup){
27837 var g = groups[btn.toggleGroup];
27840 btn.un("toggle", toggleGroup);
27846 * Ext JS Library 1.1.1
27847 * Copyright(c) 2006-2007, Ext JS, LLC.
27849 * Originally Released Under LGPL - original licence link has changed is not relivant.
27852 * <script type="text/javascript">
27856 * @class Roo.SplitButton
27857 * @extends Roo.Button
27858 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27859 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27860 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27861 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27862 * @cfg {String} arrowTooltip The title attribute of the arrow
27864 * Create a new menu button
27865 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27866 * @param {Object} config The config object
27868 Roo.SplitButton = function(renderTo, config){
27869 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27871 * @event arrowclick
27872 * Fires when this button's arrow is clicked
27873 * @param {SplitButton} this
27874 * @param {EventObject} e The click event
27876 this.addEvents({"arrowclick":true});
27879 Roo.extend(Roo.SplitButton, Roo.Button, {
27880 render : function(renderTo){
27881 // this is one sweet looking template!
27882 var tpl = new Roo.Template(
27883 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27884 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27885 '<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>',
27886 "</tbody></table></td><td>",
27887 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27888 '<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>',
27889 "</tbody></table></td></tr></table>"
27891 var btn = tpl.append(renderTo, [this.text, this.type], true);
27892 var btnEl = btn.child("button");
27894 btn.addClass(this.cls);
27897 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27900 btnEl.addClass(this.iconCls);
27902 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27906 if(this.handleMouseEvents){
27907 btn.on("mouseover", this.onMouseOver, this);
27908 btn.on("mouseout", this.onMouseOut, this);
27909 btn.on("mousedown", this.onMouseDown, this);
27910 btn.on("mouseup", this.onMouseUp, this);
27912 btn.on(this.clickEvent, this.onClick, this);
27914 if(typeof this.tooltip == 'object'){
27915 Roo.QuickTips.tips(Roo.apply({
27919 btnEl.dom[this.tooltipType] = this.tooltip;
27922 if(this.arrowTooltip){
27923 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27932 this.el.addClass("x-btn-pressed");
27934 if(Roo.isIE && !Roo.isIE7){
27935 this.autoWidth.defer(1, this);
27940 this.menu.on("show", this.onMenuShow, this);
27941 this.menu.on("hide", this.onMenuHide, this);
27943 this.fireEvent('render', this);
27947 autoWidth : function(){
27949 var tbl = this.el.child("table:first");
27950 var tbl2 = this.el.child("table:last");
27951 this.el.setWidth("auto");
27952 tbl.setWidth("auto");
27953 if(Roo.isIE7 && Roo.isStrict){
27954 var ib = this.el.child('button:first');
27955 if(ib && ib.getWidth() > 20){
27957 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27962 this.el.beginMeasure();
27964 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27965 tbl.setWidth(this.minWidth-tbl2.getWidth());
27968 this.el.endMeasure();
27971 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27975 * Sets this button's click handler
27976 * @param {Function} handler The function to call when the button is clicked
27977 * @param {Object} scope (optional) Scope for the function passed above
27979 setHandler : function(handler, scope){
27980 this.handler = handler;
27981 this.scope = scope;
27985 * Sets this button's arrow click handler
27986 * @param {Function} handler The function to call when the arrow is clicked
27987 * @param {Object} scope (optional) Scope for the function passed above
27989 setArrowHandler : function(handler, scope){
27990 this.arrowHandler = handler;
27991 this.scope = scope;
27997 focus : function(){
27999 this.el.child("button:first").focus();
28004 onClick : function(e){
28005 e.preventDefault();
28006 if(!this.disabled){
28007 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28008 if(this.menu && !this.menu.isVisible()){
28009 this.menu.show(this.el, this.menuAlign);
28011 this.fireEvent("arrowclick", this, e);
28012 if(this.arrowHandler){
28013 this.arrowHandler.call(this.scope || this, this, e);
28016 this.fireEvent("click", this, e);
28018 this.handler.call(this.scope || this, this, e);
28024 onMouseDown : function(e){
28025 if(!this.disabled){
28026 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28030 onMouseUp : function(e){
28031 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28036 // backwards compat
28037 Roo.MenuButton = Roo.SplitButton;/*
28039 * Ext JS Library 1.1.1
28040 * Copyright(c) 2006-2007, Ext JS, LLC.
28042 * Originally Released Under LGPL - original licence link has changed is not relivant.
28045 * <script type="text/javascript">
28049 * @class Roo.Toolbar
28050 * Basic Toolbar class.
28052 * Creates a new Toolbar
28053 * @param {Object} container The config object
28055 Roo.Toolbar = function(container, buttons, config)
28057 /// old consturctor format still supported..
28058 if(container instanceof Array){ // omit the container for later rendering
28059 buttons = container;
28063 if (typeof(container) == 'object' && container.xtype) {
28064 config = container;
28065 container = config.container;
28066 buttons = config.buttons || []; // not really - use items!!
28069 if (config && config.items) {
28070 xitems = config.items;
28071 delete config.items;
28073 Roo.apply(this, config);
28074 this.buttons = buttons;
28077 this.render(container);
28079 this.xitems = xitems;
28080 Roo.each(xitems, function(b) {
28086 Roo.Toolbar.prototype = {
28088 * @cfg {Array} items
28089 * array of button configs or elements to add (will be converted to a MixedCollection)
28093 * @cfg {String/HTMLElement/Element} container
28094 * The id or element that will contain the toolbar
28097 render : function(ct){
28098 this.el = Roo.get(ct);
28100 this.el.addClass(this.cls);
28102 // using a table allows for vertical alignment
28103 // 100% width is needed by Safari...
28104 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28105 this.tr = this.el.child("tr", true);
28107 this.items = new Roo.util.MixedCollection(false, function(o){
28108 return o.id || ("item" + (++autoId));
28111 this.add.apply(this, this.buttons);
28112 delete this.buttons;
28117 * Adds element(s) to the toolbar -- this function takes a variable number of
28118 * arguments of mixed type and adds them to the toolbar.
28119 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28121 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28122 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28123 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28124 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28125 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28126 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28127 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28128 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28129 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28131 * @param {Mixed} arg2
28132 * @param {Mixed} etc.
28135 var a = arguments, l = a.length;
28136 for(var i = 0; i < l; i++){
28141 _add : function(el) {
28144 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28147 if (el.applyTo){ // some kind of form field
28148 return this.addField(el);
28150 if (el.render){ // some kind of Toolbar.Item
28151 return this.addItem(el);
28153 if (typeof el == "string"){ // string
28154 if(el == "separator" || el == "-"){
28155 return this.addSeparator();
28158 return this.addSpacer();
28161 return this.addFill();
28163 return this.addText(el);
28166 if(el.tagName){ // element
28167 return this.addElement(el);
28169 if(typeof el == "object"){ // must be button config?
28170 return this.addButton(el);
28172 // and now what?!?!
28178 * Add an Xtype element
28179 * @param {Object} xtype Xtype Object
28180 * @return {Object} created Object
28182 addxtype : function(e){
28183 return this.add(e);
28187 * Returns the Element for this toolbar.
28188 * @return {Roo.Element}
28190 getEl : function(){
28196 * @return {Roo.Toolbar.Item} The separator item
28198 addSeparator : function(){
28199 return this.addItem(new Roo.Toolbar.Separator());
28203 * Adds a spacer element
28204 * @return {Roo.Toolbar.Spacer} The spacer item
28206 addSpacer : function(){
28207 return this.addItem(new Roo.Toolbar.Spacer());
28211 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28212 * @return {Roo.Toolbar.Fill} The fill item
28214 addFill : function(){
28215 return this.addItem(new Roo.Toolbar.Fill());
28219 * Adds any standard HTML element to the toolbar
28220 * @param {String/HTMLElement/Element} el The element or id of the element to add
28221 * @return {Roo.Toolbar.Item} The element's item
28223 addElement : function(el){
28224 return this.addItem(new Roo.Toolbar.Item(el));
28227 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28228 * @type Roo.util.MixedCollection
28233 * Adds any Toolbar.Item or subclass
28234 * @param {Roo.Toolbar.Item} item
28235 * @return {Roo.Toolbar.Item} The item
28237 addItem : function(item){
28238 var td = this.nextBlock();
28240 this.items.add(item);
28245 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28246 * @param {Object/Array} config A button config or array of configs
28247 * @return {Roo.Toolbar.Button/Array}
28249 addButton : function(config){
28250 if(config instanceof Array){
28252 for(var i = 0, len = config.length; i < len; i++) {
28253 buttons.push(this.addButton(config[i]));
28258 if(!(config instanceof Roo.Toolbar.Button)){
28260 new Roo.Toolbar.SplitButton(config) :
28261 new Roo.Toolbar.Button(config);
28263 var td = this.nextBlock();
28270 * Adds text to the toolbar
28271 * @param {String} text The text to add
28272 * @return {Roo.Toolbar.Item} The element's item
28274 addText : function(text){
28275 return this.addItem(new Roo.Toolbar.TextItem(text));
28279 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28280 * @param {Number} index The index where the item is to be inserted
28281 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28282 * @return {Roo.Toolbar.Button/Item}
28284 insertButton : function(index, item){
28285 if(item instanceof Array){
28287 for(var i = 0, len = item.length; i < len; i++) {
28288 buttons.push(this.insertButton(index + i, item[i]));
28292 if (!(item instanceof Roo.Toolbar.Button)){
28293 item = new Roo.Toolbar.Button(item);
28295 var td = document.createElement("td");
28296 this.tr.insertBefore(td, this.tr.childNodes[index]);
28298 this.items.insert(index, item);
28303 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28304 * @param {Object} config
28305 * @return {Roo.Toolbar.Item} The element's item
28307 addDom : function(config, returnEl){
28308 var td = this.nextBlock();
28309 Roo.DomHelper.overwrite(td, config);
28310 var ti = new Roo.Toolbar.Item(td.firstChild);
28312 this.items.add(ti);
28317 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28318 * @type Roo.util.MixedCollection
28323 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28324 * Note: the field should not have been rendered yet. For a field that has already been
28325 * rendered, use {@link #addElement}.
28326 * @param {Roo.form.Field} field
28327 * @return {Roo.ToolbarItem}
28331 addField : function(field) {
28332 if (!this.fields) {
28334 this.fields = new Roo.util.MixedCollection(false, function(o){
28335 return o.id || ("item" + (++autoId));
28340 var td = this.nextBlock();
28342 var ti = new Roo.Toolbar.Item(td.firstChild);
28344 this.items.add(ti);
28345 this.fields.add(field);
28356 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28357 this.el.child('div').hide();
28365 this.el.child('div').show();
28369 nextBlock : function(){
28370 var td = document.createElement("td");
28371 this.tr.appendChild(td);
28376 destroy : function(){
28377 if(this.items){ // rendered?
28378 Roo.destroy.apply(Roo, this.items.items);
28380 if(this.fields){ // rendered?
28381 Roo.destroy.apply(Roo, this.fields.items);
28383 Roo.Element.uncache(this.el, this.tr);
28388 * @class Roo.Toolbar.Item
28389 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28391 * Creates a new Item
28392 * @param {HTMLElement} el
28394 Roo.Toolbar.Item = function(el){
28395 this.el = Roo.getDom(el);
28396 this.id = Roo.id(this.el);
28397 this.hidden = false;
28400 Roo.Toolbar.Item.prototype = {
28403 * Get this item's HTML Element
28404 * @return {HTMLElement}
28406 getEl : function(){
28411 render : function(td){
28413 td.appendChild(this.el);
28417 * Removes and destroys this item.
28419 destroy : function(){
28420 this.td.parentNode.removeChild(this.td);
28427 this.hidden = false;
28428 this.td.style.display = "";
28435 this.hidden = true;
28436 this.td.style.display = "none";
28440 * Convenience function for boolean show/hide.
28441 * @param {Boolean} visible true to show/false to hide
28443 setVisible: function(visible){
28452 * Try to focus this item.
28454 focus : function(){
28455 Roo.fly(this.el).focus();
28459 * Disables this item.
28461 disable : function(){
28462 Roo.fly(this.td).addClass("x-item-disabled");
28463 this.disabled = true;
28464 this.el.disabled = true;
28468 * Enables this item.
28470 enable : function(){
28471 Roo.fly(this.td).removeClass("x-item-disabled");
28472 this.disabled = false;
28473 this.el.disabled = false;
28479 * @class Roo.Toolbar.Separator
28480 * @extends Roo.Toolbar.Item
28481 * A simple toolbar separator class
28483 * Creates a new Separator
28485 Roo.Toolbar.Separator = function(){
28486 var s = document.createElement("span");
28487 s.className = "ytb-sep";
28488 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28490 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28491 enable:Roo.emptyFn,
28492 disable:Roo.emptyFn,
28497 * @class Roo.Toolbar.Spacer
28498 * @extends Roo.Toolbar.Item
28499 * A simple element that adds extra horizontal space to a toolbar.
28501 * Creates a new Spacer
28503 Roo.Toolbar.Spacer = function(){
28504 var s = document.createElement("div");
28505 s.className = "ytb-spacer";
28506 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28508 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28509 enable:Roo.emptyFn,
28510 disable:Roo.emptyFn,
28515 * @class Roo.Toolbar.Fill
28516 * @extends Roo.Toolbar.Spacer
28517 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28519 * Creates a new Spacer
28521 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28523 render : function(td){
28524 td.style.width = '100%';
28525 Roo.Toolbar.Fill.superclass.render.call(this, td);
28530 * @class Roo.Toolbar.TextItem
28531 * @extends Roo.Toolbar.Item
28532 * A simple class that renders text directly into a toolbar.
28534 * Creates a new TextItem
28535 * @param {String} text
28537 Roo.Toolbar.TextItem = function(text){
28538 if (typeof(text) == 'object') {
28541 var s = document.createElement("span");
28542 s.className = "ytb-text";
28543 s.innerHTML = text;
28544 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28546 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28547 enable:Roo.emptyFn,
28548 disable:Roo.emptyFn,
28553 * @class Roo.Toolbar.Button
28554 * @extends Roo.Button
28555 * A button that renders into a toolbar.
28557 * Creates a new Button
28558 * @param {Object} config A standard {@link Roo.Button} config object
28560 Roo.Toolbar.Button = function(config){
28561 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28563 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28564 render : function(td){
28566 Roo.Toolbar.Button.superclass.render.call(this, td);
28570 * Removes and destroys this button
28572 destroy : function(){
28573 Roo.Toolbar.Button.superclass.destroy.call(this);
28574 this.td.parentNode.removeChild(this.td);
28578 * Shows this button
28581 this.hidden = false;
28582 this.td.style.display = "";
28586 * Hides this button
28589 this.hidden = true;
28590 this.td.style.display = "none";
28594 * Disables this item
28596 disable : function(){
28597 Roo.fly(this.td).addClass("x-item-disabled");
28598 this.disabled = true;
28602 * Enables this item
28604 enable : function(){
28605 Roo.fly(this.td).removeClass("x-item-disabled");
28606 this.disabled = false;
28609 // backwards compat
28610 Roo.ToolbarButton = Roo.Toolbar.Button;
28613 * @class Roo.Toolbar.SplitButton
28614 * @extends Roo.SplitButton
28615 * A menu button that renders into a toolbar.
28617 * Creates a new SplitButton
28618 * @param {Object} config A standard {@link Roo.SplitButton} config object
28620 Roo.Toolbar.SplitButton = function(config){
28621 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28623 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28624 render : function(td){
28626 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28630 * Removes and destroys this button
28632 destroy : function(){
28633 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28634 this.td.parentNode.removeChild(this.td);
28638 * Shows this button
28641 this.hidden = false;
28642 this.td.style.display = "";
28646 * Hides this button
28649 this.hidden = true;
28650 this.td.style.display = "none";
28654 // backwards compat
28655 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28657 * Ext JS Library 1.1.1
28658 * Copyright(c) 2006-2007, Ext JS, LLC.
28660 * Originally Released Under LGPL - original licence link has changed is not relivant.
28663 * <script type="text/javascript">
28667 * @class Roo.PagingToolbar
28668 * @extends Roo.Toolbar
28669 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28671 * Create a new PagingToolbar
28672 * @param {Object} config The config object
28674 Roo.PagingToolbar = function(el, ds, config)
28676 // old args format still supported... - xtype is prefered..
28677 if (typeof(el) == 'object' && el.xtype) {
28678 // created from xtype...
28680 ds = el.dataSource;
28681 el = config.container;
28684 if (config.items) {
28685 items = config.items;
28689 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28692 this.renderButtons(this.el);
28695 // supprot items array.
28697 Roo.each(items, function(e) {
28698 this.add(Roo.factory(e));
28703 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28705 * @cfg {Roo.data.Store} dataSource
28706 * The underlying data store providing the paged data
28709 * @cfg {String/HTMLElement/Element} container
28710 * container The id or element that will contain the toolbar
28713 * @cfg {Boolean} displayInfo
28714 * True to display the displayMsg (defaults to false)
28717 * @cfg {Number} pageSize
28718 * The number of records to display per page (defaults to 20)
28722 * @cfg {String} displayMsg
28723 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28725 displayMsg : 'Displaying {0} - {1} of {2}',
28727 * @cfg {String} emptyMsg
28728 * The message to display when no records are found (defaults to "No data to display")
28730 emptyMsg : 'No data to display',
28732 * Customizable piece of the default paging text (defaults to "Page")
28735 beforePageText : "Page",
28737 * Customizable piece of the default paging text (defaults to "of %0")
28740 afterPageText : "of {0}",
28742 * Customizable piece of the default paging text (defaults to "First Page")
28745 firstText : "First Page",
28747 * Customizable piece of the default paging text (defaults to "Previous Page")
28750 prevText : "Previous Page",
28752 * Customizable piece of the default paging text (defaults to "Next Page")
28755 nextText : "Next Page",
28757 * Customizable piece of the default paging text (defaults to "Last Page")
28760 lastText : "Last Page",
28762 * Customizable piece of the default paging text (defaults to "Refresh")
28765 refreshText : "Refresh",
28768 renderButtons : function(el){
28769 Roo.PagingToolbar.superclass.render.call(this, el);
28770 this.first = this.addButton({
28771 tooltip: this.firstText,
28772 cls: "x-btn-icon x-grid-page-first",
28774 handler: this.onClick.createDelegate(this, ["first"])
28776 this.prev = this.addButton({
28777 tooltip: this.prevText,
28778 cls: "x-btn-icon x-grid-page-prev",
28780 handler: this.onClick.createDelegate(this, ["prev"])
28782 //this.addSeparator();
28783 this.add(this.beforePageText);
28784 this.field = Roo.get(this.addDom({
28789 cls: "x-grid-page-number"
28791 this.field.on("keydown", this.onPagingKeydown, this);
28792 this.field.on("focus", function(){this.dom.select();});
28793 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28794 this.field.setHeight(18);
28795 //this.addSeparator();
28796 this.next = this.addButton({
28797 tooltip: this.nextText,
28798 cls: "x-btn-icon x-grid-page-next",
28800 handler: this.onClick.createDelegate(this, ["next"])
28802 this.last = this.addButton({
28803 tooltip: this.lastText,
28804 cls: "x-btn-icon x-grid-page-last",
28806 handler: this.onClick.createDelegate(this, ["last"])
28808 //this.addSeparator();
28809 this.loading = this.addButton({
28810 tooltip: this.refreshText,
28811 cls: "x-btn-icon x-grid-loading",
28812 handler: this.onClick.createDelegate(this, ["refresh"])
28815 if(this.displayInfo){
28816 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28821 updateInfo : function(){
28822 if(this.displayEl){
28823 var count = this.ds.getCount();
28824 var msg = count == 0 ?
28828 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28830 this.displayEl.update(msg);
28835 onLoad : function(ds, r, o){
28836 this.cursor = o.params ? o.params.start : 0;
28837 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28839 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28840 this.field.dom.value = ap;
28841 this.first.setDisabled(ap == 1);
28842 this.prev.setDisabled(ap == 1);
28843 this.next.setDisabled(ap == ps);
28844 this.last.setDisabled(ap == ps);
28845 this.loading.enable();
28850 getPageData : function(){
28851 var total = this.ds.getTotalCount();
28854 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28855 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28860 onLoadError : function(){
28861 this.loading.enable();
28865 onPagingKeydown : function(e){
28866 var k = e.getKey();
28867 var d = this.getPageData();
28869 var v = this.field.dom.value, pageNum;
28870 if(!v || isNaN(pageNum = parseInt(v, 10))){
28871 this.field.dom.value = d.activePage;
28874 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28875 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28878 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))
28880 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28881 this.field.dom.value = pageNum;
28882 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28885 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28887 var v = this.field.dom.value, pageNum;
28888 var increment = (e.shiftKey) ? 10 : 1;
28889 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28891 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28892 this.field.dom.value = d.activePage;
28895 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28897 this.field.dom.value = parseInt(v, 10) + increment;
28898 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28899 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28906 beforeLoad : function(){
28908 this.loading.disable();
28913 onClick : function(which){
28917 ds.load({params:{start: 0, limit: this.pageSize}});
28920 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28923 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28926 var total = ds.getTotalCount();
28927 var extra = total % this.pageSize;
28928 var lastStart = extra ? (total - extra) : total-this.pageSize;
28929 ds.load({params:{start: lastStart, limit: this.pageSize}});
28932 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28938 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28939 * @param {Roo.data.Store} store The data store to unbind
28941 unbind : function(ds){
28942 ds.un("beforeload", this.beforeLoad, this);
28943 ds.un("load", this.onLoad, this);
28944 ds.un("loadexception", this.onLoadError, this);
28945 ds.un("remove", this.updateInfo, this);
28946 ds.un("add", this.updateInfo, this);
28947 this.ds = undefined;
28951 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28952 * @param {Roo.data.Store} store The data store to bind
28954 bind : function(ds){
28955 ds.on("beforeload", this.beforeLoad, this);
28956 ds.on("load", this.onLoad, this);
28957 ds.on("loadexception", this.onLoadError, this);
28958 ds.on("remove", this.updateInfo, this);
28959 ds.on("add", this.updateInfo, this);
28964 * Ext JS Library 1.1.1
28965 * Copyright(c) 2006-2007, Ext JS, LLC.
28967 * Originally Released Under LGPL - original licence link has changed is not relivant.
28970 * <script type="text/javascript">
28974 * @class Roo.Resizable
28975 * @extends Roo.util.Observable
28976 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28977 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28978 * 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
28979 * the element will be wrapped for you automatically.</p>
28980 * <p>Here is the list of valid resize handles:</p>
28983 ------ -------------------
28992 'hd' horizontal drag
28995 * <p>Here's an example showing the creation of a typical Resizable:</p>
28997 var resizer = new Roo.Resizable("element-id", {
29005 resizer.on("resize", myHandler);
29007 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29008 * resizer.east.setDisplayed(false);</p>
29009 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29010 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29011 * resize operation's new size (defaults to [0, 0])
29012 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29013 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29014 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29015 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29016 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29017 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29018 * @cfg {Number} width The width of the element in pixels (defaults to null)
29019 * @cfg {Number} height The height of the element in pixels (defaults to null)
29020 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29021 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29022 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29023 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29024 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29025 * in favor of the handles config option (defaults to false)
29026 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29027 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29028 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29029 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29030 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29031 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29032 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29033 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29034 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29035 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29036 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29038 * Create a new resizable component
29039 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29040 * @param {Object} config configuration options
29042 Roo.Resizable = function(el, config)
29044 this.el = Roo.get(el);
29046 if(config && config.wrap){
29047 config.resizeChild = this.el;
29048 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29049 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29050 this.el.setStyle("overflow", "hidden");
29051 this.el.setPositioning(config.resizeChild.getPositioning());
29052 config.resizeChild.clearPositioning();
29053 if(!config.width || !config.height){
29054 var csize = config.resizeChild.getSize();
29055 this.el.setSize(csize.width, csize.height);
29057 if(config.pinned && !config.adjustments){
29058 config.adjustments = "auto";
29062 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29063 this.proxy.unselectable();
29064 this.proxy.enableDisplayMode('block');
29066 Roo.apply(this, config);
29069 this.disableTrackOver = true;
29070 this.el.addClass("x-resizable-pinned");
29072 // if the element isn't positioned, make it relative
29073 var position = this.el.getStyle("position");
29074 if(position != "absolute" && position != "fixed"){
29075 this.el.setStyle("position", "relative");
29077 if(!this.handles){ // no handles passed, must be legacy style
29078 this.handles = 's,e,se';
29079 if(this.multiDirectional){
29080 this.handles += ',n,w';
29083 if(this.handles == "all"){
29084 this.handles = "n s e w ne nw se sw";
29086 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29087 var ps = Roo.Resizable.positions;
29088 for(var i = 0, len = hs.length; i < len; i++){
29089 if(hs[i] && ps[hs[i]]){
29090 var pos = ps[hs[i]];
29091 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29095 this.corner = this.southeast;
29097 // updateBox = the box can move..
29098 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29099 this.updateBox = true;
29102 this.activeHandle = null;
29104 if(this.resizeChild){
29105 if(typeof this.resizeChild == "boolean"){
29106 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29108 this.resizeChild = Roo.get(this.resizeChild, true);
29112 if(this.adjustments == "auto"){
29113 var rc = this.resizeChild;
29114 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29115 if(rc && (hw || hn)){
29116 rc.position("relative");
29117 rc.setLeft(hw ? hw.el.getWidth() : 0);
29118 rc.setTop(hn ? hn.el.getHeight() : 0);
29120 this.adjustments = [
29121 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29122 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29126 if(this.draggable){
29127 this.dd = this.dynamic ?
29128 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29129 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29135 * @event beforeresize
29136 * Fired before resize is allowed. Set enabled to false to cancel resize.
29137 * @param {Roo.Resizable} this
29138 * @param {Roo.EventObject} e The mousedown event
29140 "beforeresize" : true,
29143 * Fired a resizing.
29144 * @param {Roo.Resizable} this
29145 * @param {Number} x The new x position
29146 * @param {Number} y The new y position
29147 * @param {Number} w The new w width
29148 * @param {Number} h The new h hight
29149 * @param {Roo.EventObject} e The mouseup event
29154 * Fired after a resize.
29155 * @param {Roo.Resizable} this
29156 * @param {Number} width The new width
29157 * @param {Number} height The new height
29158 * @param {Roo.EventObject} e The mouseup event
29163 if(this.width !== null && this.height !== null){
29164 this.resizeTo(this.width, this.height);
29166 this.updateChildSize();
29169 this.el.dom.style.zoom = 1;
29171 Roo.Resizable.superclass.constructor.call(this);
29174 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29175 resizeChild : false,
29176 adjustments : [0, 0],
29186 multiDirectional : false,
29187 disableTrackOver : false,
29188 easing : 'easeOutStrong',
29189 widthIncrement : 0,
29190 heightIncrement : 0,
29194 preserveRatio : false,
29195 transparent: false,
29201 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29203 constrainTo: undefined,
29205 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29207 resizeRegion: undefined,
29211 * Perform a manual resize
29212 * @param {Number} width
29213 * @param {Number} height
29215 resizeTo : function(width, height){
29216 this.el.setSize(width, height);
29217 this.updateChildSize();
29218 this.fireEvent("resize", this, width, height, null);
29222 startSizing : function(e, handle){
29223 this.fireEvent("beforeresize", this, e);
29224 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29227 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29228 this.overlay.unselectable();
29229 this.overlay.enableDisplayMode("block");
29230 this.overlay.on("mousemove", this.onMouseMove, this);
29231 this.overlay.on("mouseup", this.onMouseUp, this);
29233 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29235 this.resizing = true;
29236 this.startBox = this.el.getBox();
29237 this.startPoint = e.getXY();
29238 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29239 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29241 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29242 this.overlay.show();
29244 if(this.constrainTo) {
29245 var ct = Roo.get(this.constrainTo);
29246 this.resizeRegion = ct.getRegion().adjust(
29247 ct.getFrameWidth('t'),
29248 ct.getFrameWidth('l'),
29249 -ct.getFrameWidth('b'),
29250 -ct.getFrameWidth('r')
29254 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29256 this.proxy.setBox(this.startBox);
29258 this.proxy.setStyle('visibility', 'visible');
29264 onMouseDown : function(handle, e){
29267 this.activeHandle = handle;
29268 this.startSizing(e, handle);
29273 onMouseUp : function(e){
29274 var size = this.resizeElement();
29275 this.resizing = false;
29277 this.overlay.hide();
29279 this.fireEvent("resize", this, size.width, size.height, e);
29283 updateChildSize : function(){
29285 if(this.resizeChild){
29287 var child = this.resizeChild;
29288 var adj = this.adjustments;
29289 if(el.dom.offsetWidth){
29290 var b = el.getSize(true);
29291 child.setSize(b.width+adj[0], b.height+adj[1]);
29293 // Second call here for IE
29294 // The first call enables instant resizing and
29295 // the second call corrects scroll bars if they
29298 setTimeout(function(){
29299 if(el.dom.offsetWidth){
29300 var b = el.getSize(true);
29301 child.setSize(b.width+adj[0], b.height+adj[1]);
29309 snap : function(value, inc, min){
29310 if(!inc || !value) return value;
29311 var newValue = value;
29312 var m = value % inc;
29315 newValue = value + (inc-m);
29317 newValue = value - m;
29320 return Math.max(min, newValue);
29324 resizeElement : function(){
29325 var box = this.proxy.getBox();
29326 if(this.updateBox){
29327 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29329 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29331 this.updateChildSize();
29339 constrain : function(v, diff, m, mx){
29342 }else if(v - diff > mx){
29349 onMouseMove : function(e){
29352 try{// try catch so if something goes wrong the user doesn't get hung
29354 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29358 //var curXY = this.startPoint;
29359 var curSize = this.curSize || this.startBox;
29360 var x = this.startBox.x, y = this.startBox.y;
29361 var ox = x, oy = y;
29362 var w = curSize.width, h = curSize.height;
29363 var ow = w, oh = h;
29364 var mw = this.minWidth, mh = this.minHeight;
29365 var mxw = this.maxWidth, mxh = this.maxHeight;
29366 var wi = this.widthIncrement;
29367 var hi = this.heightIncrement;
29369 var eventXY = e.getXY();
29370 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29371 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29373 var pos = this.activeHandle.position;
29378 w = Math.min(Math.max(mw, w), mxw);
29383 h = Math.min(Math.max(mh, h), mxh);
29388 w = Math.min(Math.max(mw, w), mxw);
29389 h = Math.min(Math.max(mh, h), mxh);
29392 diffY = this.constrain(h, diffY, mh, mxh);
29399 var adiffX = Math.abs(diffX);
29400 var sub = (adiffX % wi); // how much
29401 if (sub > (wi/2)) { // far enough to snap
29402 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29404 // remove difference..
29405 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29409 x = Math.max(this.minX, x);
29412 diffX = this.constrain(w, diffX, mw, mxw);
29418 w = Math.min(Math.max(mw, w), mxw);
29419 diffY = this.constrain(h, diffY, mh, mxh);
29424 diffX = this.constrain(w, diffX, mw, mxw);
29425 diffY = this.constrain(h, diffY, mh, mxh);
29432 diffX = this.constrain(w, diffX, mw, mxw);
29434 h = Math.min(Math.max(mh, h), mxh);
29440 var sw = this.snap(w, wi, mw);
29441 var sh = this.snap(h, hi, mh);
29442 if(sw != w || sh != h){
29465 if(this.preserveRatio){
29470 h = Math.min(Math.max(mh, h), mxh);
29475 w = Math.min(Math.max(mw, w), mxw);
29480 w = Math.min(Math.max(mw, w), mxw);
29486 w = Math.min(Math.max(mw, w), mxw);
29492 h = Math.min(Math.max(mh, h), mxh);
29500 h = Math.min(Math.max(mh, h), mxh);
29510 h = Math.min(Math.max(mh, h), mxh);
29518 if (pos == 'hdrag') {
29521 this.proxy.setBounds(x, y, w, h);
29523 this.resizeElement();
29527 this.fireEvent("resizing", this, x, y, w, h, e);
29531 handleOver : function(){
29533 this.el.addClass("x-resizable-over");
29538 handleOut : function(){
29539 if(!this.resizing){
29540 this.el.removeClass("x-resizable-over");
29545 * Returns the element this component is bound to.
29546 * @return {Roo.Element}
29548 getEl : function(){
29553 * Returns the resizeChild element (or null).
29554 * @return {Roo.Element}
29556 getResizeChild : function(){
29557 return this.resizeChild;
29559 groupHandler : function()
29564 * Destroys this resizable. If the element was wrapped and
29565 * removeEl is not true then the element remains.
29566 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29568 destroy : function(removeEl){
29569 this.proxy.remove();
29571 this.overlay.removeAllListeners();
29572 this.overlay.remove();
29574 var ps = Roo.Resizable.positions;
29576 if(typeof ps[k] != "function" && this[ps[k]]){
29577 var h = this[ps[k]];
29578 h.el.removeAllListeners();
29583 this.el.update("");
29590 // hash to map config positions to true positions
29591 Roo.Resizable.positions = {
29592 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29597 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29599 // only initialize the template if resizable is used
29600 var tpl = Roo.DomHelper.createTemplate(
29601 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29604 Roo.Resizable.Handle.prototype.tpl = tpl;
29606 this.position = pos;
29608 // show north drag fro topdra
29609 var handlepos = pos == 'hdrag' ? 'north' : pos;
29611 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29612 if (pos == 'hdrag') {
29613 this.el.setStyle('cursor', 'pointer');
29615 this.el.unselectable();
29617 this.el.setOpacity(0);
29619 this.el.on("mousedown", this.onMouseDown, this);
29620 if(!disableTrackOver){
29621 this.el.on("mouseover", this.onMouseOver, this);
29622 this.el.on("mouseout", this.onMouseOut, this);
29627 Roo.Resizable.Handle.prototype = {
29628 afterResize : function(rz){
29633 onMouseDown : function(e){
29634 this.rz.onMouseDown(this, e);
29637 onMouseOver : function(e){
29638 this.rz.handleOver(this, e);
29641 onMouseOut : function(e){
29642 this.rz.handleOut(this, e);
29646 * Ext JS Library 1.1.1
29647 * Copyright(c) 2006-2007, Ext JS, LLC.
29649 * Originally Released Under LGPL - original licence link has changed is not relivant.
29652 * <script type="text/javascript">
29656 * @class Roo.Editor
29657 * @extends Roo.Component
29658 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29660 * Create a new Editor
29661 * @param {Roo.form.Field} field The Field object (or descendant)
29662 * @param {Object} config The config object
29664 Roo.Editor = function(field, config){
29665 Roo.Editor.superclass.constructor.call(this, config);
29666 this.field = field;
29669 * @event beforestartedit
29670 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29671 * false from the handler of this event.
29672 * @param {Editor} this
29673 * @param {Roo.Element} boundEl The underlying element bound to this editor
29674 * @param {Mixed} value The field value being set
29676 "beforestartedit" : true,
29679 * Fires when this editor is displayed
29680 * @param {Roo.Element} boundEl The underlying element bound to this editor
29681 * @param {Mixed} value The starting field value
29683 "startedit" : true,
29685 * @event beforecomplete
29686 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29687 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29688 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29689 * event will not fire since no edit actually occurred.
29690 * @param {Editor} this
29691 * @param {Mixed} value The current field value
29692 * @param {Mixed} startValue The original field value
29694 "beforecomplete" : true,
29697 * Fires after editing is complete and any changed value has been written to the underlying field.
29698 * @param {Editor} this
29699 * @param {Mixed} value The current field value
29700 * @param {Mixed} startValue The original field value
29704 * @event specialkey
29705 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29706 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29707 * @param {Roo.form.Field} this
29708 * @param {Roo.EventObject} e The event object
29710 "specialkey" : true
29714 Roo.extend(Roo.Editor, Roo.Component, {
29716 * @cfg {Boolean/String} autosize
29717 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29718 * or "height" to adopt the height only (defaults to false)
29721 * @cfg {Boolean} revertInvalid
29722 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29723 * validation fails (defaults to true)
29726 * @cfg {Boolean} ignoreNoChange
29727 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29728 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29729 * will never be ignored.
29732 * @cfg {Boolean} hideEl
29733 * False to keep the bound element visible while the editor is displayed (defaults to true)
29736 * @cfg {Mixed} value
29737 * The data value of the underlying field (defaults to "")
29741 * @cfg {String} alignment
29742 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29746 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29747 * for bottom-right shadow (defaults to "frame")
29751 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29755 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29757 completeOnEnter : false,
29759 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29761 cancelOnEsc : false,
29763 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29768 onRender : function(ct, position){
29769 this.el = new Roo.Layer({
29770 shadow: this.shadow,
29776 constrain: this.constrain
29778 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29779 if(this.field.msgTarget != 'title'){
29780 this.field.msgTarget = 'qtip';
29782 this.field.render(this.el);
29784 this.field.el.dom.setAttribute('autocomplete', 'off');
29786 this.field.on("specialkey", this.onSpecialKey, this);
29787 if(this.swallowKeys){
29788 this.field.el.swallowEvent(['keydown','keypress']);
29791 this.field.on("blur", this.onBlur, this);
29792 if(this.field.grow){
29793 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29797 onSpecialKey : function(field, e)
29799 //Roo.log('editor onSpecialKey');
29800 if(this.completeOnEnter && e.getKey() == e.ENTER){
29802 this.completeEdit();
29805 // do not fire special key otherwise it might hide close the editor...
29806 if(e.getKey() == e.ENTER){
29809 if(this.cancelOnEsc && e.getKey() == e.ESC){
29813 this.fireEvent('specialkey', field, e);
29818 * Starts the editing process and shows the editor.
29819 * @param {String/HTMLElement/Element} el The element to edit
29820 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29821 * to the innerHTML of el.
29823 startEdit : function(el, value){
29825 this.completeEdit();
29827 this.boundEl = Roo.get(el);
29828 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29829 if(!this.rendered){
29830 this.render(this.parentEl || document.body);
29832 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29835 this.startValue = v;
29836 this.field.setValue(v);
29838 var sz = this.boundEl.getSize();
29839 switch(this.autoSize){
29841 this.setSize(sz.width, "");
29844 this.setSize("", sz.height);
29847 this.setSize(sz.width, sz.height);
29850 this.el.alignTo(this.boundEl, this.alignment);
29851 this.editing = true;
29853 Roo.QuickTips.disable();
29859 * Sets the height and width of this editor.
29860 * @param {Number} width The new width
29861 * @param {Number} height The new height
29863 setSize : function(w, h){
29864 this.field.setSize(w, h);
29871 * Realigns the editor to the bound field based on the current alignment config value.
29873 realign : function(){
29874 this.el.alignTo(this.boundEl, this.alignment);
29878 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29879 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29881 completeEdit : function(remainVisible){
29885 var v = this.getValue();
29886 if(this.revertInvalid !== false && !this.field.isValid()){
29887 v = this.startValue;
29888 this.cancelEdit(true);
29890 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29891 this.editing = false;
29895 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29896 this.editing = false;
29897 if(this.updateEl && this.boundEl){
29898 this.boundEl.update(v);
29900 if(remainVisible !== true){
29903 this.fireEvent("complete", this, v, this.startValue);
29908 onShow : function(){
29910 if(this.hideEl !== false){
29911 this.boundEl.hide();
29914 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29915 this.fixIEFocus = true;
29916 this.deferredFocus.defer(50, this);
29918 this.field.focus();
29920 this.fireEvent("startedit", this.boundEl, this.startValue);
29923 deferredFocus : function(){
29925 this.field.focus();
29930 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29931 * reverted to the original starting value.
29932 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29933 * cancel (defaults to false)
29935 cancelEdit : function(remainVisible){
29937 this.setValue(this.startValue);
29938 if(remainVisible !== true){
29945 onBlur : function(){
29946 if(this.allowBlur !== true && this.editing){
29947 this.completeEdit();
29952 onHide : function(){
29954 this.completeEdit();
29958 if(this.field.collapse){
29959 this.field.collapse();
29962 if(this.hideEl !== false){
29963 this.boundEl.show();
29966 Roo.QuickTips.enable();
29971 * Sets the data value of the editor
29972 * @param {Mixed} value Any valid value supported by the underlying field
29974 setValue : function(v){
29975 this.field.setValue(v);
29979 * Gets the data value of the editor
29980 * @return {Mixed} The data value
29982 getValue : function(){
29983 return this.field.getValue();
29987 * Ext JS Library 1.1.1
29988 * Copyright(c) 2006-2007, Ext JS, LLC.
29990 * Originally Released Under LGPL - original licence link has changed is not relivant.
29993 * <script type="text/javascript">
29997 * @class Roo.BasicDialog
29998 * @extends Roo.util.Observable
29999 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30001 var dlg = new Roo.BasicDialog("my-dlg", {
30010 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30011 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30012 dlg.addButton('Cancel', dlg.hide, dlg);
30015 <b>A Dialog should always be a direct child of the body element.</b>
30016 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30017 * @cfg {String} title Default text to display in the title bar (defaults to null)
30018 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30019 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30020 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30021 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30022 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30023 * (defaults to null with no animation)
30024 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30025 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30026 * property for valid values (defaults to 'all')
30027 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30028 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30029 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30030 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30031 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30032 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30033 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30034 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30035 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30036 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30037 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30038 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30039 * draggable = true (defaults to false)
30040 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30041 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30042 * shadow (defaults to false)
30043 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30044 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30045 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30046 * @cfg {Array} buttons Array of buttons
30047 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30049 * Create a new BasicDialog.
30050 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30051 * @param {Object} config Configuration options
30053 Roo.BasicDialog = function(el, config){
30054 this.el = Roo.get(el);
30055 var dh = Roo.DomHelper;
30056 if(!this.el && config && config.autoCreate){
30057 if(typeof config.autoCreate == "object"){
30058 if(!config.autoCreate.id){
30059 config.autoCreate.id = el;
30061 this.el = dh.append(document.body,
30062 config.autoCreate, true);
30064 this.el = dh.append(document.body,
30065 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30069 el.setDisplayed(true);
30070 el.hide = this.hideAction;
30072 el.addClass("x-dlg");
30074 Roo.apply(this, config);
30076 this.proxy = el.createProxy("x-dlg-proxy");
30077 this.proxy.hide = this.hideAction;
30078 this.proxy.setOpacity(.5);
30082 el.setWidth(config.width);
30085 el.setHeight(config.height);
30087 this.size = el.getSize();
30088 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30089 this.xy = [config.x,config.y];
30091 this.xy = el.getCenterXY(true);
30093 /** The header element @type Roo.Element */
30094 this.header = el.child("> .x-dlg-hd");
30095 /** The body element @type Roo.Element */
30096 this.body = el.child("> .x-dlg-bd");
30097 /** The footer element @type Roo.Element */
30098 this.footer = el.child("> .x-dlg-ft");
30101 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30104 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30107 this.header.unselectable();
30109 this.header.update(this.title);
30111 // this element allows the dialog to be focused for keyboard event
30112 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30113 this.focusEl.swallowEvent("click", true);
30115 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30117 // wrap the body and footer for special rendering
30118 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30120 this.bwrap.dom.appendChild(this.footer.dom);
30123 this.bg = this.el.createChild({
30124 tag: "div", cls:"x-dlg-bg",
30125 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30127 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30130 if(this.autoScroll !== false && !this.autoTabs){
30131 this.body.setStyle("overflow", "auto");
30134 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30136 if(this.closable !== false){
30137 this.el.addClass("x-dlg-closable");
30138 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30139 this.close.on("click", this.closeClick, this);
30140 this.close.addClassOnOver("x-dlg-close-over");
30142 if(this.collapsible !== false){
30143 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30144 this.collapseBtn.on("click", this.collapseClick, this);
30145 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30146 this.header.on("dblclick", this.collapseClick, this);
30148 if(this.resizable !== false){
30149 this.el.addClass("x-dlg-resizable");
30150 this.resizer = new Roo.Resizable(el, {
30151 minWidth: this.minWidth || 80,
30152 minHeight:this.minHeight || 80,
30153 handles: this.resizeHandles || "all",
30156 this.resizer.on("beforeresize", this.beforeResize, this);
30157 this.resizer.on("resize", this.onResize, this);
30159 if(this.draggable !== false){
30160 el.addClass("x-dlg-draggable");
30161 if (!this.proxyDrag) {
30162 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30165 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30167 dd.setHandleElId(this.header.id);
30168 dd.endDrag = this.endMove.createDelegate(this);
30169 dd.startDrag = this.startMove.createDelegate(this);
30170 dd.onDrag = this.onDrag.createDelegate(this);
30175 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30176 this.mask.enableDisplayMode("block");
30178 this.el.addClass("x-dlg-modal");
30181 this.shadow = new Roo.Shadow({
30182 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30183 offset : this.shadowOffset
30186 this.shadowOffset = 0;
30188 if(Roo.useShims && this.shim !== false){
30189 this.shim = this.el.createShim();
30190 this.shim.hide = this.hideAction;
30198 if (this.buttons) {
30199 var bts= this.buttons;
30201 Roo.each(bts, function(b) {
30210 * Fires when a key is pressed
30211 * @param {Roo.BasicDialog} this
30212 * @param {Roo.EventObject} e
30217 * Fires when this dialog is moved by the user.
30218 * @param {Roo.BasicDialog} this
30219 * @param {Number} x The new page X
30220 * @param {Number} y The new page Y
30225 * Fires when this dialog is resized by the user.
30226 * @param {Roo.BasicDialog} this
30227 * @param {Number} width The new width
30228 * @param {Number} height The new height
30232 * @event beforehide
30233 * Fires before this dialog is hidden.
30234 * @param {Roo.BasicDialog} this
30236 "beforehide" : true,
30239 * Fires when this dialog is hidden.
30240 * @param {Roo.BasicDialog} this
30244 * @event beforeshow
30245 * Fires before this dialog is shown.
30246 * @param {Roo.BasicDialog} this
30248 "beforeshow" : true,
30251 * Fires when this dialog is shown.
30252 * @param {Roo.BasicDialog} this
30256 el.on("keydown", this.onKeyDown, this);
30257 el.on("mousedown", this.toFront, this);
30258 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30260 Roo.DialogManager.register(this);
30261 Roo.BasicDialog.superclass.constructor.call(this);
30264 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30265 shadowOffset: Roo.isIE ? 6 : 5,
30268 minButtonWidth: 75,
30269 defaultButton: null,
30270 buttonAlign: "right",
30275 * Sets the dialog title text
30276 * @param {String} text The title text to display
30277 * @return {Roo.BasicDialog} this
30279 setTitle : function(text){
30280 this.header.update(text);
30285 closeClick : function(){
30290 collapseClick : function(){
30291 this[this.collapsed ? "expand" : "collapse"]();
30295 * Collapses the dialog to its minimized state (only the title bar is visible).
30296 * Equivalent to the user clicking the collapse dialog button.
30298 collapse : function(){
30299 if(!this.collapsed){
30300 this.collapsed = true;
30301 this.el.addClass("x-dlg-collapsed");
30302 this.restoreHeight = this.el.getHeight();
30303 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30308 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30309 * clicking the expand dialog button.
30311 expand : function(){
30312 if(this.collapsed){
30313 this.collapsed = false;
30314 this.el.removeClass("x-dlg-collapsed");
30315 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30320 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30321 * @return {Roo.TabPanel} The tabs component
30323 initTabs : function(){
30324 var tabs = this.getTabs();
30325 while(tabs.getTab(0)){
30328 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30330 tabs.addTab(Roo.id(dom), dom.title);
30338 beforeResize : function(){
30339 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30343 onResize : function(){
30344 this.refreshSize();
30345 this.syncBodyHeight();
30346 this.adjustAssets();
30348 this.fireEvent("resize", this, this.size.width, this.size.height);
30352 onKeyDown : function(e){
30353 if(this.isVisible()){
30354 this.fireEvent("keydown", this, e);
30359 * Resizes the dialog.
30360 * @param {Number} width
30361 * @param {Number} height
30362 * @return {Roo.BasicDialog} this
30364 resizeTo : function(width, height){
30365 this.el.setSize(width, height);
30366 this.size = {width: width, height: height};
30367 this.syncBodyHeight();
30368 if(this.fixedcenter){
30371 if(this.isVisible()){
30372 this.constrainXY();
30373 this.adjustAssets();
30375 this.fireEvent("resize", this, width, height);
30381 * Resizes the dialog to fit the specified content size.
30382 * @param {Number} width
30383 * @param {Number} height
30384 * @return {Roo.BasicDialog} this
30386 setContentSize : function(w, h){
30387 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30388 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30389 //if(!this.el.isBorderBox()){
30390 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30391 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30394 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30395 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30397 this.resizeTo(w, h);
30402 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30403 * executed in response to a particular key being pressed while the dialog is active.
30404 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30405 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30406 * @param {Function} fn The function to call
30407 * @param {Object} scope (optional) The scope of the function
30408 * @return {Roo.BasicDialog} this
30410 addKeyListener : function(key, fn, scope){
30411 var keyCode, shift, ctrl, alt;
30412 if(typeof key == "object" && !(key instanceof Array)){
30413 keyCode = key["key"];
30414 shift = key["shift"];
30415 ctrl = key["ctrl"];
30420 var handler = function(dlg, e){
30421 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30422 var k = e.getKey();
30423 if(keyCode instanceof Array){
30424 for(var i = 0, len = keyCode.length; i < len; i++){
30425 if(keyCode[i] == k){
30426 fn.call(scope || window, dlg, k, e);
30432 fn.call(scope || window, dlg, k, e);
30437 this.on("keydown", handler);
30442 * Returns the TabPanel component (creates it if it doesn't exist).
30443 * Note: If you wish to simply check for the existence of tabs without creating them,
30444 * check for a null 'tabs' property.
30445 * @return {Roo.TabPanel} The tabs component
30447 getTabs : function(){
30449 this.el.addClass("x-dlg-auto-tabs");
30450 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30451 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30457 * Adds a button to the footer section of the dialog.
30458 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30459 * object or a valid Roo.DomHelper element config
30460 * @param {Function} handler The function called when the button is clicked
30461 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30462 * @return {Roo.Button} The new button
30464 addButton : function(config, handler, scope){
30465 var dh = Roo.DomHelper;
30467 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30469 if(!this.btnContainer){
30470 var tb = this.footer.createChild({
30472 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30473 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30475 this.btnContainer = tb.firstChild.firstChild.firstChild;
30480 minWidth: this.minButtonWidth,
30483 if(typeof config == "string"){
30484 bconfig.text = config;
30487 bconfig.dhconfig = config;
30489 Roo.apply(bconfig, config);
30493 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30494 bconfig.position = Math.max(0, bconfig.position);
30495 fc = this.btnContainer.childNodes[bconfig.position];
30498 var btn = new Roo.Button(
30500 this.btnContainer.insertBefore(document.createElement("td"),fc)
30501 : this.btnContainer.appendChild(document.createElement("td")),
30502 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30505 this.syncBodyHeight();
30508 * Array of all the buttons that have been added to this dialog via addButton
30513 this.buttons.push(btn);
30518 * Sets the default button to be focused when the dialog is displayed.
30519 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30520 * @return {Roo.BasicDialog} this
30522 setDefaultButton : function(btn){
30523 this.defaultButton = btn;
30528 getHeaderFooterHeight : function(safe){
30531 height += this.header.getHeight();
30534 var fm = this.footer.getMargins();
30535 height += (this.footer.getHeight()+fm.top+fm.bottom);
30537 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30538 height += this.centerBg.getPadding("tb");
30543 syncBodyHeight : function()
30545 var bd = this.body, // the text
30546 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30548 var height = this.size.height - this.getHeaderFooterHeight(false);
30549 bd.setHeight(height-bd.getMargins("tb"));
30550 var hh = this.header.getHeight();
30551 var h = this.size.height-hh;
30554 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30555 bw.setHeight(h-cb.getPadding("tb"));
30557 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30558 bd.setWidth(bw.getWidth(true));
30560 this.tabs.syncHeight();
30562 this.tabs.el.repaint();
30568 * Restores the previous state of the dialog if Roo.state is configured.
30569 * @return {Roo.BasicDialog} this
30571 restoreState : function(){
30572 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30573 if(box && box.width){
30574 this.xy = [box.x, box.y];
30575 this.resizeTo(box.width, box.height);
30581 beforeShow : function(){
30583 if(this.fixedcenter){
30584 this.xy = this.el.getCenterXY(true);
30587 Roo.get(document.body).addClass("x-body-masked");
30588 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30591 this.constrainXY();
30595 animShow : function(){
30596 var b = Roo.get(this.animateTarget).getBox();
30597 this.proxy.setSize(b.width, b.height);
30598 this.proxy.setLocation(b.x, b.y);
30600 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30601 true, .35, this.showEl.createDelegate(this));
30605 * Shows the dialog.
30606 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30607 * @return {Roo.BasicDialog} this
30609 show : function(animateTarget){
30610 if (this.fireEvent("beforeshow", this) === false){
30613 if(this.syncHeightBeforeShow){
30614 this.syncBodyHeight();
30615 }else if(this.firstShow){
30616 this.firstShow = false;
30617 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30619 this.animateTarget = animateTarget || this.animateTarget;
30620 if(!this.el.isVisible()){
30622 if(this.animateTarget && Roo.get(this.animateTarget)){
30632 showEl : function(){
30634 this.el.setXY(this.xy);
30636 this.adjustAssets(true);
30639 // IE peekaboo bug - fix found by Dave Fenwick
30643 this.fireEvent("show", this);
30647 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30648 * dialog itself will receive focus.
30650 focus : function(){
30651 if(this.defaultButton){
30652 this.defaultButton.focus();
30654 this.focusEl.focus();
30659 constrainXY : function(){
30660 if(this.constraintoviewport !== false){
30661 if(!this.viewSize){
30662 if(this.container){
30663 var s = this.container.getSize();
30664 this.viewSize = [s.width, s.height];
30666 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30669 var s = Roo.get(this.container||document).getScroll();
30671 var x = this.xy[0], y = this.xy[1];
30672 var w = this.size.width, h = this.size.height;
30673 var vw = this.viewSize[0], vh = this.viewSize[1];
30674 // only move it if it needs it
30676 // first validate right/bottom
30677 if(x + w > vw+s.left){
30681 if(y + h > vh+s.top){
30685 // then make sure top/left isn't negative
30697 if(this.isVisible()){
30698 this.el.setLocation(x, y);
30699 this.adjustAssets();
30706 onDrag : function(){
30707 if(!this.proxyDrag){
30708 this.xy = this.el.getXY();
30709 this.adjustAssets();
30714 adjustAssets : function(doShow){
30715 var x = this.xy[0], y = this.xy[1];
30716 var w = this.size.width, h = this.size.height;
30717 if(doShow === true){
30719 this.shadow.show(this.el);
30725 if(this.shadow && this.shadow.isVisible()){
30726 this.shadow.show(this.el);
30728 if(this.shim && this.shim.isVisible()){
30729 this.shim.setBounds(x, y, w, h);
30734 adjustViewport : function(w, h){
30736 w = Roo.lib.Dom.getViewWidth();
30737 h = Roo.lib.Dom.getViewHeight();
30740 this.viewSize = [w, h];
30741 if(this.modal && this.mask.isVisible()){
30742 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30743 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30745 if(this.isVisible()){
30746 this.constrainXY();
30751 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30752 * shadow, proxy, mask, etc.) Also removes all event listeners.
30753 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30755 destroy : function(removeEl){
30756 if(this.isVisible()){
30757 this.animateTarget = null;
30760 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30762 this.tabs.destroy(removeEl);
30775 for(var i = 0, len = this.buttons.length; i < len; i++){
30776 this.buttons[i].destroy();
30779 this.el.removeAllListeners();
30780 if(removeEl === true){
30781 this.el.update("");
30784 Roo.DialogManager.unregister(this);
30788 startMove : function(){
30789 if(this.proxyDrag){
30792 if(this.constraintoviewport !== false){
30793 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30798 endMove : function(){
30799 if(!this.proxyDrag){
30800 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30802 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30805 this.refreshSize();
30806 this.adjustAssets();
30808 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30812 * Brings this dialog to the front of any other visible dialogs
30813 * @return {Roo.BasicDialog} this
30815 toFront : function(){
30816 Roo.DialogManager.bringToFront(this);
30821 * Sends this dialog to the back (under) of any other visible dialogs
30822 * @return {Roo.BasicDialog} this
30824 toBack : function(){
30825 Roo.DialogManager.sendToBack(this);
30830 * Centers this dialog in the viewport
30831 * @return {Roo.BasicDialog} this
30833 center : function(){
30834 var xy = this.el.getCenterXY(true);
30835 this.moveTo(xy[0], xy[1]);
30840 * Moves the dialog's top-left corner to the specified point
30841 * @param {Number} x
30842 * @param {Number} y
30843 * @return {Roo.BasicDialog} this
30845 moveTo : function(x, y){
30847 if(this.isVisible()){
30848 this.el.setXY(this.xy);
30849 this.adjustAssets();
30855 * Aligns the dialog to the specified element
30856 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30857 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30858 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30859 * @return {Roo.BasicDialog} this
30861 alignTo : function(element, position, offsets){
30862 this.xy = this.el.getAlignToXY(element, position, offsets);
30863 if(this.isVisible()){
30864 this.el.setXY(this.xy);
30865 this.adjustAssets();
30871 * Anchors an element to another element and realigns it when the window is resized.
30872 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30873 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30874 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30875 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30876 * is a number, it is used as the buffer delay (defaults to 50ms).
30877 * @return {Roo.BasicDialog} this
30879 anchorTo : function(el, alignment, offsets, monitorScroll){
30880 var action = function(){
30881 this.alignTo(el, alignment, offsets);
30883 Roo.EventManager.onWindowResize(action, this);
30884 var tm = typeof monitorScroll;
30885 if(tm != 'undefined'){
30886 Roo.EventManager.on(window, 'scroll', action, this,
30887 {buffer: tm == 'number' ? monitorScroll : 50});
30894 * Returns true if the dialog is visible
30895 * @return {Boolean}
30897 isVisible : function(){
30898 return this.el.isVisible();
30902 animHide : function(callback){
30903 var b = Roo.get(this.animateTarget).getBox();
30905 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30907 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30908 this.hideEl.createDelegate(this, [callback]));
30912 * Hides the dialog.
30913 * @param {Function} callback (optional) Function to call when the dialog is hidden
30914 * @return {Roo.BasicDialog} this
30916 hide : function(callback){
30917 if (this.fireEvent("beforehide", this) === false){
30921 this.shadow.hide();
30926 // sometimes animateTarget seems to get set.. causing problems...
30927 // this just double checks..
30928 if(this.animateTarget && Roo.get(this.animateTarget)) {
30929 this.animHide(callback);
30932 this.hideEl(callback);
30938 hideEl : function(callback){
30942 Roo.get(document.body).removeClass("x-body-masked");
30944 this.fireEvent("hide", this);
30945 if(typeof callback == "function"){
30951 hideAction : function(){
30952 this.setLeft("-10000px");
30953 this.setTop("-10000px");
30954 this.setStyle("visibility", "hidden");
30958 refreshSize : function(){
30959 this.size = this.el.getSize();
30960 this.xy = this.el.getXY();
30961 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30965 // z-index is managed by the DialogManager and may be overwritten at any time
30966 setZIndex : function(index){
30968 this.mask.setStyle("z-index", index);
30971 this.shim.setStyle("z-index", ++index);
30974 this.shadow.setZIndex(++index);
30976 this.el.setStyle("z-index", ++index);
30978 this.proxy.setStyle("z-index", ++index);
30981 this.resizer.proxy.setStyle("z-index", ++index);
30984 this.lastZIndex = index;
30988 * Returns the element for this dialog
30989 * @return {Roo.Element} The underlying dialog Element
30991 getEl : function(){
30997 * @class Roo.DialogManager
30998 * Provides global access to BasicDialogs that have been created and
30999 * support for z-indexing (layering) multiple open dialogs.
31001 Roo.DialogManager = function(){
31003 var accessList = [];
31007 var sortDialogs = function(d1, d2){
31008 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31012 var orderDialogs = function(){
31013 accessList.sort(sortDialogs);
31014 var seed = Roo.DialogManager.zseed;
31015 for(var i = 0, len = accessList.length; i < len; i++){
31016 var dlg = accessList[i];
31018 dlg.setZIndex(seed + (i*10));
31025 * The starting z-index for BasicDialogs (defaults to 9000)
31026 * @type Number The z-index value
31031 register : function(dlg){
31032 list[dlg.id] = dlg;
31033 accessList.push(dlg);
31037 unregister : function(dlg){
31038 delete list[dlg.id];
31041 if(!accessList.indexOf){
31042 for( i = 0, len = accessList.length; i < len; i++){
31043 if(accessList[i] == dlg){
31044 accessList.splice(i, 1);
31049 i = accessList.indexOf(dlg);
31051 accessList.splice(i, 1);
31057 * Gets a registered dialog by id
31058 * @param {String/Object} id The id of the dialog or a dialog
31059 * @return {Roo.BasicDialog} this
31061 get : function(id){
31062 return typeof id == "object" ? id : list[id];
31066 * Brings the specified dialog to the front
31067 * @param {String/Object} dlg The id of the dialog or a dialog
31068 * @return {Roo.BasicDialog} this
31070 bringToFront : function(dlg){
31071 dlg = this.get(dlg);
31074 dlg._lastAccess = new Date().getTime();
31081 * Sends the specified dialog to the back
31082 * @param {String/Object} dlg The id of the dialog or a dialog
31083 * @return {Roo.BasicDialog} this
31085 sendToBack : function(dlg){
31086 dlg = this.get(dlg);
31087 dlg._lastAccess = -(new Date().getTime());
31093 * Hides all dialogs
31095 hideAll : function(){
31096 for(var id in list){
31097 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31106 * @class Roo.LayoutDialog
31107 * @extends Roo.BasicDialog
31108 * Dialog which provides adjustments for working with a layout in a Dialog.
31109 * Add your necessary layout config options to the dialog's config.<br>
31110 * Example usage (including a nested layout):
31113 dialog = new Roo.LayoutDialog("download-dlg", {
31122 // layout config merges with the dialog config
31124 tabPosition: "top",
31125 alwaysShowTabs: true
31128 dialog.addKeyListener(27, dialog.hide, dialog);
31129 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31130 dialog.addButton("Build It!", this.getDownload, this);
31132 // we can even add nested layouts
31133 var innerLayout = new Roo.BorderLayout("dl-inner", {
31143 innerLayout.beginUpdate();
31144 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31145 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31146 innerLayout.endUpdate(true);
31148 var layout = dialog.getLayout();
31149 layout.beginUpdate();
31150 layout.add("center", new Roo.ContentPanel("standard-panel",
31151 {title: "Download the Source", fitToFrame:true}));
31152 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31153 {title: "Build your own roo.js"}));
31154 layout.getRegion("center").showPanel(sp);
31155 layout.endUpdate();
31159 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31160 * @param {Object} config configuration options
31162 Roo.LayoutDialog = function(el, cfg){
31165 if (typeof(cfg) == 'undefined') {
31166 config = Roo.apply({}, el);
31167 // not sure why we use documentElement here.. - it should always be body.
31168 // IE7 borks horribly if we use documentElement.
31169 // webkit also does not like documentElement - it creates a body element...
31170 el = Roo.get( document.body || document.documentElement ).createChild();
31171 //config.autoCreate = true;
31175 config.autoTabs = false;
31176 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31177 this.body.setStyle({overflow:"hidden", position:"relative"});
31178 this.layout = new Roo.BorderLayout(this.body.dom, config);
31179 this.layout.monitorWindowResize = false;
31180 this.el.addClass("x-dlg-auto-layout");
31181 // fix case when center region overwrites center function
31182 this.center = Roo.BasicDialog.prototype.center;
31183 this.on("show", this.layout.layout, this.layout, true);
31184 if (config.items) {
31185 var xitems = config.items;
31186 delete config.items;
31187 Roo.each(xitems, this.addxtype, this);
31192 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31194 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31197 endUpdate : function(){
31198 this.layout.endUpdate();
31202 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31205 beginUpdate : function(){
31206 this.layout.beginUpdate();
31210 * Get the BorderLayout for this dialog
31211 * @return {Roo.BorderLayout}
31213 getLayout : function(){
31214 return this.layout;
31217 showEl : function(){
31218 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31220 this.layout.layout();
31225 // Use the syncHeightBeforeShow config option to control this automatically
31226 syncBodyHeight : function(){
31227 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31228 if(this.layout){this.layout.layout();}
31232 * Add an xtype element (actually adds to the layout.)
31233 * @return {Object} xdata xtype object data.
31236 addxtype : function(c) {
31237 return this.layout.addxtype(c);
31241 * Ext JS Library 1.1.1
31242 * Copyright(c) 2006-2007, Ext JS, LLC.
31244 * Originally Released Under LGPL - original licence link has changed is not relivant.
31247 * <script type="text/javascript">
31251 * @class Roo.MessageBox
31252 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31256 Roo.Msg.alert('Status', 'Changes saved successfully.');
31258 // Prompt for user data:
31259 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31261 // process text value...
31265 // Show a dialog using config options:
31267 title:'Save Changes?',
31268 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31269 buttons: Roo.Msg.YESNOCANCEL,
31276 Roo.MessageBox = function(){
31277 var dlg, opt, mask, waitTimer;
31278 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31279 var buttons, activeTextEl, bwidth;
31282 var handleButton = function(button){
31284 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31288 var handleHide = function(){
31289 if(opt && opt.cls){
31290 dlg.el.removeClass(opt.cls);
31293 Roo.TaskMgr.stop(waitTimer);
31299 var updateButtons = function(b){
31302 buttons["ok"].hide();
31303 buttons["cancel"].hide();
31304 buttons["yes"].hide();
31305 buttons["no"].hide();
31306 dlg.footer.dom.style.display = 'none';
31309 dlg.footer.dom.style.display = '';
31310 for(var k in buttons){
31311 if(typeof buttons[k] != "function"){
31314 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31315 width += buttons[k].el.getWidth()+15;
31325 var handleEsc = function(d, k, e){
31326 if(opt && opt.closable !== false){
31336 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31337 * @return {Roo.BasicDialog} The BasicDialog element
31339 getDialog : function(){
31341 dlg = new Roo.BasicDialog("x-msg-box", {
31346 constraintoviewport:false,
31348 collapsible : false,
31351 width:400, height:100,
31352 buttonAlign:"center",
31353 closeClick : function(){
31354 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31355 handleButton("no");
31357 handleButton("cancel");
31361 dlg.on("hide", handleHide);
31363 dlg.addKeyListener(27, handleEsc);
31365 var bt = this.buttonText;
31366 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31367 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31368 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31369 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31370 bodyEl = dlg.body.createChild({
31372 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>'
31374 msgEl = bodyEl.dom.firstChild;
31375 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31376 textboxEl.enableDisplayMode();
31377 textboxEl.addKeyListener([10,13], function(){
31378 if(dlg.isVisible() && opt && opt.buttons){
31379 if(opt.buttons.ok){
31380 handleButton("ok");
31381 }else if(opt.buttons.yes){
31382 handleButton("yes");
31386 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31387 textareaEl.enableDisplayMode();
31388 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31389 progressEl.enableDisplayMode();
31390 var pf = progressEl.dom.firstChild;
31392 pp = Roo.get(pf.firstChild);
31393 pp.setHeight(pf.offsetHeight);
31401 * Updates the message box body text
31402 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31403 * the XHTML-compliant non-breaking space character '&#160;')
31404 * @return {Roo.MessageBox} This message box
31406 updateText : function(text){
31407 if(!dlg.isVisible() && !opt.width){
31408 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31410 msgEl.innerHTML = text || ' ';
31412 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31413 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31415 Math.min(opt.width || cw , this.maxWidth),
31416 Math.max(opt.minWidth || this.minWidth, bwidth)
31419 activeTextEl.setWidth(w);
31421 if(dlg.isVisible()){
31422 dlg.fixedcenter = false;
31424 // to big, make it scroll. = But as usual stupid IE does not support
31427 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31428 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31429 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31431 bodyEl.dom.style.height = '';
31432 bodyEl.dom.style.overflowY = '';
31435 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31437 bodyEl.dom.style.overflowX = '';
31440 dlg.setContentSize(w, bodyEl.getHeight());
31441 if(dlg.isVisible()){
31442 dlg.fixedcenter = true;
31448 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31449 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31450 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31451 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31452 * @return {Roo.MessageBox} This message box
31454 updateProgress : function(value, text){
31456 this.updateText(text);
31458 if (pp) { // weird bug on my firefox - for some reason this is not defined
31459 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31465 * Returns true if the message box is currently displayed
31466 * @return {Boolean} True if the message box is visible, else false
31468 isVisible : function(){
31469 return dlg && dlg.isVisible();
31473 * Hides the message box if it is displayed
31476 if(this.isVisible()){
31482 * Displays a new message box, or reinitializes an existing message box, based on the config options
31483 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31484 * The following config object properties are supported:
31486 Property Type Description
31487 ---------- --------------- ------------------------------------------------------------------------------------
31488 animEl String/Element An id or Element from which the message box should animate as it opens and
31489 closes (defaults to undefined)
31490 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31491 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31492 closable Boolean False to hide the top-right close button (defaults to true). Note that
31493 progress and wait dialogs will ignore this property and always hide the
31494 close button as they can only be closed programmatically.
31495 cls String A custom CSS class to apply to the message box element
31496 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31497 displayed (defaults to 75)
31498 fn Function A callback function to execute after closing the dialog. The arguments to the
31499 function will be btn (the name of the button that was clicked, if applicable,
31500 e.g. "ok"), and text (the value of the active text field, if applicable).
31501 Progress and wait dialogs will ignore this option since they do not respond to
31502 user actions and can only be closed programmatically, so any required function
31503 should be called by the same code after it closes the dialog.
31504 icon String A CSS class that provides a background image to be used as an icon for
31505 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31506 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31507 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31508 modal Boolean False to allow user interaction with the page while the message box is
31509 displayed (defaults to true)
31510 msg String A string that will replace the existing message box body text (defaults
31511 to the XHTML-compliant non-breaking space character ' ')
31512 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31513 progress Boolean True to display a progress bar (defaults to false)
31514 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31515 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31516 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31517 title String The title text
31518 value String The string value to set into the active textbox element if displayed
31519 wait Boolean True to display a progress bar (defaults to false)
31520 width Number The width of the dialog in pixels
31527 msg: 'Please enter your address:',
31529 buttons: Roo.MessageBox.OKCANCEL,
31532 animEl: 'addAddressBtn'
31535 * @param {Object} config Configuration options
31536 * @return {Roo.MessageBox} This message box
31538 show : function(options)
31541 // this causes nightmares if you show one dialog after another
31542 // especially on callbacks..
31544 if(this.isVisible()){
31547 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31548 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31549 Roo.log("New Dialog Message:" + options.msg )
31550 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31551 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31554 var d = this.getDialog();
31556 d.setTitle(opt.title || " ");
31557 d.close.setDisplayed(opt.closable !== false);
31558 activeTextEl = textboxEl;
31559 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31564 textareaEl.setHeight(typeof opt.multiline == "number" ?
31565 opt.multiline : this.defaultTextHeight);
31566 activeTextEl = textareaEl;
31575 progressEl.setDisplayed(opt.progress === true);
31576 this.updateProgress(0);
31577 activeTextEl.dom.value = opt.value || "";
31579 dlg.setDefaultButton(activeTextEl);
31581 var bs = opt.buttons;
31584 db = buttons["ok"];
31585 }else if(bs && bs.yes){
31586 db = buttons["yes"];
31588 dlg.setDefaultButton(db);
31590 bwidth = updateButtons(opt.buttons);
31591 this.updateText(opt.msg);
31593 d.el.addClass(opt.cls);
31595 d.proxyDrag = opt.proxyDrag === true;
31596 d.modal = opt.modal !== false;
31597 d.mask = opt.modal !== false ? mask : false;
31598 if(!d.isVisible()){
31599 // force it to the end of the z-index stack so it gets a cursor in FF
31600 document.body.appendChild(dlg.el.dom);
31601 d.animateTarget = null;
31602 d.show(options.animEl);
31608 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31609 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31610 * and closing the message box when the process is complete.
31611 * @param {String} title The title bar text
31612 * @param {String} msg The message box body text
31613 * @return {Roo.MessageBox} This message box
31615 progress : function(title, msg){
31622 minWidth: this.minProgressWidth,
31629 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31630 * If a callback function is passed it will be called after the user clicks the button, and the
31631 * id of the button that was clicked will be passed as the only parameter to the callback
31632 * (could also be the top-right close button).
31633 * @param {String} title The title bar text
31634 * @param {String} msg The message box body text
31635 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31636 * @param {Object} scope (optional) The scope of the callback function
31637 * @return {Roo.MessageBox} This message box
31639 alert : function(title, msg, fn, scope){
31652 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31653 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31654 * You are responsible for closing the message box when the process is complete.
31655 * @param {String} msg The message box body text
31656 * @param {String} title (optional) The title bar text
31657 * @return {Roo.MessageBox} This message box
31659 wait : function(msg, title){
31670 waitTimer = Roo.TaskMgr.start({
31672 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31680 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31681 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31682 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31683 * @param {String} title The title bar text
31684 * @param {String} msg The message box body text
31685 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31686 * @param {Object} scope (optional) The scope of the callback function
31687 * @return {Roo.MessageBox} This message box
31689 confirm : function(title, msg, fn, scope){
31693 buttons: this.YESNO,
31702 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31703 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31704 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31705 * (could also be the top-right close button) and the text that was entered will be passed as the two
31706 * parameters to the callback.
31707 * @param {String} title The title bar text
31708 * @param {String} msg The message box body text
31709 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31710 * @param {Object} scope (optional) The scope of the callback function
31711 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31712 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31713 * @return {Roo.MessageBox} This message box
31715 prompt : function(title, msg, fn, scope, multiline){
31719 buttons: this.OKCANCEL,
31724 multiline: multiline,
31731 * Button config that displays a single OK button
31736 * Button config that displays Yes and No buttons
31739 YESNO : {yes:true, no:true},
31741 * Button config that displays OK and Cancel buttons
31744 OKCANCEL : {ok:true, cancel:true},
31746 * Button config that displays Yes, No and Cancel buttons
31749 YESNOCANCEL : {yes:true, no:true, cancel:true},
31752 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31755 defaultTextHeight : 75,
31757 * The maximum width in pixels of the message box (defaults to 600)
31762 * The minimum width in pixels of the message box (defaults to 100)
31767 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31768 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31771 minProgressWidth : 250,
31773 * An object containing the default button text strings that can be overriden for localized language support.
31774 * Supported properties are: ok, cancel, yes and no.
31775 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31788 * Shorthand for {@link Roo.MessageBox}
31790 Roo.Msg = Roo.MessageBox;/*
31792 * Ext JS Library 1.1.1
31793 * Copyright(c) 2006-2007, Ext JS, LLC.
31795 * Originally Released Under LGPL - original licence link has changed is not relivant.
31798 * <script type="text/javascript">
31801 * @class Roo.QuickTips
31802 * Provides attractive and customizable tooltips for any element.
31805 Roo.QuickTips = function(){
31806 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31807 var ce, bd, xy, dd;
31808 var visible = false, disabled = true, inited = false;
31809 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31811 var onOver = function(e){
31815 var t = e.getTarget();
31816 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31819 if(ce && t == ce.el){
31820 clearTimeout(hideProc);
31823 if(t && tagEls[t.id]){
31824 tagEls[t.id].el = t;
31825 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31828 var ttp, et = Roo.fly(t);
31829 var ns = cfg.namespace;
31830 if(tm.interceptTitles && t.title){
31833 t.removeAttribute("title");
31834 e.preventDefault();
31836 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31839 showProc = show.defer(tm.showDelay, tm, [{
31842 width: et.getAttributeNS(ns, cfg.width),
31843 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31844 title: et.getAttributeNS(ns, cfg.title),
31845 cls: et.getAttributeNS(ns, cfg.cls)
31850 var onOut = function(e){
31851 clearTimeout(showProc);
31852 var t = e.getTarget();
31853 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31854 hideProc = setTimeout(hide, tm.hideDelay);
31858 var onMove = function(e){
31864 if(tm.trackMouse && ce){
31869 var onDown = function(e){
31870 clearTimeout(showProc);
31871 clearTimeout(hideProc);
31873 if(tm.hideOnClick){
31876 tm.enable.defer(100, tm);
31881 var getPad = function(){
31882 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31885 var show = function(o){
31889 clearTimeout(dismissProc);
31891 if(removeCls){ // in case manually hidden
31892 el.removeClass(removeCls);
31896 el.addClass(ce.cls);
31897 removeCls = ce.cls;
31900 tipTitle.update(ce.title);
31903 tipTitle.update('');
31906 el.dom.style.width = tm.maxWidth+'px';
31907 //tipBody.dom.style.width = '';
31908 tipBodyText.update(o.text);
31909 var p = getPad(), w = ce.width;
31911 var td = tipBodyText.dom;
31912 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31913 if(aw > tm.maxWidth){
31915 }else if(aw < tm.minWidth){
31921 //tipBody.setWidth(w);
31922 el.setWidth(parseInt(w, 10) + p);
31923 if(ce.autoHide === false){
31924 close.setDisplayed(true);
31929 close.setDisplayed(false);
31935 el.avoidY = xy[1]-18;
31940 el.setStyle("visibility", "visible");
31941 el.fadeIn({callback: afterShow});
31947 var afterShow = function(){
31951 if(tm.autoDismiss && ce.autoHide !== false){
31952 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31957 var hide = function(noanim){
31958 clearTimeout(dismissProc);
31959 clearTimeout(hideProc);
31961 if(el.isVisible()){
31963 if(noanim !== true && tm.animate){
31964 el.fadeOut({callback: afterHide});
31971 var afterHide = function(){
31974 el.removeClass(removeCls);
31981 * @cfg {Number} minWidth
31982 * The minimum width of the quick tip (defaults to 40)
31986 * @cfg {Number} maxWidth
31987 * The maximum width of the quick tip (defaults to 300)
31991 * @cfg {Boolean} interceptTitles
31992 * True to automatically use the element's DOM title value if available (defaults to false)
31994 interceptTitles : false,
31996 * @cfg {Boolean} trackMouse
31997 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31999 trackMouse : false,
32001 * @cfg {Boolean} hideOnClick
32002 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32004 hideOnClick : true,
32006 * @cfg {Number} showDelay
32007 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32011 * @cfg {Number} hideDelay
32012 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32016 * @cfg {Boolean} autoHide
32017 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32018 * Used in conjunction with hideDelay.
32023 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32024 * (defaults to true). Used in conjunction with autoDismissDelay.
32026 autoDismiss : true,
32029 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32031 autoDismissDelay : 5000,
32033 * @cfg {Boolean} animate
32034 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32039 * @cfg {String} title
32040 * Title text to display (defaults to ''). This can be any valid HTML markup.
32044 * @cfg {String} text
32045 * Body text to display (defaults to ''). This can be any valid HTML markup.
32049 * @cfg {String} cls
32050 * A CSS class to apply to the base quick tip element (defaults to '').
32054 * @cfg {Number} width
32055 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32056 * minWidth or maxWidth.
32061 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32062 * or display QuickTips in a page.
32065 tm = Roo.QuickTips;
32066 cfg = tm.tagConfig;
32068 if(!Roo.isReady){ // allow calling of init() before onReady
32069 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32072 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32073 el.fxDefaults = {stopFx: true};
32074 // maximum custom styling
32075 //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>');
32076 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>');
32077 tipTitle = el.child('h3');
32078 tipTitle.enableDisplayMode("block");
32079 tipBody = el.child('div.x-tip-bd');
32080 tipBodyText = el.child('div.x-tip-bd-inner');
32081 //bdLeft = el.child('div.x-tip-bd-left');
32082 //bdRight = el.child('div.x-tip-bd-right');
32083 close = el.child('div.x-tip-close');
32084 close.enableDisplayMode("block");
32085 close.on("click", hide);
32086 var d = Roo.get(document);
32087 d.on("mousedown", onDown);
32088 d.on("mouseover", onOver);
32089 d.on("mouseout", onOut);
32090 d.on("mousemove", onMove);
32091 esc = d.addKeyListener(27, hide);
32094 dd = el.initDD("default", null, {
32095 onDrag : function(){
32099 dd.setHandleElId(tipTitle.id);
32108 * Configures a new quick tip instance and assigns it to a target element. The following config options
32111 Property Type Description
32112 ---------- --------------------- ------------------------------------------------------------------------
32113 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32115 * @param {Object} config The config object
32117 register : function(config){
32118 var cs = config instanceof Array ? config : arguments;
32119 for(var i = 0, len = cs.length; i < len; i++) {
32121 var target = c.target;
32123 if(target instanceof Array){
32124 for(var j = 0, jlen = target.length; j < jlen; j++){
32125 tagEls[target[j]] = c;
32128 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32135 * Removes this quick tip from its element and destroys it.
32136 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32138 unregister : function(el){
32139 delete tagEls[Roo.id(el)];
32143 * Enable this quick tip.
32145 enable : function(){
32146 if(inited && disabled){
32148 if(locks.length < 1){
32155 * Disable this quick tip.
32157 disable : function(){
32159 clearTimeout(showProc);
32160 clearTimeout(hideProc);
32161 clearTimeout(dismissProc);
32169 * Returns true if the quick tip is enabled, else false.
32171 isEnabled : function(){
32178 attribute : "qtip",
32188 // backwards compat
32189 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32191 * Ext JS Library 1.1.1
32192 * Copyright(c) 2006-2007, Ext JS, LLC.
32194 * Originally Released Under LGPL - original licence link has changed is not relivant.
32197 * <script type="text/javascript">
32202 * @class Roo.tree.TreePanel
32203 * @extends Roo.data.Tree
32205 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32206 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32207 * @cfg {Boolean} enableDD true to enable drag and drop
32208 * @cfg {Boolean} enableDrag true to enable just drag
32209 * @cfg {Boolean} enableDrop true to enable just drop
32210 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32211 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32212 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32213 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32214 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32215 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32216 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32217 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32218 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32219 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32220 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32221 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32222 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32223 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32224 * @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>
32225 * @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>
32228 * @param {String/HTMLElement/Element} el The container element
32229 * @param {Object} config
32231 Roo.tree.TreePanel = function(el, config){
32233 var loader = false;
32235 root = config.root;
32236 delete config.root;
32238 if (config.loader) {
32239 loader = config.loader;
32240 delete config.loader;
32243 Roo.apply(this, config);
32244 Roo.tree.TreePanel.superclass.constructor.call(this);
32245 this.el = Roo.get(el);
32246 this.el.addClass('x-tree');
32247 //console.log(root);
32249 this.setRootNode( Roo.factory(root, Roo.tree));
32252 this.loader = Roo.factory(loader, Roo.tree);
32255 * Read-only. The id of the container element becomes this TreePanel's id.
32257 this.id = this.el.id;
32260 * @event beforeload
32261 * Fires before a node is loaded, return false to cancel
32262 * @param {Node} node The node being loaded
32264 "beforeload" : true,
32267 * Fires when a node is loaded
32268 * @param {Node} node The node that was loaded
32272 * @event textchange
32273 * Fires when the text for a node is changed
32274 * @param {Node} node The node
32275 * @param {String} text The new text
32276 * @param {String} oldText The old text
32278 "textchange" : true,
32280 * @event beforeexpand
32281 * Fires before a node is expanded, return false to cancel.
32282 * @param {Node} node The node
32283 * @param {Boolean} deep
32284 * @param {Boolean} anim
32286 "beforeexpand" : true,
32288 * @event beforecollapse
32289 * Fires before a node is collapsed, return false to cancel.
32290 * @param {Node} node The node
32291 * @param {Boolean} deep
32292 * @param {Boolean} anim
32294 "beforecollapse" : true,
32297 * Fires when a node is expanded
32298 * @param {Node} node The node
32302 * @event disabledchange
32303 * Fires when the disabled status of a node changes
32304 * @param {Node} node The node
32305 * @param {Boolean} disabled
32307 "disabledchange" : true,
32310 * Fires when a node is collapsed
32311 * @param {Node} node The node
32315 * @event beforeclick
32316 * Fires before click processing on a node. Return false to cancel the default action.
32317 * @param {Node} node The node
32318 * @param {Roo.EventObject} e The event object
32320 "beforeclick":true,
32322 * @event checkchange
32323 * Fires when a node with a checkbox's checked property changes
32324 * @param {Node} this This node
32325 * @param {Boolean} checked
32327 "checkchange":true,
32330 * Fires when a node is clicked
32331 * @param {Node} node The node
32332 * @param {Roo.EventObject} e The event object
32337 * Fires when a node is double clicked
32338 * @param {Node} node The node
32339 * @param {Roo.EventObject} e The event object
32343 * @event contextmenu
32344 * Fires when a node is right clicked
32345 * @param {Node} node The node
32346 * @param {Roo.EventObject} e The event object
32348 "contextmenu":true,
32350 * @event beforechildrenrendered
32351 * Fires right before the child nodes for a node are rendered
32352 * @param {Node} node The node
32354 "beforechildrenrendered":true,
32357 * Fires when a node starts being dragged
32358 * @param {Roo.tree.TreePanel} this
32359 * @param {Roo.tree.TreeNode} node
32360 * @param {event} e The raw browser event
32362 "startdrag" : true,
32365 * Fires when a drag operation is complete
32366 * @param {Roo.tree.TreePanel} this
32367 * @param {Roo.tree.TreeNode} node
32368 * @param {event} e The raw browser event
32373 * Fires when a dragged node is dropped on a valid DD target
32374 * @param {Roo.tree.TreePanel} this
32375 * @param {Roo.tree.TreeNode} node
32376 * @param {DD} dd The dd it was dropped on
32377 * @param {event} e The raw browser event
32381 * @event beforenodedrop
32382 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32383 * passed to handlers has the following properties:<br />
32384 * <ul style="padding:5px;padding-left:16px;">
32385 * <li>tree - The TreePanel</li>
32386 * <li>target - The node being targeted for the drop</li>
32387 * <li>data - The drag data from the drag source</li>
32388 * <li>point - The point of the drop - append, above or below</li>
32389 * <li>source - The drag source</li>
32390 * <li>rawEvent - Raw mouse event</li>
32391 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32392 * to be inserted by setting them on this object.</li>
32393 * <li>cancel - Set this to true to cancel the drop.</li>
32395 * @param {Object} dropEvent
32397 "beforenodedrop" : true,
32400 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32401 * passed to handlers has the following properties:<br />
32402 * <ul style="padding:5px;padding-left:16px;">
32403 * <li>tree - The TreePanel</li>
32404 * <li>target - The node being targeted for the drop</li>
32405 * <li>data - The drag data from the drag source</li>
32406 * <li>point - The point of the drop - append, above or below</li>
32407 * <li>source - The drag source</li>
32408 * <li>rawEvent - Raw mouse event</li>
32409 * <li>dropNode - Dropped node(s).</li>
32411 * @param {Object} dropEvent
32415 * @event nodedragover
32416 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32417 * passed to handlers has the following properties:<br />
32418 * <ul style="padding:5px;padding-left:16px;">
32419 * <li>tree - The TreePanel</li>
32420 * <li>target - The node being targeted for the drop</li>
32421 * <li>data - The drag data from the drag source</li>
32422 * <li>point - The point of the drop - append, above or below</li>
32423 * <li>source - The drag source</li>
32424 * <li>rawEvent - Raw mouse event</li>
32425 * <li>dropNode - Drop node(s) provided by the source.</li>
32426 * <li>cancel - Set this to true to signal drop not allowed.</li>
32428 * @param {Object} dragOverEvent
32430 "nodedragover" : true
32433 if(this.singleExpand){
32434 this.on("beforeexpand", this.restrictExpand, this);
32437 this.editor.tree = this;
32438 this.editor = Roo.factory(this.editor, Roo.tree);
32441 if (this.selModel) {
32442 this.selModel = Roo.factory(this.selModel, Roo.tree);
32446 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32447 rootVisible : true,
32448 animate: Roo.enableFx,
32451 hlDrop : Roo.enableFx,
32455 rendererTip: false,
32457 restrictExpand : function(node){
32458 var p = node.parentNode;
32460 if(p.expandedChild && p.expandedChild.parentNode == p){
32461 p.expandedChild.collapse();
32463 p.expandedChild = node;
32467 // private override
32468 setRootNode : function(node){
32469 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32470 if(!this.rootVisible){
32471 node.ui = new Roo.tree.RootTreeNodeUI(node);
32477 * Returns the container element for this TreePanel
32479 getEl : function(){
32484 * Returns the default TreeLoader for this TreePanel
32486 getLoader : function(){
32487 return this.loader;
32493 expandAll : function(){
32494 this.root.expand(true);
32498 * Collapse all nodes
32500 collapseAll : function(){
32501 this.root.collapse(true);
32505 * Returns the selection model used by this TreePanel
32507 getSelectionModel : function(){
32508 if(!this.selModel){
32509 this.selModel = new Roo.tree.DefaultSelectionModel();
32511 return this.selModel;
32515 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32516 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32517 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32520 getChecked : function(a, startNode){
32521 startNode = startNode || this.root;
32523 var f = function(){
32524 if(this.attributes.checked){
32525 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32528 startNode.cascade(f);
32533 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32534 * @param {String} path
32535 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32536 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32537 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32539 expandPath : function(path, attr, callback){
32540 attr = attr || "id";
32541 var keys = path.split(this.pathSeparator);
32542 var curNode = this.root;
32543 if(curNode.attributes[attr] != keys[1]){ // invalid root
32545 callback(false, null);
32550 var f = function(){
32551 if(++index == keys.length){
32553 callback(true, curNode);
32557 var c = curNode.findChild(attr, keys[index]);
32560 callback(false, curNode);
32565 c.expand(false, false, f);
32567 curNode.expand(false, false, f);
32571 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32572 * @param {String} path
32573 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32574 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32575 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32577 selectPath : function(path, attr, callback){
32578 attr = attr || "id";
32579 var keys = path.split(this.pathSeparator);
32580 var v = keys.pop();
32581 if(keys.length > 0){
32582 var f = function(success, node){
32583 if(success && node){
32584 var n = node.findChild(attr, v);
32590 }else if(callback){
32591 callback(false, n);
32595 callback(false, n);
32599 this.expandPath(keys.join(this.pathSeparator), attr, f);
32601 this.root.select();
32603 callback(true, this.root);
32608 getTreeEl : function(){
32613 * Trigger rendering of this TreePanel
32615 render : function(){
32616 if (this.innerCt) {
32617 return this; // stop it rendering more than once!!
32620 this.innerCt = this.el.createChild({tag:"ul",
32621 cls:"x-tree-root-ct " +
32622 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32624 if(this.containerScroll){
32625 Roo.dd.ScrollManager.register(this.el);
32627 if((this.enableDD || this.enableDrop) && !this.dropZone){
32629 * The dropZone used by this tree if drop is enabled
32630 * @type Roo.tree.TreeDropZone
32632 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32633 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32636 if((this.enableDD || this.enableDrag) && !this.dragZone){
32638 * The dragZone used by this tree if drag is enabled
32639 * @type Roo.tree.TreeDragZone
32641 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32642 ddGroup: this.ddGroup || "TreeDD",
32643 scroll: this.ddScroll
32646 this.getSelectionModel().init(this);
32648 Roo.log("ROOT not set in tree");
32651 this.root.render();
32652 if(!this.rootVisible){
32653 this.root.renderChildren();
32659 * Ext JS Library 1.1.1
32660 * Copyright(c) 2006-2007, Ext JS, LLC.
32662 * Originally Released Under LGPL - original licence link has changed is not relivant.
32665 * <script type="text/javascript">
32670 * @class Roo.tree.DefaultSelectionModel
32671 * @extends Roo.util.Observable
32672 * The default single selection for a TreePanel.
32673 * @param {Object} cfg Configuration
32675 Roo.tree.DefaultSelectionModel = function(cfg){
32676 this.selNode = null;
32682 * @event selectionchange
32683 * Fires when the selected node changes
32684 * @param {DefaultSelectionModel} this
32685 * @param {TreeNode} node the new selection
32687 "selectionchange" : true,
32690 * @event beforeselect
32691 * Fires before the selected node changes, return false to cancel the change
32692 * @param {DefaultSelectionModel} this
32693 * @param {TreeNode} node the new selection
32694 * @param {TreeNode} node the old selection
32696 "beforeselect" : true
32699 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32702 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32703 init : function(tree){
32705 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32706 tree.on("click", this.onNodeClick, this);
32709 onNodeClick : function(node, e){
32710 if (e.ctrlKey && this.selNode == node) {
32711 this.unselect(node);
32719 * @param {TreeNode} node The node to select
32720 * @return {TreeNode} The selected node
32722 select : function(node){
32723 var last = this.selNode;
32724 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32726 last.ui.onSelectedChange(false);
32728 this.selNode = node;
32729 node.ui.onSelectedChange(true);
32730 this.fireEvent("selectionchange", this, node, last);
32737 * @param {TreeNode} node The node to unselect
32739 unselect : function(node){
32740 if(this.selNode == node){
32741 this.clearSelections();
32746 * Clear all selections
32748 clearSelections : function(){
32749 var n = this.selNode;
32751 n.ui.onSelectedChange(false);
32752 this.selNode = null;
32753 this.fireEvent("selectionchange", this, null);
32759 * Get the selected node
32760 * @return {TreeNode} The selected node
32762 getSelectedNode : function(){
32763 return this.selNode;
32767 * Returns true if the node is selected
32768 * @param {TreeNode} node The node to check
32769 * @return {Boolean}
32771 isSelected : function(node){
32772 return this.selNode == node;
32776 * Selects the node above the selected node in the tree, intelligently walking the nodes
32777 * @return TreeNode The new selection
32779 selectPrevious : function(){
32780 var s = this.selNode || this.lastSelNode;
32784 var ps = s.previousSibling;
32786 if(!ps.isExpanded() || ps.childNodes.length < 1){
32787 return this.select(ps);
32789 var lc = ps.lastChild;
32790 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32793 return this.select(lc);
32795 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32796 return this.select(s.parentNode);
32802 * Selects the node above the selected node in the tree, intelligently walking the nodes
32803 * @return TreeNode The new selection
32805 selectNext : function(){
32806 var s = this.selNode || this.lastSelNode;
32810 if(s.firstChild && s.isExpanded()){
32811 return this.select(s.firstChild);
32812 }else if(s.nextSibling){
32813 return this.select(s.nextSibling);
32814 }else if(s.parentNode){
32816 s.parentNode.bubble(function(){
32817 if(this.nextSibling){
32818 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32827 onKeyDown : function(e){
32828 var s = this.selNode || this.lastSelNode;
32829 // undesirable, but required
32834 var k = e.getKey();
32842 this.selectPrevious();
32845 e.preventDefault();
32846 if(s.hasChildNodes()){
32847 if(!s.isExpanded()){
32849 }else if(s.firstChild){
32850 this.select(s.firstChild, e);
32855 e.preventDefault();
32856 if(s.hasChildNodes() && s.isExpanded()){
32858 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32859 this.select(s.parentNode, e);
32867 * @class Roo.tree.MultiSelectionModel
32868 * @extends Roo.util.Observable
32869 * Multi selection for a TreePanel.
32870 * @param {Object} cfg Configuration
32872 Roo.tree.MultiSelectionModel = function(){
32873 this.selNodes = [];
32877 * @event selectionchange
32878 * Fires when the selected nodes change
32879 * @param {MultiSelectionModel} this
32880 * @param {Array} nodes Array of the selected nodes
32882 "selectionchange" : true
32884 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32888 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32889 init : function(tree){
32891 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32892 tree.on("click", this.onNodeClick, this);
32895 onNodeClick : function(node, e){
32896 this.select(node, e, e.ctrlKey);
32901 * @param {TreeNode} node The node to select
32902 * @param {EventObject} e (optional) An event associated with the selection
32903 * @param {Boolean} keepExisting True to retain existing selections
32904 * @return {TreeNode} The selected node
32906 select : function(node, e, keepExisting){
32907 if(keepExisting !== true){
32908 this.clearSelections(true);
32910 if(this.isSelected(node)){
32911 this.lastSelNode = node;
32914 this.selNodes.push(node);
32915 this.selMap[node.id] = node;
32916 this.lastSelNode = node;
32917 node.ui.onSelectedChange(true);
32918 this.fireEvent("selectionchange", this, this.selNodes);
32924 * @param {TreeNode} node The node to unselect
32926 unselect : function(node){
32927 if(this.selMap[node.id]){
32928 node.ui.onSelectedChange(false);
32929 var sn = this.selNodes;
32932 index = sn.indexOf(node);
32934 for(var i = 0, len = sn.length; i < len; i++){
32942 this.selNodes.splice(index, 1);
32944 delete this.selMap[node.id];
32945 this.fireEvent("selectionchange", this, this.selNodes);
32950 * Clear all selections
32952 clearSelections : function(suppressEvent){
32953 var sn = this.selNodes;
32955 for(var i = 0, len = sn.length; i < len; i++){
32956 sn[i].ui.onSelectedChange(false);
32958 this.selNodes = [];
32960 if(suppressEvent !== true){
32961 this.fireEvent("selectionchange", this, this.selNodes);
32967 * Returns true if the node is selected
32968 * @param {TreeNode} node The node to check
32969 * @return {Boolean}
32971 isSelected : function(node){
32972 return this.selMap[node.id] ? true : false;
32976 * Returns an array of the selected nodes
32979 getSelectedNodes : function(){
32980 return this.selNodes;
32983 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32985 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32987 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32990 * Ext JS Library 1.1.1
32991 * Copyright(c) 2006-2007, Ext JS, LLC.
32993 * Originally Released Under LGPL - original licence link has changed is not relivant.
32996 * <script type="text/javascript">
33000 * @class Roo.tree.TreeNode
33001 * @extends Roo.data.Node
33002 * @cfg {String} text The text for this node
33003 * @cfg {Boolean} expanded true to start the node expanded
33004 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33005 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33006 * @cfg {Boolean} disabled true to start the node disabled
33007 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33008 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33009 * @cfg {String} cls A css class to be added to the node
33010 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33011 * @cfg {String} href URL of the link used for the node (defaults to #)
33012 * @cfg {String} hrefTarget target frame for the link
33013 * @cfg {String} qtip An Ext QuickTip for the node
33014 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33015 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33016 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33017 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33018 * (defaults to undefined with no checkbox rendered)
33020 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33022 Roo.tree.TreeNode = function(attributes){
33023 attributes = attributes || {};
33024 if(typeof attributes == "string"){
33025 attributes = {text: attributes};
33027 this.childrenRendered = false;
33028 this.rendered = false;
33029 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33030 this.expanded = attributes.expanded === true;
33031 this.isTarget = attributes.isTarget !== false;
33032 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33033 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33036 * Read-only. The text for this node. To change it use setText().
33039 this.text = attributes.text;
33041 * True if this node is disabled.
33044 this.disabled = attributes.disabled === true;
33048 * @event textchange
33049 * Fires when the text for this node is changed
33050 * @param {Node} this This node
33051 * @param {String} text The new text
33052 * @param {String} oldText The old text
33054 "textchange" : true,
33056 * @event beforeexpand
33057 * Fires before this node is expanded, return false to cancel.
33058 * @param {Node} this This node
33059 * @param {Boolean} deep
33060 * @param {Boolean} anim
33062 "beforeexpand" : true,
33064 * @event beforecollapse
33065 * Fires before this node is collapsed, return false to cancel.
33066 * @param {Node} this This node
33067 * @param {Boolean} deep
33068 * @param {Boolean} anim
33070 "beforecollapse" : true,
33073 * Fires when this node is expanded
33074 * @param {Node} this This node
33078 * @event disabledchange
33079 * Fires when the disabled status of this node changes
33080 * @param {Node} this This node
33081 * @param {Boolean} disabled
33083 "disabledchange" : true,
33086 * Fires when this node is collapsed
33087 * @param {Node} this This node
33091 * @event beforeclick
33092 * Fires before click processing. Return false to cancel the default action.
33093 * @param {Node} this This node
33094 * @param {Roo.EventObject} e The event object
33096 "beforeclick":true,
33098 * @event checkchange
33099 * Fires when a node with a checkbox's checked property changes
33100 * @param {Node} this This node
33101 * @param {Boolean} checked
33103 "checkchange":true,
33106 * Fires when this node is clicked
33107 * @param {Node} this This node
33108 * @param {Roo.EventObject} e The event object
33113 * Fires when this node is double clicked
33114 * @param {Node} this This node
33115 * @param {Roo.EventObject} e The event object
33119 * @event contextmenu
33120 * Fires when this node is right clicked
33121 * @param {Node} this This node
33122 * @param {Roo.EventObject} e The event object
33124 "contextmenu":true,
33126 * @event beforechildrenrendered
33127 * Fires right before the child nodes for this node are rendered
33128 * @param {Node} this This node
33130 "beforechildrenrendered":true
33133 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33136 * Read-only. The UI for this node
33139 this.ui = new uiClass(this);
33141 // finally support items[]
33142 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33147 Roo.each(this.attributes.items, function(c) {
33148 this.appendChild(Roo.factory(c,Roo.Tree));
33150 delete this.attributes.items;
33155 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33156 preventHScroll: true,
33158 * Returns true if this node is expanded
33159 * @return {Boolean}
33161 isExpanded : function(){
33162 return this.expanded;
33166 * Returns the UI object for this node
33167 * @return {TreeNodeUI}
33169 getUI : function(){
33173 // private override
33174 setFirstChild : function(node){
33175 var of = this.firstChild;
33176 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33177 if(this.childrenRendered && of && node != of){
33178 of.renderIndent(true, true);
33181 this.renderIndent(true, true);
33185 // private override
33186 setLastChild : function(node){
33187 var ol = this.lastChild;
33188 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33189 if(this.childrenRendered && ol && node != ol){
33190 ol.renderIndent(true, true);
33193 this.renderIndent(true, true);
33197 // these methods are overridden to provide lazy rendering support
33198 // private override
33199 appendChild : function()
33201 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33202 if(node && this.childrenRendered){
33205 this.ui.updateExpandIcon();
33209 // private override
33210 removeChild : function(node){
33211 this.ownerTree.getSelectionModel().unselect(node);
33212 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33213 // if it's been rendered remove dom node
33214 if(this.childrenRendered){
33217 if(this.childNodes.length < 1){
33218 this.collapse(false, false);
33220 this.ui.updateExpandIcon();
33222 if(!this.firstChild) {
33223 this.childrenRendered = false;
33228 // private override
33229 insertBefore : function(node, refNode){
33230 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33231 if(newNode && refNode && this.childrenRendered){
33234 this.ui.updateExpandIcon();
33239 * Sets the text for this node
33240 * @param {String} text
33242 setText : function(text){
33243 var oldText = this.text;
33245 this.attributes.text = text;
33246 if(this.rendered){ // event without subscribing
33247 this.ui.onTextChange(this, text, oldText);
33249 this.fireEvent("textchange", this, text, oldText);
33253 * Triggers selection of this node
33255 select : function(){
33256 this.getOwnerTree().getSelectionModel().select(this);
33260 * Triggers deselection of this node
33262 unselect : function(){
33263 this.getOwnerTree().getSelectionModel().unselect(this);
33267 * Returns true if this node is selected
33268 * @return {Boolean}
33270 isSelected : function(){
33271 return this.getOwnerTree().getSelectionModel().isSelected(this);
33275 * Expand this node.
33276 * @param {Boolean} deep (optional) True to expand all children as well
33277 * @param {Boolean} anim (optional) false to cancel the default animation
33278 * @param {Function} callback (optional) A callback to be called when
33279 * expanding this node completes (does not wait for deep expand to complete).
33280 * Called with 1 parameter, this node.
33282 expand : function(deep, anim, callback){
33283 if(!this.expanded){
33284 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33287 if(!this.childrenRendered){
33288 this.renderChildren();
33290 this.expanded = true;
33291 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33292 this.ui.animExpand(function(){
33293 this.fireEvent("expand", this);
33294 if(typeof callback == "function"){
33298 this.expandChildNodes(true);
33300 }.createDelegate(this));
33304 this.fireEvent("expand", this);
33305 if(typeof callback == "function"){
33310 if(typeof callback == "function"){
33315 this.expandChildNodes(true);
33319 isHiddenRoot : function(){
33320 return this.isRoot && !this.getOwnerTree().rootVisible;
33324 * Collapse this node.
33325 * @param {Boolean} deep (optional) True to collapse all children as well
33326 * @param {Boolean} anim (optional) false to cancel the default animation
33328 collapse : function(deep, anim){
33329 if(this.expanded && !this.isHiddenRoot()){
33330 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33333 this.expanded = false;
33334 if((this.getOwnerTree().animate && anim !== false) || anim){
33335 this.ui.animCollapse(function(){
33336 this.fireEvent("collapse", this);
33338 this.collapseChildNodes(true);
33340 }.createDelegate(this));
33343 this.ui.collapse();
33344 this.fireEvent("collapse", this);
33348 var cs = this.childNodes;
33349 for(var i = 0, len = cs.length; i < len; i++) {
33350 cs[i].collapse(true, false);
33356 delayedExpand : function(delay){
33357 if(!this.expandProcId){
33358 this.expandProcId = this.expand.defer(delay, this);
33363 cancelExpand : function(){
33364 if(this.expandProcId){
33365 clearTimeout(this.expandProcId);
33367 this.expandProcId = false;
33371 * Toggles expanded/collapsed state of the node
33373 toggle : function(){
33382 * Ensures all parent nodes are expanded
33384 ensureVisible : function(callback){
33385 var tree = this.getOwnerTree();
33386 tree.expandPath(this.parentNode.getPath(), false, function(){
33387 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33388 Roo.callback(callback);
33389 }.createDelegate(this));
33393 * Expand all child nodes
33394 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33396 expandChildNodes : function(deep){
33397 var cs = this.childNodes;
33398 for(var i = 0, len = cs.length; i < len; i++) {
33399 cs[i].expand(deep);
33404 * Collapse all child nodes
33405 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33407 collapseChildNodes : function(deep){
33408 var cs = this.childNodes;
33409 for(var i = 0, len = cs.length; i < len; i++) {
33410 cs[i].collapse(deep);
33415 * Disables this node
33417 disable : function(){
33418 this.disabled = true;
33420 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33421 this.ui.onDisableChange(this, true);
33423 this.fireEvent("disabledchange", this, true);
33427 * Enables this node
33429 enable : function(){
33430 this.disabled = false;
33431 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33432 this.ui.onDisableChange(this, false);
33434 this.fireEvent("disabledchange", this, false);
33438 renderChildren : function(suppressEvent){
33439 if(suppressEvent !== false){
33440 this.fireEvent("beforechildrenrendered", this);
33442 var cs = this.childNodes;
33443 for(var i = 0, len = cs.length; i < len; i++){
33444 cs[i].render(true);
33446 this.childrenRendered = true;
33450 sort : function(fn, scope){
33451 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33452 if(this.childrenRendered){
33453 var cs = this.childNodes;
33454 for(var i = 0, len = cs.length; i < len; i++){
33455 cs[i].render(true);
33461 render : function(bulkRender){
33462 this.ui.render(bulkRender);
33463 if(!this.rendered){
33464 this.rendered = true;
33466 this.expanded = false;
33467 this.expand(false, false);
33473 renderIndent : function(deep, refresh){
33475 this.ui.childIndent = null;
33477 this.ui.renderIndent();
33478 if(deep === true && this.childrenRendered){
33479 var cs = this.childNodes;
33480 for(var i = 0, len = cs.length; i < len; i++){
33481 cs[i].renderIndent(true, refresh);
33487 * Ext JS Library 1.1.1
33488 * Copyright(c) 2006-2007, Ext JS, LLC.
33490 * Originally Released Under LGPL - original licence link has changed is not relivant.
33493 * <script type="text/javascript">
33497 * @class Roo.tree.AsyncTreeNode
33498 * @extends Roo.tree.TreeNode
33499 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33501 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33503 Roo.tree.AsyncTreeNode = function(config){
33504 this.loaded = false;
33505 this.loading = false;
33506 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33508 * @event beforeload
33509 * Fires before this node is loaded, return false to cancel
33510 * @param {Node} this This node
33512 this.addEvents({'beforeload':true, 'load': true});
33515 * Fires when this node is loaded
33516 * @param {Node} this This node
33519 * The loader used by this node (defaults to using the tree's defined loader)
33524 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33525 expand : function(deep, anim, callback){
33526 if(this.loading){ // if an async load is already running, waiting til it's done
33528 var f = function(){
33529 if(!this.loading){ // done loading
33530 clearInterval(timer);
33531 this.expand(deep, anim, callback);
33533 }.createDelegate(this);
33534 timer = setInterval(f, 200);
33538 if(this.fireEvent("beforeload", this) === false){
33541 this.loading = true;
33542 this.ui.beforeLoad(this);
33543 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33545 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33549 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33553 * Returns true if this node is currently loading
33554 * @return {Boolean}
33556 isLoading : function(){
33557 return this.loading;
33560 loadComplete : function(deep, anim, callback){
33561 this.loading = false;
33562 this.loaded = true;
33563 this.ui.afterLoad(this);
33564 this.fireEvent("load", this);
33565 this.expand(deep, anim, callback);
33569 * Returns true if this node has been loaded
33570 * @return {Boolean}
33572 isLoaded : function(){
33573 return this.loaded;
33576 hasChildNodes : function(){
33577 if(!this.isLeaf() && !this.loaded){
33580 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33585 * Trigger a reload for this node
33586 * @param {Function} callback
33588 reload : function(callback){
33589 this.collapse(false, false);
33590 while(this.firstChild){
33591 this.removeChild(this.firstChild);
33593 this.childrenRendered = false;
33594 this.loaded = false;
33595 if(this.isHiddenRoot()){
33596 this.expanded = false;
33598 this.expand(false, false, callback);
33602 * Ext JS Library 1.1.1
33603 * Copyright(c) 2006-2007, Ext JS, LLC.
33605 * Originally Released Under LGPL - original licence link has changed is not relivant.
33608 * <script type="text/javascript">
33612 * @class Roo.tree.TreeNodeUI
33614 * @param {Object} node The node to render
33615 * The TreeNode UI implementation is separate from the
33616 * tree implementation. Unless you are customizing the tree UI,
33617 * you should never have to use this directly.
33619 Roo.tree.TreeNodeUI = function(node){
33621 this.rendered = false;
33622 this.animating = false;
33623 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33626 Roo.tree.TreeNodeUI.prototype = {
33627 removeChild : function(node){
33629 this.ctNode.removeChild(node.ui.getEl());
33633 beforeLoad : function(){
33634 this.addClass("x-tree-node-loading");
33637 afterLoad : function(){
33638 this.removeClass("x-tree-node-loading");
33641 onTextChange : function(node, text, oldText){
33643 this.textNode.innerHTML = text;
33647 onDisableChange : function(node, state){
33648 this.disabled = state;
33650 this.addClass("x-tree-node-disabled");
33652 this.removeClass("x-tree-node-disabled");
33656 onSelectedChange : function(state){
33659 this.addClass("x-tree-selected");
33662 this.removeClass("x-tree-selected");
33666 onMove : function(tree, node, oldParent, newParent, index, refNode){
33667 this.childIndent = null;
33669 var targetNode = newParent.ui.getContainer();
33670 if(!targetNode){//target not rendered
33671 this.holder = document.createElement("div");
33672 this.holder.appendChild(this.wrap);
33675 var insertBefore = refNode ? refNode.ui.getEl() : null;
33677 targetNode.insertBefore(this.wrap, insertBefore);
33679 targetNode.appendChild(this.wrap);
33681 this.node.renderIndent(true);
33685 addClass : function(cls){
33687 Roo.fly(this.elNode).addClass(cls);
33691 removeClass : function(cls){
33693 Roo.fly(this.elNode).removeClass(cls);
33697 remove : function(){
33699 this.holder = document.createElement("div");
33700 this.holder.appendChild(this.wrap);
33704 fireEvent : function(){
33705 return this.node.fireEvent.apply(this.node, arguments);
33708 initEvents : function(){
33709 this.node.on("move", this.onMove, this);
33710 var E = Roo.EventManager;
33711 var a = this.anchor;
33713 var el = Roo.fly(a, '_treeui');
33715 if(Roo.isOpera){ // opera render bug ignores the CSS
33716 el.setStyle("text-decoration", "none");
33719 el.on("click", this.onClick, this);
33720 el.on("dblclick", this.onDblClick, this);
33723 Roo.EventManager.on(this.checkbox,
33724 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33727 el.on("contextmenu", this.onContextMenu, this);
33729 var icon = Roo.fly(this.iconNode);
33730 icon.on("click", this.onClick, this);
33731 icon.on("dblclick", this.onDblClick, this);
33732 icon.on("contextmenu", this.onContextMenu, this);
33733 E.on(this.ecNode, "click", this.ecClick, this, true);
33735 if(this.node.disabled){
33736 this.addClass("x-tree-node-disabled");
33738 if(this.node.hidden){
33739 this.addClass("x-tree-node-disabled");
33741 var ot = this.node.getOwnerTree();
33742 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33743 if(dd && (!this.node.isRoot || ot.rootVisible)){
33744 Roo.dd.Registry.register(this.elNode, {
33746 handles: this.getDDHandles(),
33752 getDDHandles : function(){
33753 return [this.iconNode, this.textNode];
33758 this.wrap.style.display = "none";
33764 this.wrap.style.display = "";
33768 onContextMenu : function(e){
33769 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33770 e.preventDefault();
33772 this.fireEvent("contextmenu", this.node, e);
33776 onClick : function(e){
33781 if(this.fireEvent("beforeclick", this.node, e) !== false){
33782 if(!this.disabled && this.node.attributes.href){
33783 this.fireEvent("click", this.node, e);
33786 e.preventDefault();
33791 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33792 this.node.toggle();
33795 this.fireEvent("click", this.node, e);
33801 onDblClick : function(e){
33802 e.preventDefault();
33807 this.toggleCheck();
33809 if(!this.animating && this.node.hasChildNodes()){
33810 this.node.toggle();
33812 this.fireEvent("dblclick", this.node, e);
33815 onCheckChange : function(){
33816 var checked = this.checkbox.checked;
33817 this.node.attributes.checked = checked;
33818 this.fireEvent('checkchange', this.node, checked);
33821 ecClick : function(e){
33822 if(!this.animating && this.node.hasChildNodes()){
33823 this.node.toggle();
33827 startDrop : function(){
33828 this.dropping = true;
33831 // delayed drop so the click event doesn't get fired on a drop
33832 endDrop : function(){
33833 setTimeout(function(){
33834 this.dropping = false;
33835 }.createDelegate(this), 50);
33838 expand : function(){
33839 this.updateExpandIcon();
33840 this.ctNode.style.display = "";
33843 focus : function(){
33844 if(!this.node.preventHScroll){
33845 try{this.anchor.focus();
33847 }else if(!Roo.isIE){
33849 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33850 var l = noscroll.scrollLeft;
33851 this.anchor.focus();
33852 noscroll.scrollLeft = l;
33857 toggleCheck : function(value){
33858 var cb = this.checkbox;
33860 cb.checked = (value === undefined ? !cb.checked : value);
33866 this.anchor.blur();
33870 animExpand : function(callback){
33871 var ct = Roo.get(this.ctNode);
33873 if(!this.node.hasChildNodes()){
33874 this.updateExpandIcon();
33875 this.ctNode.style.display = "";
33876 Roo.callback(callback);
33879 this.animating = true;
33880 this.updateExpandIcon();
33883 callback : function(){
33884 this.animating = false;
33885 Roo.callback(callback);
33888 duration: this.node.ownerTree.duration || .25
33892 highlight : function(){
33893 var tree = this.node.getOwnerTree();
33894 Roo.fly(this.wrap).highlight(
33895 tree.hlColor || "C3DAF9",
33896 {endColor: tree.hlBaseColor}
33900 collapse : function(){
33901 this.updateExpandIcon();
33902 this.ctNode.style.display = "none";
33905 animCollapse : function(callback){
33906 var ct = Roo.get(this.ctNode);
33907 ct.enableDisplayMode('block');
33910 this.animating = true;
33911 this.updateExpandIcon();
33914 callback : function(){
33915 this.animating = false;
33916 Roo.callback(callback);
33919 duration: this.node.ownerTree.duration || .25
33923 getContainer : function(){
33924 return this.ctNode;
33927 getEl : function(){
33931 appendDDGhost : function(ghostNode){
33932 ghostNode.appendChild(this.elNode.cloneNode(true));
33935 getDDRepairXY : function(){
33936 return Roo.lib.Dom.getXY(this.iconNode);
33939 onRender : function(){
33943 render : function(bulkRender){
33944 var n = this.node, a = n.attributes;
33945 var targetNode = n.parentNode ?
33946 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33948 if(!this.rendered){
33949 this.rendered = true;
33951 this.renderElements(n, a, targetNode, bulkRender);
33954 if(this.textNode.setAttributeNS){
33955 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33957 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33960 this.textNode.setAttribute("ext:qtip", a.qtip);
33962 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33965 }else if(a.qtipCfg){
33966 a.qtipCfg.target = Roo.id(this.textNode);
33967 Roo.QuickTips.register(a.qtipCfg);
33970 if(!this.node.expanded){
33971 this.updateExpandIcon();
33974 if(bulkRender === true) {
33975 targetNode.appendChild(this.wrap);
33980 renderElements : function(n, a, targetNode, bulkRender)
33982 // add some indent caching, this helps performance when rendering a large tree
33983 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33984 var t = n.getOwnerTree();
33985 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33986 if (typeof(n.attributes.html) != 'undefined') {
33987 txt = n.attributes.html;
33989 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33990 var cb = typeof a.checked == 'boolean';
33991 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33992 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33993 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33994 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33995 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33996 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33997 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33998 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33999 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34000 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34003 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34004 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34005 n.nextSibling.ui.getEl(), buf.join(""));
34007 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34010 this.elNode = this.wrap.childNodes[0];
34011 this.ctNode = this.wrap.childNodes[1];
34012 var cs = this.elNode.childNodes;
34013 this.indentNode = cs[0];
34014 this.ecNode = cs[1];
34015 this.iconNode = cs[2];
34018 this.checkbox = cs[3];
34021 this.anchor = cs[index];
34022 this.textNode = cs[index].firstChild;
34025 getAnchor : function(){
34026 return this.anchor;
34029 getTextEl : function(){
34030 return this.textNode;
34033 getIconEl : function(){
34034 return this.iconNode;
34037 isChecked : function(){
34038 return this.checkbox ? this.checkbox.checked : false;
34041 updateExpandIcon : function(){
34043 var n = this.node, c1, c2;
34044 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34045 var hasChild = n.hasChildNodes();
34049 c1 = "x-tree-node-collapsed";
34050 c2 = "x-tree-node-expanded";
34053 c1 = "x-tree-node-expanded";
34054 c2 = "x-tree-node-collapsed";
34057 this.removeClass("x-tree-node-leaf");
34058 this.wasLeaf = false;
34060 if(this.c1 != c1 || this.c2 != c2){
34061 Roo.fly(this.elNode).replaceClass(c1, c2);
34062 this.c1 = c1; this.c2 = c2;
34065 // this changes non-leafs into leafs if they have no children.
34066 // it's not very rational behaviour..
34068 if(!this.wasLeaf && this.node.leaf){
34069 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34072 this.wasLeaf = true;
34075 var ecc = "x-tree-ec-icon "+cls;
34076 if(this.ecc != ecc){
34077 this.ecNode.className = ecc;
34083 getChildIndent : function(){
34084 if(!this.childIndent){
34088 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34090 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34092 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34097 this.childIndent = buf.join("");
34099 return this.childIndent;
34102 renderIndent : function(){
34105 var p = this.node.parentNode;
34107 indent = p.ui.getChildIndent();
34109 if(this.indentMarkup != indent){ // don't rerender if not required
34110 this.indentNode.innerHTML = indent;
34111 this.indentMarkup = indent;
34113 this.updateExpandIcon();
34118 Roo.tree.RootTreeNodeUI = function(){
34119 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34121 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34122 render : function(){
34123 if(!this.rendered){
34124 var targetNode = this.node.ownerTree.innerCt.dom;
34125 this.node.expanded = true;
34126 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34127 this.wrap = this.ctNode = targetNode.firstChild;
34130 collapse : function(){
34132 expand : function(){
34136 * Ext JS Library 1.1.1
34137 * Copyright(c) 2006-2007, Ext JS, LLC.
34139 * Originally Released Under LGPL - original licence link has changed is not relivant.
34142 * <script type="text/javascript">
34145 * @class Roo.tree.TreeLoader
34146 * @extends Roo.util.Observable
34147 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34148 * nodes from a specified URL. The response must be a javascript Array definition
34149 * who's elements are node definition objects. eg:
34154 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34155 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34162 * The old style respose with just an array is still supported, but not recommended.
34165 * A server request is sent, and child nodes are loaded only when a node is expanded.
34166 * The loading node's id is passed to the server under the parameter name "node" to
34167 * enable the server to produce the correct child nodes.
34169 * To pass extra parameters, an event handler may be attached to the "beforeload"
34170 * event, and the parameters specified in the TreeLoader's baseParams property:
34172 myTreeLoader.on("beforeload", function(treeLoader, node) {
34173 this.baseParams.category = node.attributes.category;
34176 * This would pass an HTTP parameter called "category" to the server containing
34177 * the value of the Node's "category" attribute.
34179 * Creates a new Treeloader.
34180 * @param {Object} config A config object containing config properties.
34182 Roo.tree.TreeLoader = function(config){
34183 this.baseParams = {};
34184 this.requestMethod = "POST";
34185 Roo.apply(this, config);
34190 * @event beforeload
34191 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34192 * @param {Object} This TreeLoader object.
34193 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34194 * @param {Object} callback The callback function specified in the {@link #load} call.
34199 * Fires when the node has been successfuly loaded.
34200 * @param {Object} This TreeLoader object.
34201 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34202 * @param {Object} response The response object containing the data from the server.
34206 * @event loadexception
34207 * Fires if the network request failed.
34208 * @param {Object} This TreeLoader object.
34209 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34210 * @param {Object} response The response object containing the data from the server.
34212 loadexception : true,
34215 * Fires before a node is created, enabling you to return custom Node types
34216 * @param {Object} This TreeLoader object.
34217 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34222 Roo.tree.TreeLoader.superclass.constructor.call(this);
34225 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34227 * @cfg {String} dataUrl The URL from which to request a Json string which
34228 * specifies an array of node definition object representing the child nodes
34232 * @cfg {String} requestMethod either GET or POST
34233 * defaults to POST (due to BC)
34237 * @cfg {Object} baseParams (optional) An object containing properties which
34238 * specify HTTP parameters to be passed to each request for child nodes.
34241 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34242 * created by this loader. If the attributes sent by the server have an attribute in this object,
34243 * they take priority.
34246 * @cfg {Object} uiProviders (optional) An object containing properties which
34248 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34249 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34250 * <i>uiProvider</i> attribute of a returned child node is a string rather
34251 * than a reference to a TreeNodeUI implementation, this that string value
34252 * is used as a property name in the uiProviders object. You can define the provider named
34253 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34258 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34259 * child nodes before loading.
34261 clearOnLoad : true,
34264 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34265 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34266 * Grid query { data : [ .....] }
34271 * @cfg {String} queryParam (optional)
34272 * Name of the query as it will be passed on the querystring (defaults to 'node')
34273 * eg. the request will be ?node=[id]
34280 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34281 * This is called automatically when a node is expanded, but may be used to reload
34282 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34283 * @param {Roo.tree.TreeNode} node
34284 * @param {Function} callback
34286 load : function(node, callback){
34287 if(this.clearOnLoad){
34288 while(node.firstChild){
34289 node.removeChild(node.firstChild);
34292 if(node.attributes.children){ // preloaded json children
34293 var cs = node.attributes.children;
34294 for(var i = 0, len = cs.length; i < len; i++){
34295 node.appendChild(this.createNode(cs[i]));
34297 if(typeof callback == "function"){
34300 }else if(this.dataUrl){
34301 this.requestData(node, callback);
34305 getParams: function(node){
34306 var buf = [], bp = this.baseParams;
34307 for(var key in bp){
34308 if(typeof bp[key] != "function"){
34309 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34312 var n = this.queryParam === false ? 'node' : this.queryParam;
34313 buf.push(n + "=", encodeURIComponent(node.id));
34314 return buf.join("");
34317 requestData : function(node, callback){
34318 if(this.fireEvent("beforeload", this, node, callback) !== false){
34319 this.transId = Roo.Ajax.request({
34320 method:this.requestMethod,
34321 url: this.dataUrl||this.url,
34322 success: this.handleResponse,
34323 failure: this.handleFailure,
34325 argument: {callback: callback, node: node},
34326 params: this.getParams(node)
34329 // if the load is cancelled, make sure we notify
34330 // the node that we are done
34331 if(typeof callback == "function"){
34337 isLoading : function(){
34338 return this.transId ? true : false;
34341 abort : function(){
34342 if(this.isLoading()){
34343 Roo.Ajax.abort(this.transId);
34348 createNode : function(attr)
34350 // apply baseAttrs, nice idea Corey!
34351 if(this.baseAttrs){
34352 Roo.applyIf(attr, this.baseAttrs);
34354 if(this.applyLoader !== false){
34355 attr.loader = this;
34357 // uiProvider = depreciated..
34359 if(typeof(attr.uiProvider) == 'string'){
34360 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34361 /** eval:var:attr */ eval(attr.uiProvider);
34363 if(typeof(this.uiProviders['default']) != 'undefined') {
34364 attr.uiProvider = this.uiProviders['default'];
34367 this.fireEvent('create', this, attr);
34369 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34371 new Roo.tree.TreeNode(attr) :
34372 new Roo.tree.AsyncTreeNode(attr));
34375 processResponse : function(response, node, callback)
34377 var json = response.responseText;
34380 var o = Roo.decode(json);
34382 if (this.root === false && typeof(o.success) != undefined) {
34383 this.root = 'data'; // the default behaviour for list like data..
34386 if (this.root !== false && !o.success) {
34387 // it's a failure condition.
34388 var a = response.argument;
34389 this.fireEvent("loadexception", this, a.node, response);
34390 Roo.log("Load failed - should have a handler really");
34396 if (this.root !== false) {
34400 for(var i = 0, len = o.length; i < len; i++){
34401 var n = this.createNode(o[i]);
34403 node.appendChild(n);
34406 if(typeof callback == "function"){
34407 callback(this, node);
34410 this.handleFailure(response);
34414 handleResponse : function(response){
34415 this.transId = false;
34416 var a = response.argument;
34417 this.processResponse(response, a.node, a.callback);
34418 this.fireEvent("load", this, a.node, response);
34421 handleFailure : function(response)
34423 // should handle failure better..
34424 this.transId = false;
34425 var a = response.argument;
34426 this.fireEvent("loadexception", this, a.node, response);
34427 if(typeof a.callback == "function"){
34428 a.callback(this, a.node);
34433 * Ext JS Library 1.1.1
34434 * Copyright(c) 2006-2007, Ext JS, LLC.
34436 * Originally Released Under LGPL - original licence link has changed is not relivant.
34439 * <script type="text/javascript">
34443 * @class Roo.tree.TreeFilter
34444 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34445 * @param {TreePanel} tree
34446 * @param {Object} config (optional)
34448 Roo.tree.TreeFilter = function(tree, config){
34450 this.filtered = {};
34451 Roo.apply(this, config);
34454 Roo.tree.TreeFilter.prototype = {
34461 * Filter the data by a specific attribute.
34462 * @param {String/RegExp} value Either string that the attribute value
34463 * should start with or a RegExp to test against the attribute
34464 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34465 * @param {TreeNode} startNode (optional) The node to start the filter at.
34467 filter : function(value, attr, startNode){
34468 attr = attr || "text";
34470 if(typeof value == "string"){
34471 var vlen = value.length;
34472 // auto clear empty filter
34473 if(vlen == 0 && this.clearBlank){
34477 value = value.toLowerCase();
34479 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34481 }else if(value.exec){ // regex?
34483 return value.test(n.attributes[attr]);
34486 throw 'Illegal filter type, must be string or regex';
34488 this.filterBy(f, null, startNode);
34492 * Filter by a function. The passed function will be called with each
34493 * node in the tree (or from the startNode). If the function returns true, the node is kept
34494 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34495 * @param {Function} fn The filter function
34496 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34498 filterBy : function(fn, scope, startNode){
34499 startNode = startNode || this.tree.root;
34500 if(this.autoClear){
34503 var af = this.filtered, rv = this.reverse;
34504 var f = function(n){
34505 if(n == startNode){
34511 var m = fn.call(scope || n, n);
34519 startNode.cascade(f);
34522 if(typeof id != "function"){
34524 if(n && n.parentNode){
34525 n.parentNode.removeChild(n);
34533 * Clears the current filter. Note: with the "remove" option
34534 * set a filter cannot be cleared.
34536 clear : function(){
34538 var af = this.filtered;
34540 if(typeof id != "function"){
34547 this.filtered = {};
34552 * Ext JS Library 1.1.1
34553 * Copyright(c) 2006-2007, Ext JS, LLC.
34555 * Originally Released Under LGPL - original licence link has changed is not relivant.
34558 * <script type="text/javascript">
34563 * @class Roo.tree.TreeSorter
34564 * Provides sorting of nodes in a TreePanel
34566 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34567 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34568 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34569 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34570 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34571 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34573 * @param {TreePanel} tree
34574 * @param {Object} config
34576 Roo.tree.TreeSorter = function(tree, config){
34577 Roo.apply(this, config);
34578 tree.on("beforechildrenrendered", this.doSort, this);
34579 tree.on("append", this.updateSort, this);
34580 tree.on("insert", this.updateSort, this);
34582 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34583 var p = this.property || "text";
34584 var sortType = this.sortType;
34585 var fs = this.folderSort;
34586 var cs = this.caseSensitive === true;
34587 var leafAttr = this.leafAttr || 'leaf';
34589 this.sortFn = function(n1, n2){
34591 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34594 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34598 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34599 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34601 return dsc ? +1 : -1;
34603 return dsc ? -1 : +1;
34610 Roo.tree.TreeSorter.prototype = {
34611 doSort : function(node){
34612 node.sort(this.sortFn);
34615 compareNodes : function(n1, n2){
34616 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34619 updateSort : function(tree, node){
34620 if(node.childrenRendered){
34621 this.doSort.defer(1, this, [node]);
34626 * Ext JS Library 1.1.1
34627 * Copyright(c) 2006-2007, Ext JS, LLC.
34629 * Originally Released Under LGPL - original licence link has changed is not relivant.
34632 * <script type="text/javascript">
34635 if(Roo.dd.DropZone){
34637 Roo.tree.TreeDropZone = function(tree, config){
34638 this.allowParentInsert = false;
34639 this.allowContainerDrop = false;
34640 this.appendOnly = false;
34641 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34643 this.lastInsertClass = "x-tree-no-status";
34644 this.dragOverData = {};
34647 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34648 ddGroup : "TreeDD",
34651 expandDelay : 1000,
34653 expandNode : function(node){
34654 if(node.hasChildNodes() && !node.isExpanded()){
34655 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34659 queueExpand : function(node){
34660 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34663 cancelExpand : function(){
34664 if(this.expandProcId){
34665 clearTimeout(this.expandProcId);
34666 this.expandProcId = false;
34670 isValidDropPoint : function(n, pt, dd, e, data){
34671 if(!n || !data){ return false; }
34672 var targetNode = n.node;
34673 var dropNode = data.node;
34674 // default drop rules
34675 if(!(targetNode && targetNode.isTarget && pt)){
34678 if(pt == "append" && targetNode.allowChildren === false){
34681 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34684 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34687 // reuse the object
34688 var overEvent = this.dragOverData;
34689 overEvent.tree = this.tree;
34690 overEvent.target = targetNode;
34691 overEvent.data = data;
34692 overEvent.point = pt;
34693 overEvent.source = dd;
34694 overEvent.rawEvent = e;
34695 overEvent.dropNode = dropNode;
34696 overEvent.cancel = false;
34697 var result = this.tree.fireEvent("nodedragover", overEvent);
34698 return overEvent.cancel === false && result !== false;
34701 getDropPoint : function(e, n, dd)
34705 return tn.allowChildren !== false ? "append" : false; // always append for root
34707 var dragEl = n.ddel;
34708 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34709 var y = Roo.lib.Event.getPageY(e);
34710 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34712 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34713 var noAppend = tn.allowChildren === false;
34714 if(this.appendOnly || tn.parentNode.allowChildren === false){
34715 return noAppend ? false : "append";
34717 var noBelow = false;
34718 if(!this.allowParentInsert){
34719 noBelow = tn.hasChildNodes() && tn.isExpanded();
34721 var q = (b - t) / (noAppend ? 2 : 3);
34722 if(y >= t && y < (t + q)){
34724 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34731 onNodeEnter : function(n, dd, e, data)
34733 this.cancelExpand();
34736 onNodeOver : function(n, dd, e, data)
34739 var pt = this.getDropPoint(e, n, dd);
34742 // auto node expand check
34743 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34744 this.queueExpand(node);
34745 }else if(pt != "append"){
34746 this.cancelExpand();
34749 // set the insert point style on the target node
34750 var returnCls = this.dropNotAllowed;
34751 if(this.isValidDropPoint(n, pt, dd, e, data)){
34756 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34757 cls = "x-tree-drag-insert-above";
34758 }else if(pt == "below"){
34759 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34760 cls = "x-tree-drag-insert-below";
34762 returnCls = "x-tree-drop-ok-append";
34763 cls = "x-tree-drag-append";
34765 if(this.lastInsertClass != cls){
34766 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34767 this.lastInsertClass = cls;
34774 onNodeOut : function(n, dd, e, data){
34776 this.cancelExpand();
34777 this.removeDropIndicators(n);
34780 onNodeDrop : function(n, dd, e, data){
34781 var point = this.getDropPoint(e, n, dd);
34782 var targetNode = n.node;
34783 targetNode.ui.startDrop();
34784 if(!this.isValidDropPoint(n, point, dd, e, data)){
34785 targetNode.ui.endDrop();
34788 // first try to find the drop node
34789 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34792 target: targetNode,
34797 dropNode: dropNode,
34800 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34801 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34802 targetNode.ui.endDrop();
34805 // allow target changing
34806 targetNode = dropEvent.target;
34807 if(point == "append" && !targetNode.isExpanded()){
34808 targetNode.expand(false, null, function(){
34809 this.completeDrop(dropEvent);
34810 }.createDelegate(this));
34812 this.completeDrop(dropEvent);
34817 completeDrop : function(de){
34818 var ns = de.dropNode, p = de.point, t = de.target;
34819 if(!(ns instanceof Array)){
34823 for(var i = 0, len = ns.length; i < len; i++){
34826 t.parentNode.insertBefore(n, t);
34827 }else if(p == "below"){
34828 t.parentNode.insertBefore(n, t.nextSibling);
34834 if(this.tree.hlDrop){
34838 this.tree.fireEvent("nodedrop", de);
34841 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34842 if(this.tree.hlDrop){
34843 dropNode.ui.focus();
34844 dropNode.ui.highlight();
34846 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34849 getTree : function(){
34853 removeDropIndicators : function(n){
34856 Roo.fly(el).removeClass([
34857 "x-tree-drag-insert-above",
34858 "x-tree-drag-insert-below",
34859 "x-tree-drag-append"]);
34860 this.lastInsertClass = "_noclass";
34864 beforeDragDrop : function(target, e, id){
34865 this.cancelExpand();
34869 afterRepair : function(data){
34870 if(data && Roo.enableFx){
34871 data.node.ui.highlight();
34881 * Ext JS Library 1.1.1
34882 * Copyright(c) 2006-2007, Ext JS, LLC.
34884 * Originally Released Under LGPL - original licence link has changed is not relivant.
34887 * <script type="text/javascript">
34891 if(Roo.dd.DragZone){
34892 Roo.tree.TreeDragZone = function(tree, config){
34893 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34897 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34898 ddGroup : "TreeDD",
34900 onBeforeDrag : function(data, e){
34902 return n && n.draggable && !n.disabled;
34906 onInitDrag : function(e){
34907 var data = this.dragData;
34908 this.tree.getSelectionModel().select(data.node);
34909 this.proxy.update("");
34910 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34911 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34914 getRepairXY : function(e, data){
34915 return data.node.ui.getDDRepairXY();
34918 onEndDrag : function(data, e){
34919 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34924 onValidDrop : function(dd, e, id){
34925 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34929 beforeInvalidDrop : function(e, id){
34930 // this scrolls the original position back into view
34931 var sm = this.tree.getSelectionModel();
34932 sm.clearSelections();
34933 sm.select(this.dragData.node);
34938 * Ext JS Library 1.1.1
34939 * Copyright(c) 2006-2007, Ext JS, LLC.
34941 * Originally Released Under LGPL - original licence link has changed is not relivant.
34944 * <script type="text/javascript">
34947 * @class Roo.tree.TreeEditor
34948 * @extends Roo.Editor
34949 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34950 * as the editor field.
34952 * @param {Object} config (used to be the tree panel.)
34953 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34955 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34956 * @cfg {Roo.form.TextField|Object} field The field configuration
34960 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34963 if (oldconfig) { // old style..
34964 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34967 tree = config.tree;
34968 config.field = config.field || {};
34969 config.field.xtype = 'TextField';
34970 field = Roo.factory(config.field, Roo.form);
34972 config = config || {};
34977 * @event beforenodeedit
34978 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34979 * false from the handler of this event.
34980 * @param {Editor} this
34981 * @param {Roo.tree.Node} node
34983 "beforenodeedit" : true
34987 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34991 tree.on('beforeclick', this.beforeNodeClick, this);
34992 tree.getTreeEl().on('mousedown', this.hide, this);
34993 this.on('complete', this.updateNode, this);
34994 this.on('beforestartedit', this.fitToTree, this);
34995 this.on('startedit', this.bindScroll, this, {delay:10});
34996 this.on('specialkey', this.onSpecialKey, this);
34999 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35001 * @cfg {String} alignment
35002 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35008 * @cfg {Boolean} hideEl
35009 * True to hide the bound element while the editor is displayed (defaults to false)
35013 * @cfg {String} cls
35014 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35016 cls: "x-small-editor x-tree-editor",
35018 * @cfg {Boolean} shim
35019 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35025 * @cfg {Number} maxWidth
35026 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35027 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35028 * scroll and client offsets into account prior to each edit.
35035 fitToTree : function(ed, el){
35036 var td = this.tree.getTreeEl().dom, nd = el.dom;
35037 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35038 td.scrollLeft = nd.offsetLeft;
35042 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35043 this.setSize(w, '');
35045 return this.fireEvent('beforenodeedit', this, this.editNode);
35050 triggerEdit : function(node){
35051 this.completeEdit();
35052 this.editNode = node;
35053 this.startEdit(node.ui.textNode, node.text);
35057 bindScroll : function(){
35058 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35062 beforeNodeClick : function(node, e){
35063 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35064 this.lastClick = new Date();
35065 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35067 this.triggerEdit(node);
35074 updateNode : function(ed, value){
35075 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35076 this.editNode.setText(value);
35080 onHide : function(){
35081 Roo.tree.TreeEditor.superclass.onHide.call(this);
35083 this.editNode.ui.focus();
35088 onSpecialKey : function(field, e){
35089 var k = e.getKey();
35093 }else if(k == e.ENTER && !e.hasModifier()){
35095 this.completeEdit();
35098 });//<Script type="text/javascript">
35101 * Ext JS Library 1.1.1
35102 * Copyright(c) 2006-2007, Ext JS, LLC.
35104 * Originally Released Under LGPL - original licence link has changed is not relivant.
35107 * <script type="text/javascript">
35111 * Not documented??? - probably should be...
35114 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35115 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35117 renderElements : function(n, a, targetNode, bulkRender){
35118 //consel.log("renderElements?");
35119 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35121 var t = n.getOwnerTree();
35122 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35124 var cols = t.columns;
35125 var bw = t.borderWidth;
35127 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35128 var cb = typeof a.checked == "boolean";
35129 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35130 var colcls = 'x-t-' + tid + '-c0';
35132 '<li class="x-tree-node">',
35135 '<div class="x-tree-node-el ', a.cls,'">',
35137 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35140 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35141 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35142 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35143 (a.icon ? ' x-tree-node-inline-icon' : ''),
35144 (a.iconCls ? ' '+a.iconCls : ''),
35145 '" unselectable="on" />',
35146 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35147 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35149 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35150 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35151 '<span unselectable="on" qtip="' + tx + '">',
35155 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35156 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35158 for(var i = 1, len = cols.length; i < len; i++){
35160 colcls = 'x-t-' + tid + '-c' +i;
35161 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35162 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35163 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35169 '<div class="x-clear"></div></div>',
35170 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35173 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35174 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35175 n.nextSibling.ui.getEl(), buf.join(""));
35177 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35179 var el = this.wrap.firstChild;
35181 this.elNode = el.firstChild;
35182 this.ranchor = el.childNodes[1];
35183 this.ctNode = this.wrap.childNodes[1];
35184 var cs = el.firstChild.childNodes;
35185 this.indentNode = cs[0];
35186 this.ecNode = cs[1];
35187 this.iconNode = cs[2];
35190 this.checkbox = cs[3];
35193 this.anchor = cs[index];
35195 this.textNode = cs[index].firstChild;
35197 //el.on("click", this.onClick, this);
35198 //el.on("dblclick", this.onDblClick, this);
35201 // console.log(this);
35203 initEvents : function(){
35204 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35207 var a = this.ranchor;
35209 var el = Roo.get(a);
35211 if(Roo.isOpera){ // opera render bug ignores the CSS
35212 el.setStyle("text-decoration", "none");
35215 el.on("click", this.onClick, this);
35216 el.on("dblclick", this.onDblClick, this);
35217 el.on("contextmenu", this.onContextMenu, this);
35221 /*onSelectedChange : function(state){
35224 this.addClass("x-tree-selected");
35227 this.removeClass("x-tree-selected");
35230 addClass : function(cls){
35232 Roo.fly(this.elRow).addClass(cls);
35238 removeClass : function(cls){
35240 Roo.fly(this.elRow).removeClass(cls);
35246 });//<Script type="text/javascript">
35250 * Ext JS Library 1.1.1
35251 * Copyright(c) 2006-2007, Ext JS, LLC.
35253 * Originally Released Under LGPL - original licence link has changed is not relivant.
35256 * <script type="text/javascript">
35261 * @class Roo.tree.ColumnTree
35262 * @extends Roo.data.TreePanel
35263 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35264 * @cfg {int} borderWidth compined right/left border allowance
35266 * @param {String/HTMLElement/Element} el The container element
35267 * @param {Object} config
35269 Roo.tree.ColumnTree = function(el, config)
35271 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35275 * Fire this event on a container when it resizes
35276 * @param {int} w Width
35277 * @param {int} h Height
35281 this.on('resize', this.onResize, this);
35284 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35288 borderWidth: Roo.isBorderBox ? 0 : 2,
35291 render : function(){
35292 // add the header.....
35294 Roo.tree.ColumnTree.superclass.render.apply(this);
35296 this.el.addClass('x-column-tree');
35298 this.headers = this.el.createChild(
35299 {cls:'x-tree-headers'},this.innerCt.dom);
35301 var cols = this.columns, c;
35302 var totalWidth = 0;
35304 var len = cols.length;
35305 for(var i = 0; i < len; i++){
35307 totalWidth += c.width;
35308 this.headEls.push(this.headers.createChild({
35309 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35311 cls:'x-tree-hd-text',
35314 style:'width:'+(c.width-this.borderWidth)+'px;'
35317 this.headers.createChild({cls:'x-clear'});
35318 // prevent floats from wrapping when clipped
35319 this.headers.setWidth(totalWidth);
35320 //this.innerCt.setWidth(totalWidth);
35321 this.innerCt.setStyle({ overflow: 'auto' });
35322 this.onResize(this.width, this.height);
35326 onResize : function(w,h)
35331 this.innerCt.setWidth(this.width);
35332 this.innerCt.setHeight(this.height-20);
35335 var cols = this.columns, c;
35336 var totalWidth = 0;
35338 var len = cols.length;
35339 for(var i = 0; i < len; i++){
35341 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35342 // it's the expander..
35343 expEl = this.headEls[i];
35346 totalWidth += c.width;
35350 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35352 this.headers.setWidth(w-20);
35361 * Ext JS Library 1.1.1
35362 * Copyright(c) 2006-2007, Ext JS, LLC.
35364 * Originally Released Under LGPL - original licence link has changed is not relivant.
35367 * <script type="text/javascript">
35371 * @class Roo.menu.Menu
35372 * @extends Roo.util.Observable
35373 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35374 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35376 * Creates a new Menu
35377 * @param {Object} config Configuration options
35379 Roo.menu.Menu = function(config){
35380 Roo.apply(this, config);
35381 this.id = this.id || Roo.id();
35384 * @event beforeshow
35385 * Fires before this menu is displayed
35386 * @param {Roo.menu.Menu} this
35390 * @event beforehide
35391 * Fires before this menu is hidden
35392 * @param {Roo.menu.Menu} this
35397 * Fires after this menu is displayed
35398 * @param {Roo.menu.Menu} this
35403 * Fires after this menu is hidden
35404 * @param {Roo.menu.Menu} this
35409 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35410 * @param {Roo.menu.Menu} this
35411 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35412 * @param {Roo.EventObject} e
35417 * Fires when the mouse is hovering over this menu
35418 * @param {Roo.menu.Menu} this
35419 * @param {Roo.EventObject} e
35420 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35425 * Fires when the mouse exits this menu
35426 * @param {Roo.menu.Menu} this
35427 * @param {Roo.EventObject} e
35428 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35433 * Fires when a menu item contained in this menu is clicked
35434 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35435 * @param {Roo.EventObject} e
35439 if (this.registerMenu) {
35440 Roo.menu.MenuMgr.register(this);
35443 var mis = this.items;
35444 this.items = new Roo.util.MixedCollection();
35446 this.add.apply(this, mis);
35450 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35452 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35456 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35457 * for bottom-right shadow (defaults to "sides")
35461 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35462 * this menu (defaults to "tl-tr?")
35464 subMenuAlign : "tl-tr?",
35466 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35467 * relative to its element of origin (defaults to "tl-bl?")
35469 defaultAlign : "tl-bl?",
35471 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35473 allowOtherMenus : false,
35475 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35477 registerMenu : true,
35482 render : function(){
35486 var el = this.el = new Roo.Layer({
35488 shadow:this.shadow,
35490 parentEl: this.parentEl || document.body,
35494 this.keyNav = new Roo.menu.MenuNav(this);
35497 el.addClass("x-menu-plain");
35500 el.addClass(this.cls);
35502 // generic focus element
35503 this.focusEl = el.createChild({
35504 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35506 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35507 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35509 ul.on("mouseover", this.onMouseOver, this);
35510 ul.on("mouseout", this.onMouseOut, this);
35511 this.items.each(function(item){
35516 var li = document.createElement("li");
35517 li.className = "x-menu-list-item";
35518 ul.dom.appendChild(li);
35519 item.render(li, this);
35526 autoWidth : function(){
35527 var el = this.el, ul = this.ul;
35531 var w = this.width;
35534 }else if(Roo.isIE){
35535 el.setWidth(this.minWidth);
35536 var t = el.dom.offsetWidth; // force recalc
35537 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35542 delayAutoWidth : function(){
35545 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35547 this.awTask.delay(20);
35552 findTargetItem : function(e){
35553 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35554 if(t && t.menuItemId){
35555 return this.items.get(t.menuItemId);
35560 onClick : function(e){
35561 Roo.log("menu.onClick");
35562 var t = this.findTargetItem(e);
35567 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35568 if(t == this.activeItem && t.shouldDeactivate(e)){
35569 this.activeItem.deactivate();
35570 delete this.activeItem;
35574 this.setActiveItem(t, true);
35582 this.fireEvent("click", this, t, e);
35586 setActiveItem : function(item, autoExpand){
35587 if(item != this.activeItem){
35588 if(this.activeItem){
35589 this.activeItem.deactivate();
35591 this.activeItem = item;
35592 item.activate(autoExpand);
35593 }else if(autoExpand){
35599 tryActivate : function(start, step){
35600 var items = this.items;
35601 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35602 var item = items.get(i);
35603 if(!item.disabled && item.canActivate){
35604 this.setActiveItem(item, false);
35612 onMouseOver : function(e){
35614 if(t = this.findTargetItem(e)){
35615 if(t.canActivate && !t.disabled){
35616 this.setActiveItem(t, true);
35619 this.fireEvent("mouseover", this, e, t);
35623 onMouseOut : function(e){
35625 if(t = this.findTargetItem(e)){
35626 if(t == this.activeItem && t.shouldDeactivate(e)){
35627 this.activeItem.deactivate();
35628 delete this.activeItem;
35631 this.fireEvent("mouseout", this, e, t);
35635 * Read-only. Returns true if the menu is currently displayed, else false.
35638 isVisible : function(){
35639 return this.el && !this.hidden;
35643 * Displays this menu relative to another element
35644 * @param {String/HTMLElement/Roo.Element} element The element to align to
35645 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35646 * the element (defaults to this.defaultAlign)
35647 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35649 show : function(el, pos, parentMenu){
35650 this.parentMenu = parentMenu;
35654 this.fireEvent("beforeshow", this);
35655 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35659 * Displays this menu at a specific xy position
35660 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35661 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35663 showAt : function(xy, parentMenu, /* private: */_e){
35664 this.parentMenu = parentMenu;
35669 this.fireEvent("beforeshow", this);
35670 xy = this.el.adjustForConstraints(xy);
35674 this.hidden = false;
35676 this.fireEvent("show", this);
35679 focus : function(){
35681 this.doFocus.defer(50, this);
35685 doFocus : function(){
35687 this.focusEl.focus();
35692 * Hides this menu and optionally all parent menus
35693 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35695 hide : function(deep){
35696 if(this.el && this.isVisible()){
35697 this.fireEvent("beforehide", this);
35698 if(this.activeItem){
35699 this.activeItem.deactivate();
35700 this.activeItem = null;
35703 this.hidden = true;
35704 this.fireEvent("hide", this);
35706 if(deep === true && this.parentMenu){
35707 this.parentMenu.hide(true);
35712 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35713 * Any of the following are valid:
35715 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35716 * <li>An HTMLElement object which will be converted to a menu item</li>
35717 * <li>A menu item config object that will be created as a new menu item</li>
35718 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35719 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35724 var menu = new Roo.menu.Menu();
35726 // Create a menu item to add by reference
35727 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35729 // Add a bunch of items at once using different methods.
35730 // Only the last item added will be returned.
35731 var item = menu.add(
35732 menuItem, // add existing item by ref
35733 'Dynamic Item', // new TextItem
35734 '-', // new separator
35735 { text: 'Config Item' } // new item by config
35738 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35739 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35742 var a = arguments, l = a.length, item;
35743 for(var i = 0; i < l; i++){
35745 if ((typeof(el) == "object") && el.xtype && el.xns) {
35746 el = Roo.factory(el, Roo.menu);
35749 if(el.render){ // some kind of Item
35750 item = this.addItem(el);
35751 }else if(typeof el == "string"){ // string
35752 if(el == "separator" || el == "-"){
35753 item = this.addSeparator();
35755 item = this.addText(el);
35757 }else if(el.tagName || el.el){ // element
35758 item = this.addElement(el);
35759 }else if(typeof el == "object"){ // must be menu item config?
35760 item = this.addMenuItem(el);
35767 * Returns this menu's underlying {@link Roo.Element} object
35768 * @return {Roo.Element} The element
35770 getEl : function(){
35778 * Adds a separator bar to the menu
35779 * @return {Roo.menu.Item} The menu item that was added
35781 addSeparator : function(){
35782 return this.addItem(new Roo.menu.Separator());
35786 * Adds an {@link Roo.Element} object to the menu
35787 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35788 * @return {Roo.menu.Item} The menu item that was added
35790 addElement : function(el){
35791 return this.addItem(new Roo.menu.BaseItem(el));
35795 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35796 * @param {Roo.menu.Item} item The menu item to add
35797 * @return {Roo.menu.Item} The menu item that was added
35799 addItem : function(item){
35800 this.items.add(item);
35802 var li = document.createElement("li");
35803 li.className = "x-menu-list-item";
35804 this.ul.dom.appendChild(li);
35805 item.render(li, this);
35806 this.delayAutoWidth();
35812 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35813 * @param {Object} config A MenuItem config object
35814 * @return {Roo.menu.Item} The menu item that was added
35816 addMenuItem : function(config){
35817 if(!(config instanceof Roo.menu.Item)){
35818 if(typeof config.checked == "boolean"){ // must be check menu item config?
35819 config = new Roo.menu.CheckItem(config);
35821 config = new Roo.menu.Item(config);
35824 return this.addItem(config);
35828 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35829 * @param {String} text The text to display in the menu item
35830 * @return {Roo.menu.Item} The menu item that was added
35832 addText : function(text){
35833 return this.addItem(new Roo.menu.TextItem({ text : text }));
35837 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35838 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35839 * @param {Roo.menu.Item} item The menu item to add
35840 * @return {Roo.menu.Item} The menu item that was added
35842 insert : function(index, item){
35843 this.items.insert(index, item);
35845 var li = document.createElement("li");
35846 li.className = "x-menu-list-item";
35847 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35848 item.render(li, this);
35849 this.delayAutoWidth();
35855 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35856 * @param {Roo.menu.Item} item The menu item to remove
35858 remove : function(item){
35859 this.items.removeKey(item.id);
35864 * Removes and destroys all items in the menu
35866 removeAll : function(){
35868 while(f = this.items.first()){
35874 // MenuNav is a private utility class used internally by the Menu
35875 Roo.menu.MenuNav = function(menu){
35876 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35877 this.scope = this.menu = menu;
35880 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35881 doRelay : function(e, h){
35882 var k = e.getKey();
35883 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35884 this.menu.tryActivate(0, 1);
35887 return h.call(this.scope || this, e, this.menu);
35890 up : function(e, m){
35891 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35892 m.tryActivate(m.items.length-1, -1);
35896 down : function(e, m){
35897 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35898 m.tryActivate(0, 1);
35902 right : function(e, m){
35904 m.activeItem.expandMenu(true);
35908 left : function(e, m){
35910 if(m.parentMenu && m.parentMenu.activeItem){
35911 m.parentMenu.activeItem.activate();
35915 enter : function(e, m){
35917 e.stopPropagation();
35918 m.activeItem.onClick(e);
35919 m.fireEvent("click", this, m.activeItem);
35925 * Ext JS Library 1.1.1
35926 * Copyright(c) 2006-2007, Ext JS, LLC.
35928 * Originally Released Under LGPL - original licence link has changed is not relivant.
35931 * <script type="text/javascript">
35935 * @class Roo.menu.MenuMgr
35936 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35939 Roo.menu.MenuMgr = function(){
35940 var menus, active, groups = {}, attached = false, lastShow = new Date();
35942 // private - called when first menu is created
35945 active = new Roo.util.MixedCollection();
35946 Roo.get(document).addKeyListener(27, function(){
35947 if(active.length > 0){
35954 function hideAll(){
35955 if(active && active.length > 0){
35956 var c = active.clone();
35957 c.each(function(m){
35964 function onHide(m){
35966 if(active.length < 1){
35967 Roo.get(document).un("mousedown", onMouseDown);
35973 function onShow(m){
35974 var last = active.last();
35975 lastShow = new Date();
35978 Roo.get(document).on("mousedown", onMouseDown);
35982 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35983 m.parentMenu.activeChild = m;
35984 }else if(last && last.isVisible()){
35985 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35990 function onBeforeHide(m){
35992 m.activeChild.hide();
35994 if(m.autoHideTimer){
35995 clearTimeout(m.autoHideTimer);
35996 delete m.autoHideTimer;
36001 function onBeforeShow(m){
36002 var pm = m.parentMenu;
36003 if(!pm && !m.allowOtherMenus){
36005 }else if(pm && pm.activeChild && active != m){
36006 pm.activeChild.hide();
36011 function onMouseDown(e){
36012 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36018 function onBeforeCheck(mi, state){
36020 var g = groups[mi.group];
36021 for(var i = 0, l = g.length; i < l; i++){
36023 g[i].setChecked(false);
36032 * Hides all menus that are currently visible
36034 hideAll : function(){
36039 register : function(menu){
36043 menus[menu.id] = menu;
36044 menu.on("beforehide", onBeforeHide);
36045 menu.on("hide", onHide);
36046 menu.on("beforeshow", onBeforeShow);
36047 menu.on("show", onShow);
36048 var g = menu.group;
36049 if(g && menu.events["checkchange"]){
36053 groups[g].push(menu);
36054 menu.on("checkchange", onCheck);
36059 * Returns a {@link Roo.menu.Menu} object
36060 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36061 * be used to generate and return a new Menu instance.
36063 get : function(menu){
36064 if(typeof menu == "string"){ // menu id
36065 return menus[menu];
36066 }else if(menu.events){ // menu instance
36068 }else if(typeof menu.length == 'number'){ // array of menu items?
36069 return new Roo.menu.Menu({items:menu});
36070 }else{ // otherwise, must be a config
36071 return new Roo.menu.Menu(menu);
36076 unregister : function(menu){
36077 delete menus[menu.id];
36078 menu.un("beforehide", onBeforeHide);
36079 menu.un("hide", onHide);
36080 menu.un("beforeshow", onBeforeShow);
36081 menu.un("show", onShow);
36082 var g = menu.group;
36083 if(g && menu.events["checkchange"]){
36084 groups[g].remove(menu);
36085 menu.un("checkchange", onCheck);
36090 registerCheckable : function(menuItem){
36091 var g = menuItem.group;
36096 groups[g].push(menuItem);
36097 menuItem.on("beforecheckchange", onBeforeCheck);
36102 unregisterCheckable : function(menuItem){
36103 var g = menuItem.group;
36105 groups[g].remove(menuItem);
36106 menuItem.un("beforecheckchange", onBeforeCheck);
36112 * Ext JS Library 1.1.1
36113 * Copyright(c) 2006-2007, Ext JS, LLC.
36115 * Originally Released Under LGPL - original licence link has changed is not relivant.
36118 * <script type="text/javascript">
36123 * @class Roo.menu.BaseItem
36124 * @extends Roo.Component
36125 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36126 * management and base configuration options shared by all menu components.
36128 * Creates a new BaseItem
36129 * @param {Object} config Configuration options
36131 Roo.menu.BaseItem = function(config){
36132 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36137 * Fires when this item is clicked
36138 * @param {Roo.menu.BaseItem} this
36139 * @param {Roo.EventObject} e
36144 * Fires when this item is activated
36145 * @param {Roo.menu.BaseItem} this
36149 * @event deactivate
36150 * Fires when this item is deactivated
36151 * @param {Roo.menu.BaseItem} this
36157 this.on("click", this.handler, this.scope, true);
36161 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36163 * @cfg {Function} handler
36164 * A function that will handle the click event of this menu item (defaults to undefined)
36167 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36169 canActivate : false,
36172 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36177 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36179 activeClass : "x-menu-item-active",
36181 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36183 hideOnClick : true,
36185 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36190 ctype: "Roo.menu.BaseItem",
36193 actionMode : "container",
36196 render : function(container, parentMenu){
36197 this.parentMenu = parentMenu;
36198 Roo.menu.BaseItem.superclass.render.call(this, container);
36199 this.container.menuItemId = this.id;
36203 onRender : function(container, position){
36204 this.el = Roo.get(this.el);
36205 container.dom.appendChild(this.el.dom);
36209 onClick : function(e){
36210 if(!this.disabled && this.fireEvent("click", this, e) !== false
36211 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36212 this.handleClick(e);
36219 activate : function(){
36223 var li = this.container;
36224 li.addClass(this.activeClass);
36225 this.region = li.getRegion().adjust(2, 2, -2, -2);
36226 this.fireEvent("activate", this);
36231 deactivate : function(){
36232 this.container.removeClass(this.activeClass);
36233 this.fireEvent("deactivate", this);
36237 shouldDeactivate : function(e){
36238 return !this.region || !this.region.contains(e.getPoint());
36242 handleClick : function(e){
36243 if(this.hideOnClick){
36244 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36249 expandMenu : function(autoActivate){
36254 hideMenu : function(){
36259 * Ext JS Library 1.1.1
36260 * Copyright(c) 2006-2007, Ext JS, LLC.
36262 * Originally Released Under LGPL - original licence link has changed is not relivant.
36265 * <script type="text/javascript">
36269 * @class Roo.menu.Adapter
36270 * @extends Roo.menu.BaseItem
36271 * 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.
36272 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36274 * Creates a new Adapter
36275 * @param {Object} config Configuration options
36277 Roo.menu.Adapter = function(component, config){
36278 Roo.menu.Adapter.superclass.constructor.call(this, config);
36279 this.component = component;
36281 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36283 canActivate : true,
36286 onRender : function(container, position){
36287 this.component.render(container);
36288 this.el = this.component.getEl();
36292 activate : function(){
36296 this.component.focus();
36297 this.fireEvent("activate", this);
36302 deactivate : function(){
36303 this.fireEvent("deactivate", this);
36307 disable : function(){
36308 this.component.disable();
36309 Roo.menu.Adapter.superclass.disable.call(this);
36313 enable : function(){
36314 this.component.enable();
36315 Roo.menu.Adapter.superclass.enable.call(this);
36319 * Ext JS Library 1.1.1
36320 * Copyright(c) 2006-2007, Ext JS, LLC.
36322 * Originally Released Under LGPL - original licence link has changed is not relivant.
36325 * <script type="text/javascript">
36329 * @class Roo.menu.TextItem
36330 * @extends Roo.menu.BaseItem
36331 * Adds a static text string to a menu, usually used as either a heading or group separator.
36332 * Note: old style constructor with text is still supported.
36335 * Creates a new TextItem
36336 * @param {Object} cfg Configuration
36338 Roo.menu.TextItem = function(cfg){
36339 if (typeof(cfg) == 'string') {
36342 Roo.apply(this,cfg);
36345 Roo.menu.TextItem.superclass.constructor.call(this);
36348 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36350 * @cfg {Boolean} text Text to show on item.
36355 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36357 hideOnClick : false,
36359 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36361 itemCls : "x-menu-text",
36364 onRender : function(){
36365 var s = document.createElement("span");
36366 s.className = this.itemCls;
36367 s.innerHTML = this.text;
36369 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36373 * Ext JS Library 1.1.1
36374 * Copyright(c) 2006-2007, Ext JS, LLC.
36376 * Originally Released Under LGPL - original licence link has changed is not relivant.
36379 * <script type="text/javascript">
36383 * @class Roo.menu.Separator
36384 * @extends Roo.menu.BaseItem
36385 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36386 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36388 * @param {Object} config Configuration options
36390 Roo.menu.Separator = function(config){
36391 Roo.menu.Separator.superclass.constructor.call(this, config);
36394 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36396 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36398 itemCls : "x-menu-sep",
36400 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36402 hideOnClick : false,
36405 onRender : function(li){
36406 var s = document.createElement("span");
36407 s.className = this.itemCls;
36408 s.innerHTML = " ";
36410 li.addClass("x-menu-sep-li");
36411 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36415 * Ext JS Library 1.1.1
36416 * Copyright(c) 2006-2007, Ext JS, LLC.
36418 * Originally Released Under LGPL - original licence link has changed is not relivant.
36421 * <script type="text/javascript">
36424 * @class Roo.menu.Item
36425 * @extends Roo.menu.BaseItem
36426 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36427 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36428 * activation and click handling.
36430 * Creates a new Item
36431 * @param {Object} config Configuration options
36433 Roo.menu.Item = function(config){
36434 Roo.menu.Item.superclass.constructor.call(this, config);
36436 this.menu = Roo.menu.MenuMgr.get(this.menu);
36439 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36442 * @cfg {String} text
36443 * The text to show on the menu item.
36447 * @cfg {String} HTML to render in menu
36448 * The text to show on the menu item (HTML version).
36452 * @cfg {String} icon
36453 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36457 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36459 itemCls : "x-menu-item",
36461 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36463 canActivate : true,
36465 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36468 // doc'd in BaseItem
36472 ctype: "Roo.menu.Item",
36475 onRender : function(container, position){
36476 var el = document.createElement("a");
36477 el.hideFocus = true;
36478 el.unselectable = "on";
36479 el.href = this.href || "#";
36480 if(this.hrefTarget){
36481 el.target = this.hrefTarget;
36483 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36485 var html = this.html.length ? this.html : String.format('{0}',this.text);
36487 el.innerHTML = String.format(
36488 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36489 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36491 Roo.menu.Item.superclass.onRender.call(this, container, position);
36495 * Sets the text to display in this menu item
36496 * @param {String} text The text to display
36497 * @param {Boolean} isHTML true to indicate text is pure html.
36499 setText : function(text, isHTML){
36507 var html = this.html.length ? this.html : String.format('{0}',this.text);
36509 this.el.update(String.format(
36510 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36511 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36512 this.parentMenu.autoWidth();
36517 handleClick : function(e){
36518 if(!this.href){ // if no link defined, stop the event automatically
36521 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36525 activate : function(autoExpand){
36526 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36536 shouldDeactivate : function(e){
36537 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36538 if(this.menu && this.menu.isVisible()){
36539 return !this.menu.getEl().getRegion().contains(e.getPoint());
36547 deactivate : function(){
36548 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36553 expandMenu : function(autoActivate){
36554 if(!this.disabled && this.menu){
36555 clearTimeout(this.hideTimer);
36556 delete this.hideTimer;
36557 if(!this.menu.isVisible() && !this.showTimer){
36558 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36559 }else if (this.menu.isVisible() && autoActivate){
36560 this.menu.tryActivate(0, 1);
36566 deferExpand : function(autoActivate){
36567 delete this.showTimer;
36568 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36570 this.menu.tryActivate(0, 1);
36575 hideMenu : function(){
36576 clearTimeout(this.showTimer);
36577 delete this.showTimer;
36578 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36579 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36584 deferHide : function(){
36585 delete this.hideTimer;
36590 * Ext JS Library 1.1.1
36591 * Copyright(c) 2006-2007, Ext JS, LLC.
36593 * Originally Released Under LGPL - original licence link has changed is not relivant.
36596 * <script type="text/javascript">
36600 * @class Roo.menu.CheckItem
36601 * @extends Roo.menu.Item
36602 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36604 * Creates a new CheckItem
36605 * @param {Object} config Configuration options
36607 Roo.menu.CheckItem = function(config){
36608 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36611 * @event beforecheckchange
36612 * Fires before the checked value is set, providing an opportunity to cancel if needed
36613 * @param {Roo.menu.CheckItem} this
36614 * @param {Boolean} checked The new checked value that will be set
36616 "beforecheckchange" : true,
36618 * @event checkchange
36619 * Fires after the checked value has been set
36620 * @param {Roo.menu.CheckItem} this
36621 * @param {Boolean} checked The checked value that was set
36623 "checkchange" : true
36625 if(this.checkHandler){
36626 this.on('checkchange', this.checkHandler, this.scope);
36629 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36631 * @cfg {String} group
36632 * All check items with the same group name will automatically be grouped into a single-select
36633 * radio button group (defaults to '')
36636 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36638 itemCls : "x-menu-item x-menu-check-item",
36640 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36642 groupClass : "x-menu-group-item",
36645 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36646 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36647 * initialized with checked = true will be rendered as checked.
36652 ctype: "Roo.menu.CheckItem",
36655 onRender : function(c){
36656 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36658 this.el.addClass(this.groupClass);
36660 Roo.menu.MenuMgr.registerCheckable(this);
36662 this.checked = false;
36663 this.setChecked(true, true);
36668 destroy : function(){
36670 Roo.menu.MenuMgr.unregisterCheckable(this);
36672 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36676 * Set the checked state of this item
36677 * @param {Boolean} checked The new checked value
36678 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36680 setChecked : function(state, suppressEvent){
36681 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36682 if(this.container){
36683 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36685 this.checked = state;
36686 if(suppressEvent !== true){
36687 this.fireEvent("checkchange", this, state);
36693 handleClick : function(e){
36694 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36695 this.setChecked(!this.checked);
36697 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36701 * Ext JS Library 1.1.1
36702 * Copyright(c) 2006-2007, Ext JS, LLC.
36704 * Originally Released Under LGPL - original licence link has changed is not relivant.
36707 * <script type="text/javascript">
36711 * @class Roo.menu.DateItem
36712 * @extends Roo.menu.Adapter
36713 * A menu item that wraps the {@link Roo.DatPicker} component.
36715 * Creates a new DateItem
36716 * @param {Object} config Configuration options
36718 Roo.menu.DateItem = function(config){
36719 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36720 /** The Roo.DatePicker object @type Roo.DatePicker */
36721 this.picker = this.component;
36722 this.addEvents({select: true});
36724 this.picker.on("render", function(picker){
36725 picker.getEl().swallowEvent("click");
36726 picker.container.addClass("x-menu-date-item");
36729 this.picker.on("select", this.onSelect, this);
36732 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36734 onSelect : function(picker, date){
36735 this.fireEvent("select", this, date, picker);
36736 Roo.menu.DateItem.superclass.handleClick.call(this);
36740 * Ext JS Library 1.1.1
36741 * Copyright(c) 2006-2007, Ext JS, LLC.
36743 * Originally Released Under LGPL - original licence link has changed is not relivant.
36746 * <script type="text/javascript">
36750 * @class Roo.menu.ColorItem
36751 * @extends Roo.menu.Adapter
36752 * A menu item that wraps the {@link Roo.ColorPalette} component.
36754 * Creates a new ColorItem
36755 * @param {Object} config Configuration options
36757 Roo.menu.ColorItem = function(config){
36758 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36759 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36760 this.palette = this.component;
36761 this.relayEvents(this.palette, ["select"]);
36762 if(this.selectHandler){
36763 this.on('select', this.selectHandler, this.scope);
36766 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36768 * Ext JS Library 1.1.1
36769 * Copyright(c) 2006-2007, Ext JS, LLC.
36771 * Originally Released Under LGPL - original licence link has changed is not relivant.
36774 * <script type="text/javascript">
36779 * @class Roo.menu.DateMenu
36780 * @extends Roo.menu.Menu
36781 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36783 * Creates a new DateMenu
36784 * @param {Object} config Configuration options
36786 Roo.menu.DateMenu = function(config){
36787 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36789 var di = new Roo.menu.DateItem(config);
36792 * The {@link Roo.DatePicker} instance for this DateMenu
36795 this.picker = di.picker;
36798 * @param {DatePicker} picker
36799 * @param {Date} date
36801 this.relayEvents(di, ["select"]);
36802 this.on('beforeshow', function(){
36804 this.picker.hideMonthPicker(false);
36808 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36812 * Ext JS Library 1.1.1
36813 * Copyright(c) 2006-2007, Ext JS, LLC.
36815 * Originally Released Under LGPL - original licence link has changed is not relivant.
36818 * <script type="text/javascript">
36823 * @class Roo.menu.ColorMenu
36824 * @extends Roo.menu.Menu
36825 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36827 * Creates a new ColorMenu
36828 * @param {Object} config Configuration options
36830 Roo.menu.ColorMenu = function(config){
36831 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36833 var ci = new Roo.menu.ColorItem(config);
36836 * The {@link Roo.ColorPalette} instance for this ColorMenu
36837 * @type ColorPalette
36839 this.palette = ci.palette;
36842 * @param {ColorPalette} palette
36843 * @param {String} color
36845 this.relayEvents(ci, ["select"]);
36847 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36849 * Ext JS Library 1.1.1
36850 * Copyright(c) 2006-2007, Ext JS, LLC.
36852 * Originally Released Under LGPL - original licence link has changed is not relivant.
36855 * <script type="text/javascript">
36859 * @class Roo.form.Field
36860 * @extends Roo.BoxComponent
36861 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36863 * Creates a new Field
36864 * @param {Object} config Configuration options
36866 Roo.form.Field = function(config){
36867 Roo.form.Field.superclass.constructor.call(this, config);
36870 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36872 * @cfg {String} fieldLabel Label to use when rendering a form.
36875 * @cfg {String} qtip Mouse over tip
36879 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36881 invalidClass : "x-form-invalid",
36883 * @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")
36885 invalidText : "The value in this field is invalid",
36887 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36889 focusClass : "x-form-focus",
36891 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36892 automatic validation (defaults to "keyup").
36894 validationEvent : "keyup",
36896 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36898 validateOnBlur : true,
36900 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36902 validationDelay : 250,
36904 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36905 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36907 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36909 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36911 fieldClass : "x-form-field",
36913 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36916 ----------- ----------------------------------------------------------------------
36917 qtip Display a quick tip when the user hovers over the field
36918 title Display a default browser title attribute popup
36919 under Add a block div beneath the field containing the error text
36920 side Add an error icon to the right of the field with a popup on hover
36921 [element id] Add the error text directly to the innerHTML of the specified element
36924 msgTarget : 'qtip',
36926 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36931 * @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.
36936 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36941 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36943 inputType : undefined,
36946 * @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).
36948 tabIndex : undefined,
36951 isFormField : true,
36956 * @property {Roo.Element} fieldEl
36957 * Element Containing the rendered Field (with label etc.)
36960 * @cfg {Mixed} value A value to initialize this field with.
36965 * @cfg {String} name The field's HTML name attribute.
36968 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36972 initComponent : function(){
36973 Roo.form.Field.superclass.initComponent.call(this);
36977 * Fires when this field receives input focus.
36978 * @param {Roo.form.Field} this
36983 * Fires when this field loses input focus.
36984 * @param {Roo.form.Field} this
36988 * @event specialkey
36989 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36990 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36991 * @param {Roo.form.Field} this
36992 * @param {Roo.EventObject} e The event object
36997 * Fires just before the field blurs if the field value has changed.
36998 * @param {Roo.form.Field} this
36999 * @param {Mixed} newValue The new value
37000 * @param {Mixed} oldValue The original value
37005 * Fires after the field has been marked as invalid.
37006 * @param {Roo.form.Field} this
37007 * @param {String} msg The validation message
37012 * Fires after the field has been validated with no errors.
37013 * @param {Roo.form.Field} this
37018 * Fires after the key up
37019 * @param {Roo.form.Field} this
37020 * @param {Roo.EventObject} e The event Object
37027 * Returns the name attribute of the field if available
37028 * @return {String} name The field name
37030 getName: function(){
37031 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37035 onRender : function(ct, position){
37036 Roo.form.Field.superclass.onRender.call(this, ct, position);
37038 var cfg = this.getAutoCreate();
37040 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37042 if (!cfg.name.length) {
37045 if(this.inputType){
37046 cfg.type = this.inputType;
37048 this.el = ct.createChild(cfg, position);
37050 var type = this.el.dom.type;
37052 if(type == 'password'){
37055 this.el.addClass('x-form-'+type);
37058 this.el.dom.readOnly = true;
37060 if(this.tabIndex !== undefined){
37061 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37064 this.el.addClass([this.fieldClass, this.cls]);
37069 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37070 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37071 * @return {Roo.form.Field} this
37073 applyTo : function(target){
37074 this.allowDomMove = false;
37075 this.el = Roo.get(target);
37076 this.render(this.el.dom.parentNode);
37081 initValue : function(){
37082 if(this.value !== undefined){
37083 this.setValue(this.value);
37084 }else if(this.el.dom.value.length > 0){
37085 this.setValue(this.el.dom.value);
37090 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37092 isDirty : function() {
37093 if(this.disabled) {
37096 return String(this.getValue()) !== String(this.originalValue);
37100 afterRender : function(){
37101 Roo.form.Field.superclass.afterRender.call(this);
37106 fireKey : function(e){
37107 //Roo.log('field ' + e.getKey());
37108 if(e.isNavKeyPress()){
37109 this.fireEvent("specialkey", this, e);
37114 * Resets the current field value to the originally loaded value and clears any validation messages
37116 reset : function(){
37117 this.setValue(this.resetValue);
37118 this.clearInvalid();
37122 initEvents : function(){
37123 // safari killled keypress - so keydown is now used..
37124 this.el.on("keydown" , this.fireKey, this);
37125 this.el.on("focus", this.onFocus, this);
37126 this.el.on("blur", this.onBlur, this);
37127 this.el.relayEvent('keyup', this);
37129 // reference to original value for reset
37130 this.originalValue = this.getValue();
37131 this.resetValue = this.getValue();
37135 onFocus : function(){
37136 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37137 this.el.addClass(this.focusClass);
37139 if(!this.hasFocus){
37140 this.hasFocus = true;
37141 this.startValue = this.getValue();
37142 this.fireEvent("focus", this);
37146 beforeBlur : Roo.emptyFn,
37149 onBlur : function(){
37151 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37152 this.el.removeClass(this.focusClass);
37154 this.hasFocus = false;
37155 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37158 var v = this.getValue();
37159 if(String(v) !== String(this.startValue)){
37160 this.fireEvent('change', this, v, this.startValue);
37162 this.fireEvent("blur", this);
37166 * Returns whether or not the field value is currently valid
37167 * @param {Boolean} preventMark True to disable marking the field invalid
37168 * @return {Boolean} True if the value is valid, else false
37170 isValid : function(preventMark){
37174 var restore = this.preventMark;
37175 this.preventMark = preventMark === true;
37176 var v = this.validateValue(this.processValue(this.getRawValue()));
37177 this.preventMark = restore;
37182 * Validates the field value
37183 * @return {Boolean} True if the value is valid, else false
37185 validate : function(){
37186 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37187 this.clearInvalid();
37193 processValue : function(value){
37198 // Subclasses should provide the validation implementation by overriding this
37199 validateValue : function(value){
37204 * Mark this field as invalid
37205 * @param {String} msg The validation message
37207 markInvalid : function(msg){
37208 if(!this.rendered || this.preventMark){ // not rendered
37212 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37214 obj.el.addClass(this.invalidClass);
37215 msg = msg || this.invalidText;
37216 switch(this.msgTarget){
37218 obj.el.dom.qtip = msg;
37219 obj.el.dom.qclass = 'x-form-invalid-tip';
37220 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37221 Roo.QuickTips.enable();
37225 this.el.dom.title = msg;
37229 var elp = this.el.findParent('.x-form-element', 5, true);
37230 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37231 this.errorEl.setWidth(elp.getWidth(true)-20);
37233 this.errorEl.update(msg);
37234 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37237 if(!this.errorIcon){
37238 var elp = this.el.findParent('.x-form-element', 5, true);
37239 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37241 this.alignErrorIcon();
37242 this.errorIcon.dom.qtip = msg;
37243 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37244 this.errorIcon.show();
37245 this.on('resize', this.alignErrorIcon, this);
37248 var t = Roo.getDom(this.msgTarget);
37250 t.style.display = this.msgDisplay;
37253 this.fireEvent('invalid', this, msg);
37257 alignErrorIcon : function(){
37258 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37262 * Clear any invalid styles/messages for this field
37264 clearInvalid : function(){
37265 if(!this.rendered || this.preventMark){ // not rendered
37268 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37270 obj.el.removeClass(this.invalidClass);
37271 switch(this.msgTarget){
37273 obj.el.dom.qtip = '';
37276 this.el.dom.title = '';
37280 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37284 if(this.errorIcon){
37285 this.errorIcon.dom.qtip = '';
37286 this.errorIcon.hide();
37287 this.un('resize', this.alignErrorIcon, this);
37291 var t = Roo.getDom(this.msgTarget);
37293 t.style.display = 'none';
37296 this.fireEvent('valid', this);
37300 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37301 * @return {Mixed} value The field value
37303 getRawValue : function(){
37304 var v = this.el.getValue();
37310 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37311 * @return {Mixed} value The field value
37313 getValue : function(){
37314 var v = this.el.getValue();
37320 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37321 * @param {Mixed} value The value to set
37323 setRawValue : function(v){
37324 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37328 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37329 * @param {Mixed} value The value to set
37331 setValue : function(v){
37334 this.el.dom.value = (v === null || v === undefined ? '' : v);
37339 adjustSize : function(w, h){
37340 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37341 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37345 adjustWidth : function(tag, w){
37346 tag = tag.toLowerCase();
37347 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37348 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37349 if(tag == 'input'){
37352 if(tag == 'textarea'){
37355 }else if(Roo.isOpera){
37356 if(tag == 'input'){
37359 if(tag == 'textarea'){
37369 // anything other than normal should be considered experimental
37370 Roo.form.Field.msgFx = {
37372 show: function(msgEl, f){
37373 msgEl.setDisplayed('block');
37376 hide : function(msgEl, f){
37377 msgEl.setDisplayed(false).update('');
37382 show: function(msgEl, f){
37383 msgEl.slideIn('t', {stopFx:true});
37386 hide : function(msgEl, f){
37387 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37392 show: function(msgEl, f){
37393 msgEl.fixDisplay();
37394 msgEl.alignTo(f.el, 'tl-tr');
37395 msgEl.slideIn('l', {stopFx:true});
37398 hide : function(msgEl, f){
37399 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37404 * Ext JS Library 1.1.1
37405 * Copyright(c) 2006-2007, Ext JS, LLC.
37407 * Originally Released Under LGPL - original licence link has changed is not relivant.
37410 * <script type="text/javascript">
37415 * @class Roo.form.TextField
37416 * @extends Roo.form.Field
37417 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37418 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37420 * Creates a new TextField
37421 * @param {Object} config Configuration options
37423 Roo.form.TextField = function(config){
37424 Roo.form.TextField.superclass.constructor.call(this, config);
37428 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37429 * according to the default logic, but this event provides a hook for the developer to apply additional
37430 * logic at runtime to resize the field if needed.
37431 * @param {Roo.form.Field} this This text field
37432 * @param {Number} width The new field width
37438 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37440 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37444 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37448 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37452 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37456 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37460 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37462 disableKeyFilter : false,
37464 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37468 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37472 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37474 maxLength : Number.MAX_VALUE,
37476 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37478 minLengthText : "The minimum length for this field is {0}",
37480 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37482 maxLengthText : "The maximum length for this field is {0}",
37484 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37486 selectOnFocus : false,
37488 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37490 blankText : "This field is required",
37492 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37493 * If available, this function will be called only after the basic validators all return true, and will be passed the
37494 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37498 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37499 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37500 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37504 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37508 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37514 initEvents : function()
37516 if (this.emptyText) {
37517 this.el.attr('placeholder', this.emptyText);
37520 Roo.form.TextField.superclass.initEvents.call(this);
37521 if(this.validationEvent == 'keyup'){
37522 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37523 this.el.on('keyup', this.filterValidation, this);
37525 else if(this.validationEvent !== false){
37526 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37529 if(this.selectOnFocus){
37530 this.on("focus", this.preFocus, this);
37533 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37534 this.el.on("keypress", this.filterKeys, this);
37537 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37538 this.el.on("click", this.autoSize, this);
37540 if(this.el.is('input[type=password]') && Roo.isSafari){
37541 this.el.on('keydown', this.SafariOnKeyDown, this);
37545 processValue : function(value){
37546 if(this.stripCharsRe){
37547 var newValue = value.replace(this.stripCharsRe, '');
37548 if(newValue !== value){
37549 this.setRawValue(newValue);
37556 filterValidation : function(e){
37557 if(!e.isNavKeyPress()){
37558 this.validationTask.delay(this.validationDelay);
37563 onKeyUp : function(e){
37564 if(!e.isNavKeyPress()){
37570 * Resets the current field value to the originally-loaded value and clears any validation messages.
37573 reset : function(){
37574 Roo.form.TextField.superclass.reset.call(this);
37580 preFocus : function(){
37582 if(this.selectOnFocus){
37583 this.el.dom.select();
37589 filterKeys : function(e){
37590 var k = e.getKey();
37591 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37594 var c = e.getCharCode(), cc = String.fromCharCode(c);
37595 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37598 if(!this.maskRe.test(cc)){
37603 setValue : function(v){
37605 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37611 * Validates a value according to the field's validation rules and marks the field as invalid
37612 * if the validation fails
37613 * @param {Mixed} value The value to validate
37614 * @return {Boolean} True if the value is valid, else false
37616 validateValue : function(value){
37617 if(value.length < 1) { // if it's blank
37618 if(this.allowBlank){
37619 this.clearInvalid();
37622 this.markInvalid(this.blankText);
37626 if(value.length < this.minLength){
37627 this.markInvalid(String.format(this.minLengthText, this.minLength));
37630 if(value.length > this.maxLength){
37631 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37635 var vt = Roo.form.VTypes;
37636 if(!vt[this.vtype](value, this)){
37637 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37641 if(typeof this.validator == "function"){
37642 var msg = this.validator(value);
37644 this.markInvalid(msg);
37648 if(this.regex && !this.regex.test(value)){
37649 this.markInvalid(this.regexText);
37656 * Selects text in this field
37657 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37658 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37660 selectText : function(start, end){
37661 var v = this.getRawValue();
37663 start = start === undefined ? 0 : start;
37664 end = end === undefined ? v.length : end;
37665 var d = this.el.dom;
37666 if(d.setSelectionRange){
37667 d.setSelectionRange(start, end);
37668 }else if(d.createTextRange){
37669 var range = d.createTextRange();
37670 range.moveStart("character", start);
37671 range.moveEnd("character", v.length-end);
37678 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37679 * This only takes effect if grow = true, and fires the autosize event.
37681 autoSize : function(){
37682 if(!this.grow || !this.rendered){
37686 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37689 var v = el.dom.value;
37690 var d = document.createElement('div');
37691 d.appendChild(document.createTextNode(v));
37695 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37696 this.el.setWidth(w);
37697 this.fireEvent("autosize", this, w);
37701 SafariOnKeyDown : function(event)
37703 // this is a workaround for a password hang bug on chrome/ webkit.
37705 var isSelectAll = false;
37707 if(this.el.dom.selectionEnd > 0){
37708 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37710 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37711 event.preventDefault();
37716 if(isSelectAll){ // backspace and delete key
37718 event.preventDefault();
37719 // this is very hacky as keydown always get's upper case.
37721 var cc = String.fromCharCode(event.getCharCode());
37722 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37730 * Ext JS Library 1.1.1
37731 * Copyright(c) 2006-2007, Ext JS, LLC.
37733 * Originally Released Under LGPL - original licence link has changed is not relivant.
37736 * <script type="text/javascript">
37740 * @class Roo.form.Hidden
37741 * @extends Roo.form.TextField
37742 * Simple Hidden element used on forms
37744 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37747 * Creates a new Hidden form element.
37748 * @param {Object} config Configuration options
37753 // easy hidden field...
37754 Roo.form.Hidden = function(config){
37755 Roo.form.Hidden.superclass.constructor.call(this, config);
37758 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37760 inputType: 'hidden',
37763 labelSeparator: '',
37765 itemCls : 'x-form-item-display-none'
37773 * Ext JS Library 1.1.1
37774 * Copyright(c) 2006-2007, Ext JS, LLC.
37776 * Originally Released Under LGPL - original licence link has changed is not relivant.
37779 * <script type="text/javascript">
37783 * @class Roo.form.TriggerField
37784 * @extends Roo.form.TextField
37785 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37786 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37787 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37788 * for which you can provide a custom implementation. For example:
37790 var trigger = new Roo.form.TriggerField();
37791 trigger.onTriggerClick = myTriggerFn;
37792 trigger.applyTo('my-field');
37795 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37796 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37797 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37798 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37800 * Create a new TriggerField.
37801 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37802 * to the base TextField)
37804 Roo.form.TriggerField = function(config){
37805 this.mimicing = false;
37806 Roo.form.TriggerField.superclass.constructor.call(this, config);
37809 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37811 * @cfg {String} triggerClass A CSS class to apply to the trigger
37814 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37815 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37817 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37819 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37823 /** @cfg {Boolean} grow @hide */
37824 /** @cfg {Number} growMin @hide */
37825 /** @cfg {Number} growMax @hide */
37831 autoSize: Roo.emptyFn,
37835 deferHeight : true,
37838 actionMode : 'wrap',
37840 onResize : function(w, h){
37841 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37842 if(typeof w == 'number'){
37843 var x = w - this.trigger.getWidth();
37844 this.el.setWidth(this.adjustWidth('input', x));
37845 this.trigger.setStyle('left', x+'px');
37850 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37853 getResizeEl : function(){
37858 getPositionEl : function(){
37863 alignErrorIcon : function(){
37864 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37868 onRender : function(ct, position){
37869 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37870 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37871 this.trigger = this.wrap.createChild(this.triggerConfig ||
37872 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37873 if(this.hideTrigger){
37874 this.trigger.setDisplayed(false);
37876 this.initTrigger();
37878 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37883 initTrigger : function(){
37884 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37885 this.trigger.addClassOnOver('x-form-trigger-over');
37886 this.trigger.addClassOnClick('x-form-trigger-click');
37890 onDestroy : function(){
37892 this.trigger.removeAllListeners();
37893 this.trigger.remove();
37896 this.wrap.remove();
37898 Roo.form.TriggerField.superclass.onDestroy.call(this);
37902 onFocus : function(){
37903 Roo.form.TriggerField.superclass.onFocus.call(this);
37904 if(!this.mimicing){
37905 this.wrap.addClass('x-trigger-wrap-focus');
37906 this.mimicing = true;
37907 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37908 if(this.monitorTab){
37909 this.el.on("keydown", this.checkTab, this);
37915 checkTab : function(e){
37916 if(e.getKey() == e.TAB){
37917 this.triggerBlur();
37922 onBlur : function(){
37927 mimicBlur : function(e, t){
37928 if(!this.wrap.contains(t) && this.validateBlur()){
37929 this.triggerBlur();
37934 triggerBlur : function(){
37935 this.mimicing = false;
37936 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37937 if(this.monitorTab){
37938 this.el.un("keydown", this.checkTab, this);
37940 this.wrap.removeClass('x-trigger-wrap-focus');
37941 Roo.form.TriggerField.superclass.onBlur.call(this);
37945 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37946 validateBlur : function(e, t){
37951 onDisable : function(){
37952 Roo.form.TriggerField.superclass.onDisable.call(this);
37954 this.wrap.addClass('x-item-disabled');
37959 onEnable : function(){
37960 Roo.form.TriggerField.superclass.onEnable.call(this);
37962 this.wrap.removeClass('x-item-disabled');
37967 onShow : function(){
37968 var ae = this.getActionEl();
37971 ae.dom.style.display = '';
37972 ae.dom.style.visibility = 'visible';
37978 onHide : function(){
37979 var ae = this.getActionEl();
37980 ae.dom.style.display = 'none';
37984 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37985 * by an implementing function.
37987 * @param {EventObject} e
37989 onTriggerClick : Roo.emptyFn
37992 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37993 // to be extended by an implementing class. For an example of implementing this class, see the custom
37994 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37995 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37996 initComponent : function(){
37997 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37999 this.triggerConfig = {
38000 tag:'span', cls:'x-form-twin-triggers', cn:[
38001 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38002 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38006 getTrigger : function(index){
38007 return this.triggers[index];
38010 initTrigger : function(){
38011 var ts = this.trigger.select('.x-form-trigger', true);
38012 this.wrap.setStyle('overflow', 'hidden');
38013 var triggerField = this;
38014 ts.each(function(t, all, index){
38015 t.hide = function(){
38016 var w = triggerField.wrap.getWidth();
38017 this.dom.style.display = 'none';
38018 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38020 t.show = function(){
38021 var w = triggerField.wrap.getWidth();
38022 this.dom.style.display = '';
38023 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38025 var triggerIndex = 'Trigger'+(index+1);
38027 if(this['hide'+triggerIndex]){
38028 t.dom.style.display = 'none';
38030 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38031 t.addClassOnOver('x-form-trigger-over');
38032 t.addClassOnClick('x-form-trigger-click');
38034 this.triggers = ts.elements;
38037 onTrigger1Click : Roo.emptyFn,
38038 onTrigger2Click : Roo.emptyFn
38041 * Ext JS Library 1.1.1
38042 * Copyright(c) 2006-2007, Ext JS, LLC.
38044 * Originally Released Under LGPL - original licence link has changed is not relivant.
38047 * <script type="text/javascript">
38051 * @class Roo.form.TextArea
38052 * @extends Roo.form.TextField
38053 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38054 * support for auto-sizing.
38056 * Creates a new TextArea
38057 * @param {Object} config Configuration options
38059 Roo.form.TextArea = function(config){
38060 Roo.form.TextArea.superclass.constructor.call(this, config);
38061 // these are provided exchanges for backwards compat
38062 // minHeight/maxHeight were replaced by growMin/growMax to be
38063 // compatible with TextField growing config values
38064 if(this.minHeight !== undefined){
38065 this.growMin = this.minHeight;
38067 if(this.maxHeight !== undefined){
38068 this.growMax = this.maxHeight;
38072 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38074 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38078 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38082 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38083 * in the field (equivalent to setting overflow: hidden, defaults to false)
38085 preventScrollbars: false,
38087 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38088 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38092 onRender : function(ct, position){
38094 this.defaultAutoCreate = {
38096 style:"width:300px;height:60px;",
38097 autocomplete: "off"
38100 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38102 this.textSizeEl = Roo.DomHelper.append(document.body, {
38103 tag: "pre", cls: "x-form-grow-sizer"
38105 if(this.preventScrollbars){
38106 this.el.setStyle("overflow", "hidden");
38108 this.el.setHeight(this.growMin);
38112 onDestroy : function(){
38113 if(this.textSizeEl){
38114 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38116 Roo.form.TextArea.superclass.onDestroy.call(this);
38120 onKeyUp : function(e){
38121 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38127 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38128 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38130 autoSize : function(){
38131 if(!this.grow || !this.textSizeEl){
38135 var v = el.dom.value;
38136 var ts = this.textSizeEl;
38139 ts.appendChild(document.createTextNode(v));
38142 Roo.fly(ts).setWidth(this.el.getWidth());
38144 v = "  ";
38147 v = v.replace(/\n/g, '<p> </p>');
38149 v += " \n ";
38152 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38153 if(h != this.lastHeight){
38154 this.lastHeight = h;
38155 this.el.setHeight(h);
38156 this.fireEvent("autosize", this, h);
38161 * Ext JS Library 1.1.1
38162 * Copyright(c) 2006-2007, Ext JS, LLC.
38164 * Originally Released Under LGPL - original licence link has changed is not relivant.
38167 * <script type="text/javascript">
38172 * @class Roo.form.NumberField
38173 * @extends Roo.form.TextField
38174 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38176 * Creates a new NumberField
38177 * @param {Object} config Configuration options
38179 Roo.form.NumberField = function(config){
38180 Roo.form.NumberField.superclass.constructor.call(this, config);
38183 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38185 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38187 fieldClass: "x-form-field x-form-num-field",
38189 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38191 allowDecimals : true,
38193 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38195 decimalSeparator : ".",
38197 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38199 decimalPrecision : 2,
38201 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38203 allowNegative : true,
38205 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38207 minValue : Number.NEGATIVE_INFINITY,
38209 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38211 maxValue : Number.MAX_VALUE,
38213 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38215 minText : "The minimum value for this field is {0}",
38217 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38219 maxText : "The maximum value for this field is {0}",
38221 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38222 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38224 nanText : "{0} is not a valid number",
38227 initEvents : function(){
38228 Roo.form.NumberField.superclass.initEvents.call(this);
38229 var allowed = "0123456789";
38230 if(this.allowDecimals){
38231 allowed += this.decimalSeparator;
38233 if(this.allowNegative){
38236 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38237 var keyPress = function(e){
38238 var k = e.getKey();
38239 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38242 var c = e.getCharCode();
38243 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38247 this.el.on("keypress", keyPress, this);
38251 validateValue : function(value){
38252 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38255 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38258 var num = this.parseValue(value);
38260 this.markInvalid(String.format(this.nanText, value));
38263 if(num < this.minValue){
38264 this.markInvalid(String.format(this.minText, this.minValue));
38267 if(num > this.maxValue){
38268 this.markInvalid(String.format(this.maxText, this.maxValue));
38274 getValue : function(){
38275 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38279 parseValue : function(value){
38280 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38281 return isNaN(value) ? '' : value;
38285 fixPrecision : function(value){
38286 var nan = isNaN(value);
38287 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38288 return nan ? '' : value;
38290 return parseFloat(value).toFixed(this.decimalPrecision);
38293 setValue : function(v){
38294 v = this.fixPrecision(v);
38295 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38299 decimalPrecisionFcn : function(v){
38300 return Math.floor(v);
38303 beforeBlur : function(){
38304 var v = this.parseValue(this.getRawValue());
38311 * Ext JS Library 1.1.1
38312 * Copyright(c) 2006-2007, Ext JS, LLC.
38314 * Originally Released Under LGPL - original licence link has changed is not relivant.
38317 * <script type="text/javascript">
38321 * @class Roo.form.DateField
38322 * @extends Roo.form.TriggerField
38323 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38325 * Create a new DateField
38326 * @param {Object} config
38328 Roo.form.DateField = function(config){
38329 Roo.form.DateField.superclass.constructor.call(this, config);
38335 * Fires when a date is selected
38336 * @param {Roo.form.DateField} combo This combo box
38337 * @param {Date} date The date selected
38344 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38345 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38346 this.ddMatch = null;
38347 if(this.disabledDates){
38348 var dd = this.disabledDates;
38350 for(var i = 0; i < dd.length; i++){
38352 if(i != dd.length-1) re += "|";
38354 this.ddMatch = new RegExp(re + ")");
38358 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38360 * @cfg {String} format
38361 * The default date format string which can be overriden for localization support. The format must be
38362 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38366 * @cfg {String} altFormats
38367 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38368 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38370 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38372 * @cfg {Array} disabledDays
38373 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38375 disabledDays : null,
38377 * @cfg {String} disabledDaysText
38378 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38380 disabledDaysText : "Disabled",
38382 * @cfg {Array} disabledDates
38383 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38384 * expression so they are very powerful. Some examples:
38386 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38387 * <li>["03/08", "09/16"] would disable those days for every year</li>
38388 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38389 * <li>["03/../2006"] would disable every day in March 2006</li>
38390 * <li>["^03"] would disable every day in every March</li>
38392 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38393 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38395 disabledDates : null,
38397 * @cfg {String} disabledDatesText
38398 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38400 disabledDatesText : "Disabled",
38402 * @cfg {Date/String} minValue
38403 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38404 * valid format (defaults to null).
38408 * @cfg {Date/String} maxValue
38409 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38410 * valid format (defaults to null).
38414 * @cfg {String} minText
38415 * The error text to display when the date in the cell is before minValue (defaults to
38416 * 'The date in this field must be after {minValue}').
38418 minText : "The date in this field must be equal to or after {0}",
38420 * @cfg {String} maxText
38421 * The error text to display when the date in the cell is after maxValue (defaults to
38422 * 'The date in this field must be before {maxValue}').
38424 maxText : "The date in this field must be equal to or before {0}",
38426 * @cfg {String} invalidText
38427 * The error text to display when the date in the field is invalid (defaults to
38428 * '{value} is not a valid date - it must be in the format {format}').
38430 invalidText : "{0} is not a valid date - it must be in the format {1}",
38432 * @cfg {String} triggerClass
38433 * An additional CSS class used to style the trigger button. The trigger will always get the
38434 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38435 * which displays a calendar icon).
38437 triggerClass : 'x-form-date-trigger',
38441 * @cfg {Boolean} useIso
38442 * if enabled, then the date field will use a hidden field to store the
38443 * real value as iso formated date. default (false)
38447 * @cfg {String/Object} autoCreate
38448 * A DomHelper element spec, or true for a default element spec (defaults to
38449 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38452 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38455 hiddenField: false,
38457 onRender : function(ct, position)
38459 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38461 //this.el.dom.removeAttribute('name');
38462 Roo.log("Changing name?");
38463 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38464 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38466 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38467 // prevent input submission
38468 this.hiddenName = this.name;
38475 validateValue : function(value)
38477 value = this.formatDate(value);
38478 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38479 Roo.log('super failed');
38482 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38485 var svalue = value;
38486 value = this.parseDate(value);
38488 Roo.log('parse date failed' + svalue);
38489 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38492 var time = value.getTime();
38493 if(this.minValue && time < this.minValue.getTime()){
38494 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38497 if(this.maxValue && time > this.maxValue.getTime()){
38498 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38501 if(this.disabledDays){
38502 var day = value.getDay();
38503 for(var i = 0; i < this.disabledDays.length; i++) {
38504 if(day === this.disabledDays[i]){
38505 this.markInvalid(this.disabledDaysText);
38510 var fvalue = this.formatDate(value);
38511 if(this.ddMatch && this.ddMatch.test(fvalue)){
38512 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38519 // Provides logic to override the default TriggerField.validateBlur which just returns true
38520 validateBlur : function(){
38521 return !this.menu || !this.menu.isVisible();
38524 getName: function()
38526 // returns hidden if it's set..
38527 if (!this.rendered) {return ''};
38528 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38533 * Returns the current date value of the date field.
38534 * @return {Date} The date value
38536 getValue : function(){
38538 return this.hiddenField ?
38539 this.hiddenField.value :
38540 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38544 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38545 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38546 * (the default format used is "m/d/y").
38549 //All of these calls set the same date value (May 4, 2006)
38551 //Pass a date object:
38552 var dt = new Date('5/4/06');
38553 dateField.setValue(dt);
38555 //Pass a date string (default format):
38556 dateField.setValue('5/4/06');
38558 //Pass a date string (custom format):
38559 dateField.format = 'Y-m-d';
38560 dateField.setValue('2006-5-4');
38562 * @param {String/Date} date The date or valid date string
38564 setValue : function(date){
38565 if (this.hiddenField) {
38566 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38568 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38569 // make sure the value field is always stored as a date..
38570 this.value = this.parseDate(date);
38576 parseDate : function(value){
38577 if(!value || value instanceof Date){
38580 var v = Date.parseDate(value, this.format);
38581 if (!v && this.useIso) {
38582 v = Date.parseDate(value, 'Y-m-d');
38584 if(!v && this.altFormats){
38585 if(!this.altFormatsArray){
38586 this.altFormatsArray = this.altFormats.split("|");
38588 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38589 v = Date.parseDate(value, this.altFormatsArray[i]);
38596 formatDate : function(date, fmt){
38597 return (!date || !(date instanceof Date)) ?
38598 date : date.dateFormat(fmt || this.format);
38603 select: function(m, d){
38606 this.fireEvent('select', this, d);
38608 show : function(){ // retain focus styling
38612 this.focus.defer(10, this);
38613 var ml = this.menuListeners;
38614 this.menu.un("select", ml.select, this);
38615 this.menu.un("show", ml.show, this);
38616 this.menu.un("hide", ml.hide, this);
38621 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38622 onTriggerClick : function(){
38626 if(this.menu == null){
38627 this.menu = new Roo.menu.DateMenu();
38629 Roo.apply(this.menu.picker, {
38630 showClear: this.allowBlank,
38631 minDate : this.minValue,
38632 maxDate : this.maxValue,
38633 disabledDatesRE : this.ddMatch,
38634 disabledDatesText : this.disabledDatesText,
38635 disabledDays : this.disabledDays,
38636 disabledDaysText : this.disabledDaysText,
38637 format : this.useIso ? 'Y-m-d' : this.format,
38638 minText : String.format(this.minText, this.formatDate(this.minValue)),
38639 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38641 this.menu.on(Roo.apply({}, this.menuListeners, {
38644 this.menu.picker.setValue(this.getValue() || new Date());
38645 this.menu.show(this.el, "tl-bl?");
38648 beforeBlur : function(){
38649 var v = this.parseDate(this.getRawValue());
38659 isDirty : function() {
38660 if(this.disabled) {
38664 if(typeof(this.startValue) === 'undefined'){
38668 return String(this.getValue()) !== String(this.startValue);
38673 * Ext JS Library 1.1.1
38674 * Copyright(c) 2006-2007, Ext JS, LLC.
38676 * Originally Released Under LGPL - original licence link has changed is not relivant.
38679 * <script type="text/javascript">
38683 * @class Roo.form.MonthField
38684 * @extends Roo.form.TriggerField
38685 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38687 * Create a new MonthField
38688 * @param {Object} config
38690 Roo.form.MonthField = function(config){
38692 Roo.form.MonthField.superclass.constructor.call(this, config);
38698 * Fires when a date is selected
38699 * @param {Roo.form.MonthFieeld} combo This combo box
38700 * @param {Date} date The date selected
38707 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38708 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38709 this.ddMatch = null;
38710 if(this.disabledDates){
38711 var dd = this.disabledDates;
38713 for(var i = 0; i < dd.length; i++){
38715 if(i != dd.length-1) re += "|";
38717 this.ddMatch = new RegExp(re + ")");
38721 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38723 * @cfg {String} format
38724 * The default date format string which can be overriden for localization support. The format must be
38725 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38729 * @cfg {String} altFormats
38730 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38731 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38733 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38735 * @cfg {Array} disabledDays
38736 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38738 disabledDays : [0,1,2,3,4,5,6],
38740 * @cfg {String} disabledDaysText
38741 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38743 disabledDaysText : "Disabled",
38745 * @cfg {Array} disabledDates
38746 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38747 * expression so they are very powerful. Some examples:
38749 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38750 * <li>["03/08", "09/16"] would disable those days for every year</li>
38751 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38752 * <li>["03/../2006"] would disable every day in March 2006</li>
38753 * <li>["^03"] would disable every day in every March</li>
38755 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38756 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38758 disabledDates : null,
38760 * @cfg {String} disabledDatesText
38761 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38763 disabledDatesText : "Disabled",
38765 * @cfg {Date/String} minValue
38766 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38767 * valid format (defaults to null).
38771 * @cfg {Date/String} maxValue
38772 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38773 * valid format (defaults to null).
38777 * @cfg {String} minText
38778 * The error text to display when the date in the cell is before minValue (defaults to
38779 * 'The date in this field must be after {minValue}').
38781 minText : "The date in this field must be equal to or after {0}",
38783 * @cfg {String} maxTextf
38784 * The error text to display when the date in the cell is after maxValue (defaults to
38785 * 'The date in this field must be before {maxValue}').
38787 maxText : "The date in this field must be equal to or before {0}",
38789 * @cfg {String} invalidText
38790 * The error text to display when the date in the field is invalid (defaults to
38791 * '{value} is not a valid date - it must be in the format {format}').
38793 invalidText : "{0} is not a valid date - it must be in the format {1}",
38795 * @cfg {String} triggerClass
38796 * An additional CSS class used to style the trigger button. The trigger will always get the
38797 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38798 * which displays a calendar icon).
38800 triggerClass : 'x-form-date-trigger',
38804 * @cfg {Boolean} useIso
38805 * if enabled, then the date field will use a hidden field to store the
38806 * real value as iso formated date. default (true)
38810 * @cfg {String/Object} autoCreate
38811 * A DomHelper element spec, or true for a default element spec (defaults to
38812 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38815 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38818 hiddenField: false,
38820 hideMonthPicker : false,
38822 onRender : function(ct, position)
38824 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38826 this.el.dom.removeAttribute('name');
38827 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38829 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38830 // prevent input submission
38831 this.hiddenName = this.name;
38838 validateValue : function(value)
38840 value = this.formatDate(value);
38841 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38844 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38847 var svalue = value;
38848 value = this.parseDate(value);
38850 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38853 var time = value.getTime();
38854 if(this.minValue && time < this.minValue.getTime()){
38855 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38858 if(this.maxValue && time > this.maxValue.getTime()){
38859 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38862 /*if(this.disabledDays){
38863 var day = value.getDay();
38864 for(var i = 0; i < this.disabledDays.length; i++) {
38865 if(day === this.disabledDays[i]){
38866 this.markInvalid(this.disabledDaysText);
38872 var fvalue = this.formatDate(value);
38873 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38874 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38882 // Provides logic to override the default TriggerField.validateBlur which just returns true
38883 validateBlur : function(){
38884 return !this.menu || !this.menu.isVisible();
38888 * Returns the current date value of the date field.
38889 * @return {Date} The date value
38891 getValue : function(){
38895 return this.hiddenField ?
38896 this.hiddenField.value :
38897 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38901 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38902 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38903 * (the default format used is "m/d/y").
38906 //All of these calls set the same date value (May 4, 2006)
38908 //Pass a date object:
38909 var dt = new Date('5/4/06');
38910 monthField.setValue(dt);
38912 //Pass a date string (default format):
38913 monthField.setValue('5/4/06');
38915 //Pass a date string (custom format):
38916 monthField.format = 'Y-m-d';
38917 monthField.setValue('2006-5-4');
38919 * @param {String/Date} date The date or valid date string
38921 setValue : function(date){
38922 Roo.log('month setValue' + date);
38923 // can only be first of month..
38925 var val = this.parseDate(date);
38927 if (this.hiddenField) {
38928 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38930 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38931 this.value = this.parseDate(date);
38935 parseDate : function(value){
38936 if(!value || value instanceof Date){
38937 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38940 var v = Date.parseDate(value, this.format);
38941 if (!v && this.useIso) {
38942 v = Date.parseDate(value, 'Y-m-d');
38946 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38950 if(!v && this.altFormats){
38951 if(!this.altFormatsArray){
38952 this.altFormatsArray = this.altFormats.split("|");
38954 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38955 v = Date.parseDate(value, this.altFormatsArray[i]);
38962 formatDate : function(date, fmt){
38963 return (!date || !(date instanceof Date)) ?
38964 date : date.dateFormat(fmt || this.format);
38969 select: function(m, d){
38971 this.fireEvent('select', this, d);
38973 show : function(){ // retain focus styling
38977 this.focus.defer(10, this);
38978 var ml = this.menuListeners;
38979 this.menu.un("select", ml.select, this);
38980 this.menu.un("show", ml.show, this);
38981 this.menu.un("hide", ml.hide, this);
38985 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38986 onTriggerClick : function(){
38990 if(this.menu == null){
38991 this.menu = new Roo.menu.DateMenu();
38995 Roo.apply(this.menu.picker, {
38997 showClear: this.allowBlank,
38998 minDate : this.minValue,
38999 maxDate : this.maxValue,
39000 disabledDatesRE : this.ddMatch,
39001 disabledDatesText : this.disabledDatesText,
39003 format : this.useIso ? 'Y-m-d' : this.format,
39004 minText : String.format(this.minText, this.formatDate(this.minValue)),
39005 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39008 this.menu.on(Roo.apply({}, this.menuListeners, {
39016 // hide month picker get's called when we called by 'before hide';
39018 var ignorehide = true;
39019 p.hideMonthPicker = function(disableAnim){
39023 if(this.monthPicker){
39024 Roo.log("hideMonthPicker called");
39025 if(disableAnim === true){
39026 this.monthPicker.hide();
39028 this.monthPicker.slideOut('t', {duration:.2});
39029 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39030 p.fireEvent("select", this, this.value);
39036 Roo.log('picker set value');
39037 Roo.log(this.getValue());
39038 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39039 m.show(this.el, 'tl-bl?');
39040 ignorehide = false;
39041 // this will trigger hideMonthPicker..
39044 // hidden the day picker
39045 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39051 p.showMonthPicker.defer(100, p);
39057 beforeBlur : function(){
39058 var v = this.parseDate(this.getRawValue());
39064 /** @cfg {Boolean} grow @hide */
39065 /** @cfg {Number} growMin @hide */
39066 /** @cfg {Number} growMax @hide */
39073 * Ext JS Library 1.1.1
39074 * Copyright(c) 2006-2007, Ext JS, LLC.
39076 * Originally Released Under LGPL - original licence link has changed is not relivant.
39079 * <script type="text/javascript">
39084 * @class Roo.form.ComboBox
39085 * @extends Roo.form.TriggerField
39086 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39088 * Create a new ComboBox.
39089 * @param {Object} config Configuration options
39091 Roo.form.ComboBox = function(config){
39092 Roo.form.ComboBox.superclass.constructor.call(this, config);
39096 * Fires when the dropdown list is expanded
39097 * @param {Roo.form.ComboBox} combo This combo box
39102 * Fires when the dropdown list is collapsed
39103 * @param {Roo.form.ComboBox} combo This combo box
39107 * @event beforeselect
39108 * Fires before a list item is selected. Return false to cancel the selection.
39109 * @param {Roo.form.ComboBox} combo This combo box
39110 * @param {Roo.data.Record} record The data record returned from the underlying store
39111 * @param {Number} index The index of the selected item in the dropdown list
39113 'beforeselect' : true,
39116 * Fires when a list item is selected
39117 * @param {Roo.form.ComboBox} combo This combo box
39118 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39119 * @param {Number} index The index of the selected item in the dropdown list
39123 * @event beforequery
39124 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39125 * The event object passed has these properties:
39126 * @param {Roo.form.ComboBox} combo This combo box
39127 * @param {String} query The query
39128 * @param {Boolean} forceAll true to force "all" query
39129 * @param {Boolean} cancel true to cancel the query
39130 * @param {Object} e The query event object
39132 'beforequery': true,
39135 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39136 * @param {Roo.form.ComboBox} combo This combo box
39141 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39142 * @param {Roo.form.ComboBox} combo This combo box
39143 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39149 if(this.transform){
39150 this.allowDomMove = false;
39151 var s = Roo.getDom(this.transform);
39152 if(!this.hiddenName){
39153 this.hiddenName = s.name;
39156 this.mode = 'local';
39157 var d = [], opts = s.options;
39158 for(var i = 0, len = opts.length;i < len; i++){
39160 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39162 this.value = value;
39164 d.push([value, o.text]);
39166 this.store = new Roo.data.SimpleStore({
39168 fields: ['value', 'text'],
39171 this.valueField = 'value';
39172 this.displayField = 'text';
39174 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39175 if(!this.lazyRender){
39176 this.target = true;
39177 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39178 s.parentNode.removeChild(s); // remove it
39179 this.render(this.el.parentNode);
39181 s.parentNode.removeChild(s); // remove it
39186 this.store = Roo.factory(this.store, Roo.data);
39189 this.selectedIndex = -1;
39190 if(this.mode == 'local'){
39191 if(config.queryDelay === undefined){
39192 this.queryDelay = 10;
39194 if(config.minChars === undefined){
39200 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39202 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39205 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39206 * rendering into an Roo.Editor, defaults to false)
39209 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39210 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39213 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39216 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39217 * the dropdown list (defaults to undefined, with no header element)
39221 * @cfg {String/Roo.Template} tpl The template to use to render the output
39225 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39227 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39229 listWidth: undefined,
39231 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39232 * mode = 'remote' or 'text' if mode = 'local')
39234 displayField: undefined,
39236 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39237 * mode = 'remote' or 'value' if mode = 'local').
39238 * Note: use of a valueField requires the user make a selection
39239 * in order for a value to be mapped.
39241 valueField: undefined,
39245 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39246 * field's data value (defaults to the underlying DOM element's name)
39248 hiddenName: undefined,
39250 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39254 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39256 selectedClass: 'x-combo-selected',
39258 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39259 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39260 * which displays a downward arrow icon).
39262 triggerClass : 'x-form-arrow-trigger',
39264 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39268 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39269 * anchor positions (defaults to 'tl-bl')
39271 listAlign: 'tl-bl?',
39273 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39277 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39278 * query specified by the allQuery config option (defaults to 'query')
39280 triggerAction: 'query',
39282 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39283 * (defaults to 4, does not apply if editable = false)
39287 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39288 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39292 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39293 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39297 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39298 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39302 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39303 * when editable = true (defaults to false)
39305 selectOnFocus:false,
39307 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39309 queryParam: 'query',
39311 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39312 * when mode = 'remote' (defaults to 'Loading...')
39314 loadingText: 'Loading...',
39316 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39320 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39324 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39325 * traditional select (defaults to true)
39329 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39333 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39337 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39338 * listWidth has a higher value)
39342 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39343 * allow the user to set arbitrary text into the field (defaults to false)
39345 forceSelection:false,
39347 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39348 * if typeAhead = true (defaults to 250)
39350 typeAheadDelay : 250,
39352 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39353 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39355 valueNotFoundText : undefined,
39357 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39359 blockFocus : false,
39362 * @cfg {Boolean} disableClear Disable showing of clear button.
39364 disableClear : false,
39366 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39368 alwaysQuery : false,
39374 // element that contains real text value.. (when hidden is used..)
39377 onRender : function(ct, position){
39378 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39379 if(this.hiddenName){
39380 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39382 this.hiddenField.value =
39383 this.hiddenValue !== undefined ? this.hiddenValue :
39384 this.value !== undefined ? this.value : '';
39386 // prevent input submission
39387 this.el.dom.removeAttribute('name');
39392 this.el.dom.setAttribute('autocomplete', 'off');
39395 var cls = 'x-combo-list';
39397 this.list = new Roo.Layer({
39398 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39401 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39402 this.list.setWidth(lw);
39403 this.list.swallowEvent('mousewheel');
39404 this.assetHeight = 0;
39407 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39408 this.assetHeight += this.header.getHeight();
39411 this.innerList = this.list.createChild({cls:cls+'-inner'});
39412 this.innerList.on('mouseover', this.onViewOver, this);
39413 this.innerList.on('mousemove', this.onViewMove, this);
39414 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39416 if(this.allowBlank && !this.pageSize && !this.disableClear){
39417 this.footer = this.list.createChild({cls:cls+'-ft'});
39418 this.pageTb = new Roo.Toolbar(this.footer);
39422 this.footer = this.list.createChild({cls:cls+'-ft'});
39423 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39424 {pageSize: this.pageSize});
39428 if (this.pageTb && this.allowBlank && !this.disableClear) {
39430 this.pageTb.add(new Roo.Toolbar.Fill(), {
39431 cls: 'x-btn-icon x-btn-clear',
39433 handler: function()
39436 _this.clearValue();
39437 _this.onSelect(false, -1);
39442 this.assetHeight += this.footer.getHeight();
39447 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39450 this.view = new Roo.View(this.innerList, this.tpl, {
39451 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39454 this.view.on('click', this.onViewClick, this);
39456 this.store.on('beforeload', this.onBeforeLoad, this);
39457 this.store.on('load', this.onLoad, this);
39458 this.store.on('loadexception', this.onLoadException, this);
39460 if(this.resizable){
39461 this.resizer = new Roo.Resizable(this.list, {
39462 pinned:true, handles:'se'
39464 this.resizer.on('resize', function(r, w, h){
39465 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39466 this.listWidth = w;
39467 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39468 this.restrictHeight();
39470 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39472 if(!this.editable){
39473 this.editable = true;
39474 this.setEditable(false);
39478 if (typeof(this.events.add.listeners) != 'undefined') {
39480 this.addicon = this.wrap.createChild(
39481 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39483 this.addicon.on('click', function(e) {
39484 this.fireEvent('add', this);
39487 if (typeof(this.events.edit.listeners) != 'undefined') {
39489 this.editicon = this.wrap.createChild(
39490 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39491 if (this.addicon) {
39492 this.editicon.setStyle('margin-left', '40px');
39494 this.editicon.on('click', function(e) {
39496 // we fire even if inothing is selected..
39497 this.fireEvent('edit', this, this.lastData );
39507 initEvents : function(){
39508 Roo.form.ComboBox.superclass.initEvents.call(this);
39510 this.keyNav = new Roo.KeyNav(this.el, {
39511 "up" : function(e){
39512 this.inKeyMode = true;
39516 "down" : function(e){
39517 if(!this.isExpanded()){
39518 this.onTriggerClick();
39520 this.inKeyMode = true;
39525 "enter" : function(e){
39526 this.onViewClick();
39530 "esc" : function(e){
39534 "tab" : function(e){
39535 this.onViewClick(false);
39536 this.fireEvent("specialkey", this, e);
39542 doRelay : function(foo, bar, hname){
39543 if(hname == 'down' || this.scope.isExpanded()){
39544 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39551 this.queryDelay = Math.max(this.queryDelay || 10,
39552 this.mode == 'local' ? 10 : 250);
39553 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39554 if(this.typeAhead){
39555 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39557 if(this.editable !== false){
39558 this.el.on("keyup", this.onKeyUp, this);
39560 if(this.forceSelection){
39561 this.on('blur', this.doForce, this);
39565 onDestroy : function(){
39567 this.view.setStore(null);
39568 this.view.el.removeAllListeners();
39569 this.view.el.remove();
39570 this.view.purgeListeners();
39573 this.list.destroy();
39576 this.store.un('beforeload', this.onBeforeLoad, this);
39577 this.store.un('load', this.onLoad, this);
39578 this.store.un('loadexception', this.onLoadException, this);
39580 Roo.form.ComboBox.superclass.onDestroy.call(this);
39584 fireKey : function(e){
39585 if(e.isNavKeyPress() && !this.list.isVisible()){
39586 this.fireEvent("specialkey", this, e);
39591 onResize: function(w, h){
39592 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39594 if(typeof w != 'number'){
39595 // we do not handle it!?!?
39598 var tw = this.trigger.getWidth();
39599 tw += this.addicon ? this.addicon.getWidth() : 0;
39600 tw += this.editicon ? this.editicon.getWidth() : 0;
39602 this.el.setWidth( this.adjustWidth('input', x));
39604 this.trigger.setStyle('left', x+'px');
39606 if(this.list && this.listWidth === undefined){
39607 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39608 this.list.setWidth(lw);
39609 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39617 * Allow or prevent the user from directly editing the field text. If false is passed,
39618 * the user will only be able to select from the items defined in the dropdown list. This method
39619 * is the runtime equivalent of setting the 'editable' config option at config time.
39620 * @param {Boolean} value True to allow the user to directly edit the field text
39622 setEditable : function(value){
39623 if(value == this.editable){
39626 this.editable = value;
39628 this.el.dom.setAttribute('readOnly', true);
39629 this.el.on('mousedown', this.onTriggerClick, this);
39630 this.el.addClass('x-combo-noedit');
39632 this.el.dom.setAttribute('readOnly', false);
39633 this.el.un('mousedown', this.onTriggerClick, this);
39634 this.el.removeClass('x-combo-noedit');
39639 onBeforeLoad : function(){
39640 if(!this.hasFocus){
39643 this.innerList.update(this.loadingText ?
39644 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39645 this.restrictHeight();
39646 this.selectedIndex = -1;
39650 onLoad : function(){
39651 if(!this.hasFocus){
39654 if(this.store.getCount() > 0){
39656 this.restrictHeight();
39657 if(this.lastQuery == this.allQuery){
39659 this.el.dom.select();
39661 if(!this.selectByValue(this.value, true)){
39662 this.select(0, true);
39666 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39667 this.taTask.delay(this.typeAheadDelay);
39671 this.onEmptyResults();
39676 onLoadException : function()
39679 Roo.log(this.store.reader.jsonData);
39680 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39681 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39687 onTypeAhead : function(){
39688 if(this.store.getCount() > 0){
39689 var r = this.store.getAt(0);
39690 var newValue = r.data[this.displayField];
39691 var len = newValue.length;
39692 var selStart = this.getRawValue().length;
39693 if(selStart != len){
39694 this.setRawValue(newValue);
39695 this.selectText(selStart, newValue.length);
39701 onSelect : function(record, index){
39702 if(this.fireEvent('beforeselect', this, record, index) !== false){
39703 this.setFromData(index > -1 ? record.data : false);
39705 this.fireEvent('select', this, record, index);
39710 * Returns the currently selected field value or empty string if no value is set.
39711 * @return {String} value The selected value
39713 getValue : function(){
39714 if(this.valueField){
39715 return typeof this.value != 'undefined' ? this.value : '';
39717 return Roo.form.ComboBox.superclass.getValue.call(this);
39722 * Clears any text/value currently set in the field
39724 clearValue : function(){
39725 if(this.hiddenField){
39726 this.hiddenField.value = '';
39729 this.setRawValue('');
39730 this.lastSelectionText = '';
39735 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39736 * will be displayed in the field. If the value does not match the data value of an existing item,
39737 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39738 * Otherwise the field will be blank (although the value will still be set).
39739 * @param {String} value The value to match
39741 setValue : function(v){
39743 if(this.valueField){
39744 var r = this.findRecord(this.valueField, v);
39746 text = r.data[this.displayField];
39747 }else if(this.valueNotFoundText !== undefined){
39748 text = this.valueNotFoundText;
39751 this.lastSelectionText = text;
39752 if(this.hiddenField){
39753 this.hiddenField.value = v;
39755 Roo.form.ComboBox.superclass.setValue.call(this, text);
39759 * @property {Object} the last set data for the element
39764 * Sets the value of the field based on a object which is related to the record format for the store.
39765 * @param {Object} value the value to set as. or false on reset?
39767 setFromData : function(o){
39768 var dv = ''; // display value
39769 var vv = ''; // value value..
39771 if (this.displayField) {
39772 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39774 // this is an error condition!!!
39775 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39778 if(this.valueField){
39779 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39781 if(this.hiddenField){
39782 this.hiddenField.value = vv;
39784 this.lastSelectionText = dv;
39785 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39789 // no hidden field.. - we store the value in 'value', but still display
39790 // display field!!!!
39791 this.lastSelectionText = dv;
39792 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39798 reset : function(){
39799 // overridden so that last data is reset..
39800 this.setValue(this.resetValue);
39801 this.clearInvalid();
39802 this.lastData = false;
39804 this.view.clearSelections();
39808 findRecord : function(prop, value){
39810 if(this.store.getCount() > 0){
39811 this.store.each(function(r){
39812 if(r.data[prop] == value){
39822 getName: function()
39824 // returns hidden if it's set..
39825 if (!this.rendered) {return ''};
39826 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39830 onViewMove : function(e, t){
39831 this.inKeyMode = false;
39835 onViewOver : function(e, t){
39836 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39839 var item = this.view.findItemFromChild(t);
39841 var index = this.view.indexOf(item);
39842 this.select(index, false);
39847 onViewClick : function(doFocus)
39849 var index = this.view.getSelectedIndexes()[0];
39850 var r = this.store.getAt(index);
39852 this.onSelect(r, index);
39854 if(doFocus !== false && !this.blockFocus){
39860 restrictHeight : function(){
39861 this.innerList.dom.style.height = '';
39862 var inner = this.innerList.dom;
39863 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39864 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39865 this.list.beginUpdate();
39866 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39867 this.list.alignTo(this.el, this.listAlign);
39868 this.list.endUpdate();
39872 onEmptyResults : function(){
39877 * Returns true if the dropdown list is expanded, else false.
39879 isExpanded : function(){
39880 return this.list.isVisible();
39884 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39885 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39886 * @param {String} value The data value of the item to select
39887 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39888 * selected item if it is not currently in view (defaults to true)
39889 * @return {Boolean} True if the value matched an item in the list, else false
39891 selectByValue : function(v, scrollIntoView){
39892 if(v !== undefined && v !== null){
39893 var r = this.findRecord(this.valueField || this.displayField, v);
39895 this.select(this.store.indexOf(r), scrollIntoView);
39903 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39904 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39905 * @param {Number} index The zero-based index of the list item to select
39906 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39907 * selected item if it is not currently in view (defaults to true)
39909 select : function(index, scrollIntoView){
39910 this.selectedIndex = index;
39911 this.view.select(index);
39912 if(scrollIntoView !== false){
39913 var el = this.view.getNode(index);
39915 this.innerList.scrollChildIntoView(el, false);
39921 selectNext : function(){
39922 var ct = this.store.getCount();
39924 if(this.selectedIndex == -1){
39926 }else if(this.selectedIndex < ct-1){
39927 this.select(this.selectedIndex+1);
39933 selectPrev : function(){
39934 var ct = this.store.getCount();
39936 if(this.selectedIndex == -1){
39938 }else if(this.selectedIndex != 0){
39939 this.select(this.selectedIndex-1);
39945 onKeyUp : function(e){
39946 if(this.editable !== false && !e.isSpecialKey()){
39947 this.lastKey = e.getKey();
39948 this.dqTask.delay(this.queryDelay);
39953 validateBlur : function(){
39954 return !this.list || !this.list.isVisible();
39958 initQuery : function(){
39959 this.doQuery(this.getRawValue());
39963 doForce : function(){
39964 if(this.el.dom.value.length > 0){
39965 this.el.dom.value =
39966 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39972 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39973 * query allowing the query action to be canceled if needed.
39974 * @param {String} query The SQL query to execute
39975 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39976 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39977 * saved in the current store (defaults to false)
39979 doQuery : function(q, forceAll){
39980 if(q === undefined || q === null){
39985 forceAll: forceAll,
39989 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39993 forceAll = qe.forceAll;
39994 if(forceAll === true || (q.length >= this.minChars)){
39995 if(this.lastQuery != q || this.alwaysQuery){
39996 this.lastQuery = q;
39997 if(this.mode == 'local'){
39998 this.selectedIndex = -1;
40000 this.store.clearFilter();
40002 this.store.filter(this.displayField, q);
40006 this.store.baseParams[this.queryParam] = q;
40008 params: this.getParams(q)
40013 this.selectedIndex = -1;
40020 getParams : function(q){
40022 //p[this.queryParam] = q;
40025 p.limit = this.pageSize;
40031 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40033 collapse : function(){
40034 if(!this.isExpanded()){
40038 Roo.get(document).un('mousedown', this.collapseIf, this);
40039 Roo.get(document).un('mousewheel', this.collapseIf, this);
40040 if (!this.editable) {
40041 Roo.get(document).un('keydown', this.listKeyPress, this);
40043 this.fireEvent('collapse', this);
40047 collapseIf : function(e){
40048 if(!e.within(this.wrap) && !e.within(this.list)){
40054 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40056 expand : function(){
40057 if(this.isExpanded() || !this.hasFocus){
40060 this.list.alignTo(this.el, this.listAlign);
40062 Roo.get(document).on('mousedown', this.collapseIf, this);
40063 Roo.get(document).on('mousewheel', this.collapseIf, this);
40064 if (!this.editable) {
40065 Roo.get(document).on('keydown', this.listKeyPress, this);
40068 this.fireEvent('expand', this);
40072 // Implements the default empty TriggerField.onTriggerClick function
40073 onTriggerClick : function(){
40077 if(this.isExpanded()){
40079 if (!this.blockFocus) {
40084 this.hasFocus = true;
40085 if(this.triggerAction == 'all') {
40086 this.doQuery(this.allQuery, true);
40088 this.doQuery(this.getRawValue());
40090 if (!this.blockFocus) {
40095 listKeyPress : function(e)
40097 //Roo.log('listkeypress');
40098 // scroll to first matching element based on key pres..
40099 if (e.isSpecialKey()) {
40102 var k = String.fromCharCode(e.getKey()).toUpperCase();
40105 var csel = this.view.getSelectedNodes();
40106 var cselitem = false;
40108 var ix = this.view.indexOf(csel[0]);
40109 cselitem = this.store.getAt(ix);
40110 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40116 this.store.each(function(v) {
40118 // start at existing selection.
40119 if (cselitem.id == v.id) {
40125 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40126 match = this.store.indexOf(v);
40131 if (match === false) {
40132 return true; // no more action?
40135 this.view.select(match);
40136 var sn = Roo.get(this.view.getSelectedNodes()[0])
40137 sn.scrollIntoView(sn.dom.parentNode, false);
40141 * @cfg {Boolean} grow
40145 * @cfg {Number} growMin
40149 * @cfg {Number} growMax
40157 * Copyright(c) 2010-2012, Roo J Solutions Limited
40164 * @class Roo.form.ComboBoxArray
40165 * @extends Roo.form.TextField
40166 * A facebook style adder... for lists of email / people / countries etc...
40167 * pick multiple items from a combo box, and shows each one.
40169 * Fred [x] Brian [x] [Pick another |v]
40172 * For this to work: it needs various extra information
40173 * - normal combo problay has
40175 * + displayField, valueField
40177 * For our purpose...
40180 * If we change from 'extends' to wrapping...
40187 * Create a new ComboBoxArray.
40188 * @param {Object} config Configuration options
40192 Roo.form.ComboBoxArray = function(config)
40197 * Fires when remove the value from the list
40198 * @param {Roo.form.ComboBoxArray} _self This combo box array
40199 * @param {Roo.form.ComboBoxArray.Item} item removed item
40206 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40208 this.items = new Roo.util.MixedCollection(false);
40210 // construct the child combo...
40220 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40223 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40228 // behavies liek a hiddne field
40229 inputType: 'hidden',
40231 * @cfg {Number} width The width of the box that displays the selected element
40238 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40242 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40244 hiddenName : false,
40247 // private the array of items that are displayed..
40249 // private - the hidden field el.
40251 // private - the filed el..
40254 //validateValue : function() { return true; }, // all values are ok!
40255 //onAddClick: function() { },
40257 onRender : function(ct, position)
40260 // create the standard hidden element
40261 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40264 // give fake names to child combo;
40265 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40266 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40268 this.combo = Roo.factory(this.combo, Roo.form);
40269 this.combo.onRender(ct, position);
40270 if (typeof(this.combo.width) != 'undefined') {
40271 this.combo.onResize(this.combo.width,0);
40274 this.combo.initEvents();
40276 // assigned so form know we need to do this..
40277 this.store = this.combo.store;
40278 this.valueField = this.combo.valueField;
40279 this.displayField = this.combo.displayField ;
40282 this.combo.wrap.addClass('x-cbarray-grp');
40284 var cbwrap = this.combo.wrap.createChild(
40285 {tag: 'div', cls: 'x-cbarray-cb'},
40290 this.hiddenEl = this.combo.wrap.createChild({
40291 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40293 this.el = this.combo.wrap.createChild({
40294 tag: 'input', type:'hidden' , name: this.name, value : ''
40296 // this.el.dom.removeAttribute("name");
40299 this.outerWrap = this.combo.wrap;
40300 this.wrap = cbwrap;
40302 this.outerWrap.setWidth(this.width);
40303 this.outerWrap.dom.removeChild(this.el.dom);
40305 this.wrap.dom.appendChild(this.el.dom);
40306 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40307 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40309 this.combo.trigger.setStyle('position','relative');
40310 this.combo.trigger.setStyle('left', '0px');
40311 this.combo.trigger.setStyle('top', '2px');
40313 this.combo.el.setStyle('vertical-align', 'text-bottom');
40315 //this.trigger.setStyle('vertical-align', 'top');
40317 // this should use the code from combo really... on('add' ....)
40321 this.adder = this.outerWrap.createChild(
40322 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40324 this.adder.on('click', function(e) {
40325 _t.fireEvent('adderclick', this, e);
40329 //this.adder.on('click', this.onAddClick, _t);
40332 this.combo.on('select', function(cb, rec, ix) {
40333 this.addItem(rec.data);
40336 cb.el.dom.value = '';
40337 //cb.lastData = rec.data;
40346 getName: function()
40348 // returns hidden if it's set..
40349 if (!this.rendered) {return ''};
40350 return this.hiddenName ? this.hiddenName : this.name;
40355 onResize: function(w, h){
40358 // not sure if this is needed..
40359 //this.combo.onResize(w,h);
40361 if(typeof w != 'number'){
40362 // we do not handle it!?!?
40365 var tw = this.combo.trigger.getWidth();
40366 tw += this.addicon ? this.addicon.getWidth() : 0;
40367 tw += this.editicon ? this.editicon.getWidth() : 0;
40369 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40371 this.combo.trigger.setStyle('left', '0px');
40373 if(this.list && this.listWidth === undefined){
40374 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40375 this.list.setWidth(lw);
40376 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40383 addItem: function(rec)
40385 var valueField = this.combo.valueField;
40386 var displayField = this.combo.displayField;
40387 if (this.items.indexOfKey(rec[valueField]) > -1) {
40388 //console.log("GOT " + rec.data.id);
40392 var x = new Roo.form.ComboBoxArray.Item({
40393 //id : rec[this.idField],
40395 displayField : displayField ,
40396 tipField : displayField ,
40400 this.items.add(rec[valueField],x);
40401 // add it before the element..
40402 this.updateHiddenEl();
40403 x.render(this.outerWrap, this.wrap.dom);
40404 // add the image handler..
40407 updateHiddenEl : function()
40410 if (!this.hiddenEl) {
40414 var idField = this.combo.valueField;
40416 this.items.each(function(f) {
40417 ar.push(f.data[idField]);
40420 this.hiddenEl.dom.value = ar.join(',');
40426 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40427 this.items.each(function(f) {
40430 this.el.dom.value = '';
40431 if (this.hiddenEl) {
40432 this.hiddenEl.dom.value = '';
40436 getValue: function()
40438 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40440 setValue: function(v) // not a valid action - must use addItems..
40447 if (this.store.isLocal && (typeof(v) == 'string')) {
40448 // then we can use the store to find the values..
40449 // comma seperated at present.. this needs to allow JSON based encoding..
40450 this.hiddenEl.value = v;
40452 Roo.each(v.split(','), function(k) {
40453 Roo.log("CHECK " + this.valueField + ',' + k);
40454 var li = this.store.query(this.valueField, k);
40459 add[this.valueField] = k;
40460 add[this.displayField] = li.item(0).data[this.displayField];
40466 if (typeof(v) == 'object') {
40467 // then let's assume it's an array of objects..
40468 Roo.each(v, function(l) {
40476 setFromData: function(v)
40478 // this recieves an object, if setValues is called.
40480 this.el.dom.value = v[this.displayField];
40481 this.hiddenEl.dom.value = v[this.valueField];
40482 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40485 var kv = v[this.valueField];
40486 var dv = v[this.displayField];
40487 kv = typeof(kv) != 'string' ? '' : kv;
40488 dv = typeof(dv) != 'string' ? '' : dv;
40491 var keys = kv.split(',');
40492 var display = dv.split(',');
40493 for (var i = 0 ; i < keys.length; i++) {
40496 add[this.valueField] = keys[i];
40497 add[this.displayField] = display[i];
40505 * Validates the combox array value
40506 * @return {Boolean} True if the value is valid, else false
40508 validate : function(){
40509 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40510 this.clearInvalid();
40516 validateValue : function(value){
40517 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40525 isDirty : function() {
40526 if(this.disabled) {
40531 var d = Roo.decode(String(this.originalValue));
40533 return String(this.getValue()) !== String(this.originalValue);
40536 var originalValue = [];
40538 for (var i = 0; i < d.length; i++){
40539 originalValue.push(d[i][this.valueField]);
40542 return String(this.getValue()) !== String(originalValue.join(','));
40551 * @class Roo.form.ComboBoxArray.Item
40552 * @extends Roo.BoxComponent
40553 * A selected item in the list
40554 * Fred [x] Brian [x] [Pick another |v]
40557 * Create a new item.
40558 * @param {Object} config Configuration options
40561 Roo.form.ComboBoxArray.Item = function(config) {
40562 config.id = Roo.id();
40563 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40566 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40569 displayField : false,
40573 defaultAutoCreate : {
40575 cls: 'x-cbarray-item',
40582 src : Roo.BLANK_IMAGE_URL ,
40590 onRender : function(ct, position)
40592 Roo.form.Field.superclass.onRender.call(this, ct, position);
40595 var cfg = this.getAutoCreate();
40596 this.el = ct.createChild(cfg, position);
40599 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40601 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40602 this.cb.renderer(this.data) :
40603 String.format('{0}',this.data[this.displayField]);
40606 this.el.child('div').dom.setAttribute('qtip',
40607 String.format('{0}',this.data[this.tipField])
40610 this.el.child('img').on('click', this.remove, this);
40614 remove : function()
40616 this.cb.items.remove(this);
40617 this.el.child('img').un('click', this.remove, this);
40619 this.cb.updateHiddenEl();
40621 this.cb.fireEvent('remove', this.cb, this);
40625 * Ext JS Library 1.1.1
40626 * Copyright(c) 2006-2007, Ext JS, LLC.
40628 * Originally Released Under LGPL - original licence link has changed is not relivant.
40631 * <script type="text/javascript">
40634 * @class Roo.form.Checkbox
40635 * @extends Roo.form.Field
40636 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40638 * Creates a new Checkbox
40639 * @param {Object} config Configuration options
40641 Roo.form.Checkbox = function(config){
40642 Roo.form.Checkbox.superclass.constructor.call(this, config);
40646 * Fires when the checkbox is checked or unchecked.
40647 * @param {Roo.form.Checkbox} this This checkbox
40648 * @param {Boolean} checked The new checked value
40654 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40656 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40658 focusClass : undefined,
40660 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40662 fieldClass: "x-form-field",
40664 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40668 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40669 * {tag: "input", type: "checkbox", autocomplete: "off"})
40671 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40673 * @cfg {String} boxLabel The text that appears beside the checkbox
40677 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40681 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40683 valueOff: '0', // value when not checked..
40685 actionMode : 'viewEl',
40688 itemCls : 'x-menu-check-item x-form-item',
40689 groupClass : 'x-menu-group-item',
40690 inputType : 'hidden',
40693 inSetChecked: false, // check that we are not calling self...
40695 inputElement: false, // real input element?
40696 basedOn: false, // ????
40698 isFormField: true, // not sure where this is needed!!!!
40700 onResize : function(){
40701 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40702 if(!this.boxLabel){
40703 this.el.alignTo(this.wrap, 'c-c');
40707 initEvents : function(){
40708 Roo.form.Checkbox.superclass.initEvents.call(this);
40709 this.el.on("click", this.onClick, this);
40710 this.el.on("change", this.onClick, this);
40714 getResizeEl : function(){
40718 getPositionEl : function(){
40723 onRender : function(ct, position){
40724 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40726 if(this.inputValue !== undefined){
40727 this.el.dom.value = this.inputValue;
40730 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40731 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40732 var viewEl = this.wrap.createChild({
40733 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40734 this.viewEl = viewEl;
40735 this.wrap.on('click', this.onClick, this);
40737 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40738 this.el.on('propertychange', this.setFromHidden, this); //ie
40743 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40744 // viewEl.on('click', this.onClick, this);
40746 //if(this.checked){
40747 this.setChecked(this.checked);
40749 //this.checked = this.el.dom;
40755 initValue : Roo.emptyFn,
40758 * Returns the checked state of the checkbox.
40759 * @return {Boolean} True if checked, else false
40761 getValue : function(){
40763 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40765 return this.valueOff;
40770 onClick : function(){
40771 this.setChecked(!this.checked);
40773 //if(this.el.dom.checked != this.checked){
40774 // this.setValue(this.el.dom.checked);
40779 * Sets the checked state of the checkbox.
40780 * On is always based on a string comparison between inputValue and the param.
40781 * @param {Boolean/String} value - the value to set
40782 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40784 setValue : function(v,suppressEvent){
40787 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40788 //if(this.el && this.el.dom){
40789 // this.el.dom.checked = this.checked;
40790 // this.el.dom.defaultChecked = this.checked;
40792 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40793 //this.fireEvent("check", this, this.checked);
40796 setChecked : function(state,suppressEvent)
40798 if (this.inSetChecked) {
40799 this.checked = state;
40805 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40807 this.checked = state;
40808 if(suppressEvent !== true){
40809 this.fireEvent('check', this, state);
40811 this.inSetChecked = true;
40812 this.el.dom.value = state ? this.inputValue : this.valueOff;
40813 this.inSetChecked = false;
40816 // handle setting of hidden value by some other method!!?!?
40817 setFromHidden: function()
40822 //console.log("SET FROM HIDDEN");
40823 //alert('setFrom hidden');
40824 this.setValue(this.el.dom.value);
40827 onDestroy : function()
40830 Roo.get(this.viewEl).remove();
40833 Roo.form.Checkbox.superclass.onDestroy.call(this);
40838 * Ext JS Library 1.1.1
40839 * Copyright(c) 2006-2007, Ext JS, LLC.
40841 * Originally Released Under LGPL - original licence link has changed is not relivant.
40844 * <script type="text/javascript">
40848 * @class Roo.form.Radio
40849 * @extends Roo.form.Checkbox
40850 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40851 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40853 * Creates a new Radio
40854 * @param {Object} config Configuration options
40856 Roo.form.Radio = function(){
40857 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40859 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40860 inputType: 'radio',
40863 * If this radio is part of a group, it will return the selected value
40866 getGroupValue : function(){
40867 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40871 onRender : function(ct, position){
40872 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40874 if(this.inputValue !== undefined){
40875 this.el.dom.value = this.inputValue;
40878 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40879 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40880 //var viewEl = this.wrap.createChild({
40881 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40882 //this.viewEl = viewEl;
40883 //this.wrap.on('click', this.onClick, this);
40885 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40886 //this.el.on('propertychange', this.setFromHidden, this); //ie
40891 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40892 // viewEl.on('click', this.onClick, this);
40895 this.el.dom.checked = 'checked' ;
40901 });//<script type="text/javascript">
40904 * Based Ext JS Library 1.1.1
40905 * Copyright(c) 2006-2007, Ext JS, LLC.
40911 * @class Roo.HtmlEditorCore
40912 * @extends Roo.Component
40913 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40915 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40918 Roo.HtmlEditorCore = function(config){
40921 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40924 * @event initialize
40925 * Fires when the editor is fully initialized (including the iframe)
40926 * @param {Roo.HtmlEditorCore} this
40931 * Fires when the editor is first receives the focus. Any insertion must wait
40932 * until after this event.
40933 * @param {Roo.HtmlEditorCore} this
40937 * @event beforesync
40938 * Fires before the textarea is updated with content from the editor iframe. Return false
40939 * to cancel the sync.
40940 * @param {Roo.HtmlEditorCore} this
40941 * @param {String} html
40945 * @event beforepush
40946 * Fires before the iframe editor is updated with content from the textarea. Return false
40947 * to cancel the push.
40948 * @param {Roo.HtmlEditorCore} this
40949 * @param {String} html
40954 * Fires when the textarea is updated with content from the editor iframe.
40955 * @param {Roo.HtmlEditorCore} this
40956 * @param {String} html
40961 * Fires when the iframe editor is updated with content from the textarea.
40962 * @param {Roo.HtmlEditorCore} this
40963 * @param {String} html
40968 * @event editorevent
40969 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40970 * @param {Roo.HtmlEditorCore} this
40978 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
40982 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
40988 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40993 * @cfg {Number} height (in pixels)
40997 * @cfg {Number} width (in pixels)
41002 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41005 stylesheets: false,
41010 // private properties
41011 validationEvent : false,
41013 initialized : false,
41015 sourceEditMode : false,
41016 onFocus : Roo.emptyFn,
41018 hideMode:'offsets',
41026 * Protected method that will not generally be called directly. It
41027 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41028 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41030 getDocMarkup : function(){
41033 Roo.log(this.stylesheets);
41035 // inherit styels from page...??
41036 if (this.stylesheets === false) {
41038 Roo.get(document.head).select('style').each(function(node) {
41039 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41042 Roo.get(document.head).select('link').each(function(node) {
41043 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41046 } else if (!this.stylesheets.length) {
41048 st = '<style type="text/css">' +
41049 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41052 Roo.each(this.stylesheets, function(s) {
41053 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41058 st += '<style type="text/css">' +
41059 'IMG { cursor: pointer } ' +
41063 return '<html><head>' + st +
41064 //<style type="text/css">' +
41065 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41067 ' </head><body class="roo-htmleditor-body"></body></html>';
41071 onRender : function(ct, position)
41074 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41075 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41078 this.el.dom.style.border = '0 none';
41079 this.el.dom.setAttribute('tabIndex', -1);
41080 this.el.addClass('x-hidden hide');
41084 if(Roo.isIE){ // fix IE 1px bogus margin
41085 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41089 this.frameId = Roo.id();
41093 var iframe = this.owner.wrap.createChild({
41095 cls: 'form-control', // bootstrap..
41097 name: this.frameId,
41098 frameBorder : 'no',
41099 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41104 this.iframe = iframe.dom;
41106 this.assignDocWin();
41108 this.doc.designMode = 'on';
41111 this.doc.write(this.getDocMarkup());
41115 var task = { // must defer to wait for browser to be ready
41117 //console.log("run task?" + this.doc.readyState);
41118 this.assignDocWin();
41119 if(this.doc.body || this.doc.readyState == 'complete'){
41121 this.doc.designMode="on";
41125 Roo.TaskMgr.stop(task);
41126 this.initEditor.defer(10, this);
41133 Roo.TaskMgr.start(task);
41140 onResize : function(w, h)
41142 Roo.log('resize: ' +w + ',' + h );
41143 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41147 if(typeof w == 'number'){
41149 this.iframe.style.width = w + 'px';
41151 if(typeof h == 'number'){
41153 this.iframe.style.height = h + 'px';
41155 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41162 * Toggles the editor between standard and source edit mode.
41163 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41165 toggleSourceEdit : function(sourceEditMode){
41167 this.sourceEditMode = sourceEditMode === true;
41169 if(this.sourceEditMode){
41171 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41174 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41175 //this.iframe.className = '';
41178 //this.setSize(this.owner.wrap.getSize());
41179 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41186 * Protected method that will not generally be called directly. If you need/want
41187 * custom HTML cleanup, this is the method you should override.
41188 * @param {String} html The HTML to be cleaned
41189 * return {String} The cleaned HTML
41191 cleanHtml : function(html){
41192 html = String(html);
41193 if(html.length > 5){
41194 if(Roo.isSafari){ // strip safari nonsense
41195 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41198 if(html == ' '){
41205 * HTML Editor -> Textarea
41206 * Protected method that will not generally be called directly. Syncs the contents
41207 * of the editor iframe with the textarea.
41209 syncValue : function(){
41210 if(this.initialized){
41211 var bd = (this.doc.body || this.doc.documentElement);
41212 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41213 var html = bd.innerHTML;
41215 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41216 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41218 html = '<div style="'+m[0]+'">' + html + '</div>';
41221 html = this.cleanHtml(html);
41222 // fix up the special chars.. normaly like back quotes in word...
41223 // however we do not want to do this with chinese..
41224 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41225 var cc = b.charCodeAt();
41227 (cc >= 0x4E00 && cc < 0xA000 ) ||
41228 (cc >= 0x3400 && cc < 0x4E00 ) ||
41229 (cc >= 0xf900 && cc < 0xfb00 )
41235 if(this.owner.fireEvent('beforesync', this, html) !== false){
41236 this.el.dom.value = html;
41237 this.owner.fireEvent('sync', this, html);
41243 * Protected method that will not generally be called directly. Pushes the value of the textarea
41244 * into the iframe editor.
41246 pushValue : function(){
41247 if(this.initialized){
41248 var v = this.el.dom.value.trim();
41250 // if(v.length < 1){
41254 if(this.owner.fireEvent('beforepush', this, v) !== false){
41255 var d = (this.doc.body || this.doc.documentElement);
41257 this.cleanUpPaste();
41258 this.el.dom.value = d.innerHTML;
41259 this.owner.fireEvent('push', this, v);
41265 deferFocus : function(){
41266 this.focus.defer(10, this);
41270 focus : function(){
41271 if(this.win && !this.sourceEditMode){
41278 assignDocWin: function()
41280 var iframe = this.iframe;
41283 this.doc = iframe.contentWindow.document;
41284 this.win = iframe.contentWindow;
41286 if (!Roo.get(this.frameId)) {
41289 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41290 this.win = Roo.get(this.frameId).dom.contentWindow;
41295 initEditor : function(){
41296 //console.log("INIT EDITOR");
41297 this.assignDocWin();
41301 this.doc.designMode="on";
41303 this.doc.write(this.getDocMarkup());
41306 var dbody = (this.doc.body || this.doc.documentElement);
41307 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41308 // this copies styles from the containing element into thsi one..
41309 // not sure why we need all of this..
41310 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41311 ss['background-attachment'] = 'fixed'; // w3c
41312 dbody.bgProperties = 'fixed'; // ie
41313 Roo.DomHelper.applyStyles(dbody, ss);
41314 Roo.EventManager.on(this.doc, {
41315 //'mousedown': this.onEditorEvent,
41316 'mouseup': this.onEditorEvent,
41317 'dblclick': this.onEditorEvent,
41318 'click': this.onEditorEvent,
41319 'keyup': this.onEditorEvent,
41324 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41326 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41327 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41329 this.initialized = true;
41331 this.owner.fireEvent('initialize', this);
41336 onDestroy : function(){
41342 //for (var i =0; i < this.toolbars.length;i++) {
41343 // // fixme - ask toolbars for heights?
41344 // this.toolbars[i].onDestroy();
41347 //this.wrap.dom.innerHTML = '';
41348 //this.wrap.remove();
41353 onFirstFocus : function(){
41355 this.assignDocWin();
41358 this.activated = true;
41361 if(Roo.isGecko){ // prevent silly gecko errors
41363 var s = this.win.getSelection();
41364 if(!s.focusNode || s.focusNode.nodeType != 3){
41365 var r = s.getRangeAt(0);
41366 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41371 this.execCmd('useCSS', true);
41372 this.execCmd('styleWithCSS', false);
41375 this.owner.fireEvent('activate', this);
41379 adjustFont: function(btn){
41380 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41381 //if(Roo.isSafari){ // safari
41384 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41385 if(Roo.isSafari){ // safari
41386 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41387 v = (v < 10) ? 10 : v;
41388 v = (v > 48) ? 48 : v;
41389 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41394 v = Math.max(1, v+adjust);
41396 this.execCmd('FontSize', v );
41399 onEditorEvent : function(e){
41400 this.owner.fireEvent('editorevent', this, e);
41401 // this.updateToolbar();
41402 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41405 insertTag : function(tg)
41407 // could be a bit smarter... -> wrap the current selected tRoo..
41408 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41410 range = this.createRange(this.getSelection());
41411 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41412 wrappingNode.appendChild(range.extractContents());
41413 range.insertNode(wrappingNode);
41420 this.execCmd("formatblock", tg);
41424 insertText : function(txt)
41428 var range = this.createRange();
41429 range.deleteContents();
41430 //alert(Sender.getAttribute('label'));
41432 range.insertNode(this.doc.createTextNode(txt));
41438 * Executes a Midas editor command on the editor document and performs necessary focus and
41439 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41440 * @param {String} cmd The Midas command
41441 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41443 relayCmd : function(cmd, value){
41445 this.execCmd(cmd, value);
41446 this.owner.fireEvent('editorevent', this);
41447 //this.updateToolbar();
41448 this.owner.deferFocus();
41452 * Executes a Midas editor command directly on the editor document.
41453 * For visual commands, you should use {@link #relayCmd} instead.
41454 * <b>This should only be called after the editor is initialized.</b>
41455 * @param {String} cmd The Midas command
41456 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41458 execCmd : function(cmd, value){
41459 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41466 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41468 * @param {String} text | dom node..
41470 insertAtCursor : function(text)
41475 if(!this.activated){
41481 var r = this.doc.selection.createRange();
41492 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41496 // from jquery ui (MIT licenced)
41498 var win = this.win;
41500 if (win.getSelection && win.getSelection().getRangeAt) {
41501 range = win.getSelection().getRangeAt(0);
41502 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41503 range.insertNode(node);
41504 } else if (win.document.selection && win.document.selection.createRange) {
41505 // no firefox support
41506 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41507 win.document.selection.createRange().pasteHTML(txt);
41509 // no firefox support
41510 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41511 this.execCmd('InsertHTML', txt);
41520 mozKeyPress : function(e){
41522 var c = e.getCharCode(), cmd;
41525 c = String.fromCharCode(c).toLowerCase();
41539 this.cleanUpPaste.defer(100, this);
41547 e.preventDefault();
41555 fixKeys : function(){ // load time branching for fastest keydown performance
41557 return function(e){
41558 var k = e.getKey(), r;
41561 r = this.doc.selection.createRange();
41564 r.pasteHTML('    ');
41571 r = this.doc.selection.createRange();
41573 var target = r.parentElement();
41574 if(!target || target.tagName.toLowerCase() != 'li'){
41576 r.pasteHTML('<br />');
41582 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41583 this.cleanUpPaste.defer(100, this);
41589 }else if(Roo.isOpera){
41590 return function(e){
41591 var k = e.getKey();
41595 this.execCmd('InsertHTML','    ');
41598 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41599 this.cleanUpPaste.defer(100, this);
41604 }else if(Roo.isSafari){
41605 return function(e){
41606 var k = e.getKey();
41610 this.execCmd('InsertText','\t');
41614 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41615 this.cleanUpPaste.defer(100, this);
41623 getAllAncestors: function()
41625 var p = this.getSelectedNode();
41628 a.push(p); // push blank onto stack..
41629 p = this.getParentElement();
41633 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41637 a.push(this.doc.body);
41641 lastSelNode : false,
41644 getSelection : function()
41646 this.assignDocWin();
41647 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41650 getSelectedNode: function()
41652 // this may only work on Gecko!!!
41654 // should we cache this!!!!
41659 var range = this.createRange(this.getSelection()).cloneRange();
41662 var parent = range.parentElement();
41664 var testRange = range.duplicate();
41665 testRange.moveToElementText(parent);
41666 if (testRange.inRange(range)) {
41669 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41672 parent = parent.parentElement;
41677 // is ancestor a text element.
41678 var ac = range.commonAncestorContainer;
41679 if (ac.nodeType == 3) {
41680 ac = ac.parentNode;
41683 var ar = ac.childNodes;
41686 var other_nodes = [];
41687 var has_other_nodes = false;
41688 for (var i=0;i<ar.length;i++) {
41689 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41692 // fullly contained node.
41694 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41699 // probably selected..
41700 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41701 other_nodes.push(ar[i]);
41705 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41710 has_other_nodes = true;
41712 if (!nodes.length && other_nodes.length) {
41713 nodes= other_nodes;
41715 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41721 createRange: function(sel)
41723 // this has strange effects when using with
41724 // top toolbar - not sure if it's a great idea.
41725 //this.editor.contentWindow.focus();
41726 if (typeof sel != "undefined") {
41728 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41730 return this.doc.createRange();
41733 return this.doc.createRange();
41736 getParentElement: function()
41739 this.assignDocWin();
41740 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41742 var range = this.createRange(sel);
41745 var p = range.commonAncestorContainer;
41746 while (p.nodeType == 3) { // text node
41757 * Range intersection.. the hard stuff...
41761 * [ -- selected range --- ]
41765 * if end is before start or hits it. fail.
41766 * if start is after end or hits it fail.
41768 * if either hits (but other is outside. - then it's not
41774 // @see http://www.thismuchiknow.co.uk/?p=64.
41775 rangeIntersectsNode : function(range, node)
41777 var nodeRange = node.ownerDocument.createRange();
41779 nodeRange.selectNode(node);
41781 nodeRange.selectNodeContents(node);
41784 var rangeStartRange = range.cloneRange();
41785 rangeStartRange.collapse(true);
41787 var rangeEndRange = range.cloneRange();
41788 rangeEndRange.collapse(false);
41790 var nodeStartRange = nodeRange.cloneRange();
41791 nodeStartRange.collapse(true);
41793 var nodeEndRange = nodeRange.cloneRange();
41794 nodeEndRange.collapse(false);
41796 return rangeStartRange.compareBoundaryPoints(
41797 Range.START_TO_START, nodeEndRange) == -1 &&
41798 rangeEndRange.compareBoundaryPoints(
41799 Range.START_TO_START, nodeStartRange) == 1;
41803 rangeCompareNode : function(range, node)
41805 var nodeRange = node.ownerDocument.createRange();
41807 nodeRange.selectNode(node);
41809 nodeRange.selectNodeContents(node);
41813 range.collapse(true);
41815 nodeRange.collapse(true);
41817 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41818 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41820 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41822 var nodeIsBefore = ss == 1;
41823 var nodeIsAfter = ee == -1;
41825 if (nodeIsBefore && nodeIsAfter)
41827 if (!nodeIsBefore && nodeIsAfter)
41828 return 1; //right trailed.
41830 if (nodeIsBefore && !nodeIsAfter)
41831 return 2; // left trailed.
41836 // private? - in a new class?
41837 cleanUpPaste : function()
41839 // cleans up the whole document..
41840 Roo.log('cleanuppaste');
41842 this.cleanUpChildren(this.doc.body);
41843 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41844 if (clean != this.doc.body.innerHTML) {
41845 this.doc.body.innerHTML = clean;
41850 cleanWordChars : function(input) {// change the chars to hex code
41851 var he = Roo.HtmlEditorCore;
41853 var output = input;
41854 Roo.each(he.swapCodes, function(sw) {
41855 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41857 output = output.replace(swapper, sw[1]);
41864 cleanUpChildren : function (n)
41866 if (!n.childNodes.length) {
41869 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41870 this.cleanUpChild(n.childNodes[i]);
41877 cleanUpChild : function (node)
41880 //console.log(node);
41881 if (node.nodeName == "#text") {
41882 // clean up silly Windows -- stuff?
41885 if (node.nodeName == "#comment") {
41886 node.parentNode.removeChild(node);
41887 // clean up silly Windows -- stuff?
41891 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
41893 node.parentNode.removeChild(node);
41898 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41900 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41901 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41903 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41904 // remove_keep_children = true;
41907 if (remove_keep_children) {
41908 this.cleanUpChildren(node);
41909 // inserts everything just before this node...
41910 while (node.childNodes.length) {
41911 var cn = node.childNodes[0];
41912 node.removeChild(cn);
41913 node.parentNode.insertBefore(cn, node);
41915 node.parentNode.removeChild(node);
41919 if (!node.attributes || !node.attributes.length) {
41920 this.cleanUpChildren(node);
41924 function cleanAttr(n,v)
41927 if (v.match(/^\./) || v.match(/^\//)) {
41930 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41933 if (v.match(/^#/)) {
41936 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41937 node.removeAttribute(n);
41941 function cleanStyle(n,v)
41943 if (v.match(/expression/)) { //XSS?? should we even bother..
41944 node.removeAttribute(n);
41947 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
41948 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
41951 var parts = v.split(/;/);
41954 Roo.each(parts, function(p) {
41955 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41959 var l = p.split(':').shift().replace(/\s+/g,'');
41960 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41962 if ( cblack.indexOf(l) > -1) {
41963 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41964 //node.removeAttribute(n);
41968 // only allow 'c whitelisted system attributes'
41969 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41970 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41971 //node.removeAttribute(n);
41981 if (clean.length) {
41982 node.setAttribute(n, clean.join(';'));
41984 node.removeAttribute(n);
41990 for (var i = node.attributes.length-1; i > -1 ; i--) {
41991 var a = node.attributes[i];
41994 if (a.name.toLowerCase().substr(0,2)=='on') {
41995 node.removeAttribute(a.name);
41998 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
41999 node.removeAttribute(a.name);
42002 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42003 cleanAttr(a.name,a.value); // fixme..
42006 if (a.name == 'style') {
42007 cleanStyle(a.name,a.value);
42010 /// clean up MS crap..
42011 // tecnically this should be a list of valid class'es..
42014 if (a.name == 'class') {
42015 if (a.value.match(/^Mso/)) {
42016 node.className = '';
42019 if (a.value.match(/body/)) {
42020 node.className = '';
42031 this.cleanUpChildren(node);
42036 * Clean up MS wordisms...
42038 cleanWord : function(node)
42041 var cleanWordChildren = function()
42043 if (!node.childNodes.length) {
42046 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42047 _t.cleanWord(node.childNodes[i]);
42053 this.cleanWord(this.doc.body);
42056 if (node.nodeName == "#text") {
42057 // clean up silly Windows -- stuff?
42060 if (node.nodeName == "#comment") {
42061 node.parentNode.removeChild(node);
42062 // clean up silly Windows -- stuff?
42066 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42067 node.parentNode.removeChild(node);
42071 // remove - but keep children..
42072 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42073 while (node.childNodes.length) {
42074 var cn = node.childNodes[0];
42075 node.removeChild(cn);
42076 node.parentNode.insertBefore(cn, node);
42078 node.parentNode.removeChild(node);
42079 cleanWordChildren();
42083 if (node.className.length) {
42085 var cn = node.className.split(/\W+/);
42087 Roo.each(cn, function(cls) {
42088 if (cls.match(/Mso[a-zA-Z]+/)) {
42093 node.className = cna.length ? cna.join(' ') : '';
42095 node.removeAttribute("class");
42099 if (node.hasAttribute("lang")) {
42100 node.removeAttribute("lang");
42103 if (node.hasAttribute("style")) {
42105 var styles = node.getAttribute("style").split(";");
42107 Roo.each(styles, function(s) {
42108 if (!s.match(/:/)) {
42111 var kv = s.split(":");
42112 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42115 // what ever is left... we allow.
42118 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42119 if (!nstyle.length) {
42120 node.removeAttribute('style');
42124 cleanWordChildren();
42128 domToHTML : function(currentElement, depth, nopadtext) {
42130 depth = depth || 0;
42131 nopadtext = nopadtext || false;
42133 if (!currentElement) {
42134 return this.domToHTML(this.doc.body);
42137 //Roo.log(currentElement);
42139 var allText = false;
42140 var nodeName = currentElement.nodeName;
42141 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42143 if (nodeName == '#text') {
42144 return currentElement.nodeValue;
42149 if (nodeName != 'BODY') {
42152 // Prints the node tagName, such as <A>, <IMG>, etc
42155 for(i = 0; i < currentElement.attributes.length;i++) {
42157 var aname = currentElement.attributes.item(i).name;
42158 if (!currentElement.attributes.item(i).value.length) {
42161 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42164 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42173 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42176 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42181 // Traverse the tree
42183 var currentElementChild = currentElement.childNodes.item(i);
42184 var allText = true;
42185 var innerHTML = '';
42187 while (currentElementChild) {
42188 // Formatting code (indent the tree so it looks nice on the screen)
42189 var nopad = nopadtext;
42190 if (lastnode == 'SPAN') {
42194 if (currentElementChild.nodeName == '#text') {
42195 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42196 if (!nopad && toadd.length > 80) {
42197 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42199 innerHTML += toadd;
42202 currentElementChild = currentElement.childNodes.item(i);
42208 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42210 // Recursively traverse the tree structure of the child node
42211 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42212 lastnode = currentElementChild.nodeName;
42214 currentElementChild=currentElement.childNodes.item(i);
42220 // The remaining code is mostly for formatting the tree
42221 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42226 ret+= "</"+tagName+">";
42232 // hide stuff that is not compatible
42246 * @event specialkey
42250 * @cfg {String} fieldClass @hide
42253 * @cfg {String} focusClass @hide
42256 * @cfg {String} autoCreate @hide
42259 * @cfg {String} inputType @hide
42262 * @cfg {String} invalidClass @hide
42265 * @cfg {String} invalidText @hide
42268 * @cfg {String} msgFx @hide
42271 * @cfg {String} validateOnBlur @hide
42275 Roo.HtmlEditorCore.white = [
42276 'area', 'br', 'img', 'input', 'hr', 'wbr',
42278 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42279 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42280 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42281 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42282 'table', 'ul', 'xmp',
42284 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42287 'dir', 'menu', 'ol', 'ul', 'dl',
42293 Roo.HtmlEditorCore.black = [
42294 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42296 'base', 'basefont', 'bgsound', 'blink', 'body',
42297 'frame', 'frameset', 'head', 'html', 'ilayer',
42298 'iframe', 'layer', 'link', 'meta', 'object',
42299 'script', 'style' ,'title', 'xml' // clean later..
42301 Roo.HtmlEditorCore.clean = [
42302 'script', 'style', 'title', 'xml'
42304 Roo.HtmlEditorCore.remove = [
42309 Roo.HtmlEditorCore.ablack = [
42313 Roo.HtmlEditorCore.aclean = [
42314 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42318 Roo.HtmlEditorCore.pwhite= [
42319 'http', 'https', 'mailto'
42322 // white listed style attributes.
42323 Roo.HtmlEditorCore.cwhite= [
42324 // 'text-align', /// default is to allow most things..
42330 // black listed style attributes.
42331 Roo.HtmlEditorCore.cblack= [
42332 // 'font-size' -- this can be set by the project
42336 Roo.HtmlEditorCore.swapCodes =[
42347 //<script type="text/javascript">
42350 * Ext JS Library 1.1.1
42351 * Copyright(c) 2006-2007, Ext JS, LLC.
42357 Roo.form.HtmlEditor = function(config){
42361 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42363 if (!this.toolbars) {
42364 this.toolbars = [];
42366 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42372 * @class Roo.form.HtmlEditor
42373 * @extends Roo.form.Field
42374 * Provides a lightweight HTML Editor component.
42376 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42378 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42379 * supported by this editor.</b><br/><br/>
42380 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42381 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42383 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42385 * @cfg {Boolean} clearUp
42389 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42394 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42399 * @cfg {Number} height (in pixels)
42403 * @cfg {Number} width (in pixels)
42408 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42411 stylesheets: false,
42416 // private properties
42417 validationEvent : false,
42419 initialized : false,
42422 onFocus : Roo.emptyFn,
42424 hideMode:'offsets',
42426 defaultAutoCreate : { // modified by initCompnoent..
42428 style:"width:500px;height:300px;",
42429 autocomplete: "off"
42433 initComponent : function(){
42436 * @event initialize
42437 * Fires when the editor is fully initialized (including the iframe)
42438 * @param {HtmlEditor} this
42443 * Fires when the editor is first receives the focus. Any insertion must wait
42444 * until after this event.
42445 * @param {HtmlEditor} this
42449 * @event beforesync
42450 * Fires before the textarea is updated with content from the editor iframe. Return false
42451 * to cancel the sync.
42452 * @param {HtmlEditor} this
42453 * @param {String} html
42457 * @event beforepush
42458 * Fires before the iframe editor is updated with content from the textarea. Return false
42459 * to cancel the push.
42460 * @param {HtmlEditor} this
42461 * @param {String} html
42466 * Fires when the textarea is updated with content from the editor iframe.
42467 * @param {HtmlEditor} this
42468 * @param {String} html
42473 * Fires when the iframe editor is updated with content from the textarea.
42474 * @param {HtmlEditor} this
42475 * @param {String} html
42479 * @event editmodechange
42480 * Fires when the editor switches edit modes
42481 * @param {HtmlEditor} this
42482 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42484 editmodechange: true,
42486 * @event editorevent
42487 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42488 * @param {HtmlEditor} this
42492 * @event firstfocus
42493 * Fires when on first focus - needed by toolbars..
42494 * @param {HtmlEditor} this
42499 * Auto save the htmlEditor value as a file into Events
42500 * @param {HtmlEditor} this
42504 * @event savedpreview
42505 * preview the saved version of htmlEditor
42506 * @param {HtmlEditor} this
42510 this.defaultAutoCreate = {
42512 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42513 autocomplete: "off"
42518 * Protected method that will not generally be called directly. It
42519 * is called when the editor creates its toolbar. Override this method if you need to
42520 * add custom toolbar buttons.
42521 * @param {HtmlEditor} editor
42523 createToolbar : function(editor){
42524 Roo.log("create toolbars");
42525 if (!editor.toolbars || !editor.toolbars.length) {
42526 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42529 for (var i =0 ; i < editor.toolbars.length;i++) {
42530 editor.toolbars[i] = Roo.factory(
42531 typeof(editor.toolbars[i]) == 'string' ?
42532 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42533 Roo.form.HtmlEditor);
42534 editor.toolbars[i].init(editor);
42542 onRender : function(ct, position)
42545 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42547 this.wrap = this.el.wrap({
42548 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42551 this.editorcore.onRender(ct, position);
42553 if (this.resizable) {
42554 this.resizeEl = new Roo.Resizable(this.wrap, {
42558 minHeight : this.height,
42559 height: this.height,
42560 handles : this.resizable,
42563 resize : function(r, w, h) {
42564 _t.onResize(w,h); // -something
42570 this.createToolbar(this);
42574 this.setSize(this.wrap.getSize());
42576 if (this.resizeEl) {
42577 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42578 // should trigger onReize..
42581 // if(this.autosave && this.w){
42582 // this.autoSaveFn = setInterval(this.autosave, 1000);
42587 onResize : function(w, h)
42589 //Roo.log('resize: ' +w + ',' + h );
42590 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42595 if(typeof w == 'number'){
42596 var aw = w - this.wrap.getFrameWidth('lr');
42597 this.el.setWidth(this.adjustWidth('textarea', aw));
42600 if(typeof h == 'number'){
42602 for (var i =0; i < this.toolbars.length;i++) {
42603 // fixme - ask toolbars for heights?
42604 tbh += this.toolbars[i].tb.el.getHeight();
42605 if (this.toolbars[i].footer) {
42606 tbh += this.toolbars[i].footer.el.getHeight();
42613 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42614 ah -= 5; // knock a few pixes off for look..
42615 this.el.setHeight(this.adjustWidth('textarea', ah));
42619 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42620 this.editorcore.onResize(ew,eh);
42625 * Toggles the editor between standard and source edit mode.
42626 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42628 toggleSourceEdit : function(sourceEditMode)
42630 this.editorcore.toggleSourceEdit(sourceEditMode);
42632 if(this.editorcore.sourceEditMode){
42633 Roo.log('editor - showing textarea');
42636 // Roo.log(this.syncValue());
42637 this.editorcore.syncValue();
42638 this.el.removeClass('x-hidden');
42639 this.el.dom.removeAttribute('tabIndex');
42642 Roo.log('editor - hiding textarea');
42644 // Roo.log(this.pushValue());
42645 this.editorcore.pushValue();
42647 this.el.addClass('x-hidden');
42648 this.el.dom.setAttribute('tabIndex', -1);
42649 //this.deferFocus();
42652 this.setSize(this.wrap.getSize());
42653 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42656 // private (for BoxComponent)
42657 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42659 // private (for BoxComponent)
42660 getResizeEl : function(){
42664 // private (for BoxComponent)
42665 getPositionEl : function(){
42670 initEvents : function(){
42671 this.originalValue = this.getValue();
42675 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42678 markInvalid : Roo.emptyFn,
42680 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42683 clearInvalid : Roo.emptyFn,
42685 setValue : function(v){
42686 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42687 this.editorcore.pushValue();
42692 deferFocus : function(){
42693 this.focus.defer(10, this);
42697 focus : function(){
42698 this.editorcore.focus();
42704 onDestroy : function(){
42710 for (var i =0; i < this.toolbars.length;i++) {
42711 // fixme - ask toolbars for heights?
42712 this.toolbars[i].onDestroy();
42715 this.wrap.dom.innerHTML = '';
42716 this.wrap.remove();
42721 onFirstFocus : function(){
42722 //Roo.log("onFirstFocus");
42723 this.editorcore.onFirstFocus();
42724 for (var i =0; i < this.toolbars.length;i++) {
42725 this.toolbars[i].onFirstFocus();
42731 syncValue : function()
42733 this.editorcore.syncValue();
42736 pushValue : function()
42738 this.editorcore.pushValue();
42742 // hide stuff that is not compatible
42756 * @event specialkey
42760 * @cfg {String} fieldClass @hide
42763 * @cfg {String} focusClass @hide
42766 * @cfg {String} autoCreate @hide
42769 * @cfg {String} inputType @hide
42772 * @cfg {String} invalidClass @hide
42775 * @cfg {String} invalidText @hide
42778 * @cfg {String} msgFx @hide
42781 * @cfg {String} validateOnBlur @hide
42785 // <script type="text/javascript">
42788 * Ext JS Library 1.1.1
42789 * Copyright(c) 2006-2007, Ext JS, LLC.
42795 * @class Roo.form.HtmlEditorToolbar1
42800 new Roo.form.HtmlEditor({
42803 new Roo.form.HtmlEditorToolbar1({
42804 disable : { fonts: 1 , format: 1, ..., ... , ...],
42810 * @cfg {Object} disable List of elements to disable..
42811 * @cfg {Array} btns List of additional buttons.
42815 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42818 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42821 Roo.apply(this, config);
42823 // default disabled, based on 'good practice'..
42824 this.disable = this.disable || {};
42825 Roo.applyIf(this.disable, {
42828 specialElements : true
42832 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42833 // dont call parent... till later.
42836 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42843 editorcore : false,
42845 * @cfg {Object} disable List of toolbar elements to disable
42852 * @cfg {String} createLinkText The default text for the create link prompt
42854 createLinkText : 'Please enter the URL for the link:',
42856 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42858 defaultLinkValue : 'http:/'+'/',
42862 * @cfg {Array} fontFamilies An array of available font families
42880 // "á" , ?? a acute?
42885 "°" // , // degrees
42887 // "é" , // e ecute
42888 // "ú" , // u ecute?
42891 specialElements : [
42893 text: "Insert Table",
42896 ihtml : '<table><tr><td>Cell</td></tr></table>'
42900 text: "Insert Image",
42903 ihtml : '<img src="about:blank"/>'
42912 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42913 "input:submit", "input:button", "select", "textarea", "label" ],
42916 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42918 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42926 * @cfg {String} defaultFont default font to use.
42928 defaultFont: 'tahoma',
42930 fontSelect : false,
42933 formatCombo : false,
42935 init : function(editor)
42937 this.editor = editor;
42938 this.editorcore = editor.editorcore ? editor.editorcore : editor;
42939 var editorcore = this.editorcore;
42943 var fid = editorcore.frameId;
42945 function btn(id, toggle, handler){
42946 var xid = fid + '-'+ id ;
42950 cls : 'x-btn-icon x-edit-'+id,
42951 enableToggle:toggle !== false,
42952 scope: _t, // was editor...
42953 handler:handler||_t.relayBtnCmd,
42954 clickEvent:'mousedown',
42955 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42962 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42964 // stop form submits
42965 tb.el.on('click', function(e){
42966 e.preventDefault(); // what does this do?
42969 if(!this.disable.font) { // && !Roo.isSafari){
42970 /* why no safari for fonts
42971 editor.fontSelect = tb.el.createChild({
42974 cls:'x-font-select',
42975 html: this.createFontOptions()
42978 editor.fontSelect.on('change', function(){
42979 var font = editor.fontSelect.dom.value;
42980 editor.relayCmd('fontname', font);
42981 editor.deferFocus();
42985 editor.fontSelect.dom,
42991 if(!this.disable.formats){
42992 this.formatCombo = new Roo.form.ComboBox({
42993 store: new Roo.data.SimpleStore({
42996 data : this.formats // from states.js
43000 //autoCreate : {tag: "div", size: "20"},
43001 displayField:'tag',
43005 triggerAction: 'all',
43006 emptyText:'Add tag',
43007 selectOnFocus:true,
43010 'select': function(c, r, i) {
43011 editorcore.insertTag(r.get('tag'));
43017 tb.addField(this.formatCombo);
43021 if(!this.disable.format){
43028 if(!this.disable.fontSize){
43033 btn('increasefontsize', false, editorcore.adjustFont),
43034 btn('decreasefontsize', false, editorcore.adjustFont)
43039 if(!this.disable.colors){
43042 id:editorcore.frameId +'-forecolor',
43043 cls:'x-btn-icon x-edit-forecolor',
43044 clickEvent:'mousedown',
43045 tooltip: this.buttonTips['forecolor'] || undefined,
43047 menu : new Roo.menu.ColorMenu({
43048 allowReselect: true,
43049 focus: Roo.emptyFn,
43052 selectHandler: function(cp, color){
43053 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43054 editor.deferFocus();
43057 clickEvent:'mousedown'
43060 id:editorcore.frameId +'backcolor',
43061 cls:'x-btn-icon x-edit-backcolor',
43062 clickEvent:'mousedown',
43063 tooltip: this.buttonTips['backcolor'] || undefined,
43065 menu : new Roo.menu.ColorMenu({
43066 focus: Roo.emptyFn,
43069 allowReselect: true,
43070 selectHandler: function(cp, color){
43072 editorcore.execCmd('useCSS', false);
43073 editorcore.execCmd('hilitecolor', color);
43074 editorcore.execCmd('useCSS', true);
43075 editor.deferFocus();
43077 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43078 Roo.isSafari || Roo.isIE ? '#'+color : color);
43079 editor.deferFocus();
43083 clickEvent:'mousedown'
43088 // now add all the items...
43091 if(!this.disable.alignments){
43094 btn('justifyleft'),
43095 btn('justifycenter'),
43096 btn('justifyright')
43100 //if(!Roo.isSafari){
43101 if(!this.disable.links){
43104 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43108 if(!this.disable.lists){
43111 btn('insertorderedlist'),
43112 btn('insertunorderedlist')
43115 if(!this.disable.sourceEdit){
43118 btn('sourceedit', true, function(btn){
43120 this.toggleSourceEdit(btn.pressed);
43127 // special menu.. - needs to be tidied up..
43128 if (!this.disable.special) {
43131 cls: 'x-edit-none',
43137 for (var i =0; i < this.specialChars.length; i++) {
43138 smenu.menu.items.push({
43140 html: this.specialChars[i],
43141 handler: function(a,b) {
43142 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43143 //editor.insertAtCursor(a.html);
43157 if (!this.disable.cleanStyles) {
43159 cls: 'x-btn-icon x-btn-clear',
43165 for (var i =0; i < this.cleanStyles.length; i++) {
43166 cmenu.menu.items.push({
43167 actiontype : this.cleanStyles[i],
43168 html: 'Remove ' + this.cleanStyles[i],
43169 handler: function(a,b) {
43172 var c = Roo.get(editorcore.doc.body);
43173 c.select('[style]').each(function(s) {
43174 s.dom.style.removeProperty(a.actiontype);
43176 editorcore.syncValue();
43181 cmenu.menu.items.push({
43182 actiontype : 'word',
43183 html: 'Remove MS Word Formating',
43184 handler: function(a,b) {
43185 editorcore.cleanWord();
43186 editorcore.syncValue();
43191 cmenu.menu.items.push({
43192 actiontype : 'all',
43193 html: 'Remove All Styles',
43194 handler: function(a,b) {
43196 var c = Roo.get(editorcore.doc.body);
43197 c.select('[style]').each(function(s) {
43198 s.dom.removeAttribute('style');
43200 editorcore.syncValue();
43204 cmenu.menu.items.push({
43205 actiontype : 'word',
43206 html: 'Tidy HTML Source',
43207 handler: function(a,b) {
43208 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43209 editorcore.syncValue();
43218 if (!this.disable.specialElements) {
43221 cls: 'x-edit-none',
43226 for (var i =0; i < this.specialElements.length; i++) {
43227 semenu.menu.items.push(
43229 handler: function(a,b) {
43230 editor.insertAtCursor(this.ihtml);
43232 }, this.specialElements[i])
43244 for(var i =0; i< this.btns.length;i++) {
43245 var b = Roo.factory(this.btns[i],Roo.form);
43246 b.cls = 'x-edit-none';
43247 b.scope = editorcore;
43255 // disable everything...
43257 this.tb.items.each(function(item){
43258 if(item.id != editorcore.frameId+ '-sourceedit'){
43262 this.rendered = true;
43264 // the all the btns;
43265 editor.on('editorevent', this.updateToolbar, this);
43266 // other toolbars need to implement this..
43267 //editor.on('editmodechange', this.updateToolbar, this);
43271 relayBtnCmd : function(btn) {
43272 this.editorcore.relayCmd(btn.cmd);
43274 // private used internally
43275 createLink : function(){
43276 Roo.log("create link?");
43277 var url = prompt(this.createLinkText, this.defaultLinkValue);
43278 if(url && url != 'http:/'+'/'){
43279 this.editorcore.relayCmd('createlink', url);
43285 * Protected method that will not generally be called directly. It triggers
43286 * a toolbar update by reading the markup state of the current selection in the editor.
43288 updateToolbar: function(){
43290 if(!this.editorcore.activated){
43291 this.editor.onFirstFocus();
43295 var btns = this.tb.items.map,
43296 doc = this.editorcore.doc,
43297 frameId = this.editorcore.frameId;
43299 if(!this.disable.font && !Roo.isSafari){
43301 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43302 if(name != this.fontSelect.dom.value){
43303 this.fontSelect.dom.value = name;
43307 if(!this.disable.format){
43308 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43309 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43310 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43312 if(!this.disable.alignments){
43313 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43314 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43315 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43317 if(!Roo.isSafari && !this.disable.lists){
43318 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43319 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43322 var ans = this.editorcore.getAllAncestors();
43323 if (this.formatCombo) {
43326 var store = this.formatCombo.store;
43327 this.formatCombo.setValue("");
43328 for (var i =0; i < ans.length;i++) {
43329 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43331 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43339 // hides menus... - so this cant be on a menu...
43340 Roo.menu.MenuMgr.hideAll();
43342 //this.editorsyncValue();
43346 createFontOptions : function(){
43347 var buf = [], fs = this.fontFamilies, ff, lc;
43351 for(var i = 0, len = fs.length; i< len; i++){
43353 lc = ff.toLowerCase();
43355 '<option value="',lc,'" style="font-family:',ff,';"',
43356 (this.defaultFont == lc ? ' selected="true">' : '>'),
43361 return buf.join('');
43364 toggleSourceEdit : function(sourceEditMode){
43366 Roo.log("toolbar toogle");
43367 if(sourceEditMode === undefined){
43368 sourceEditMode = !this.sourceEditMode;
43370 this.sourceEditMode = sourceEditMode === true;
43371 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43372 // just toggle the button?
43373 if(btn.pressed !== this.sourceEditMode){
43374 btn.toggle(this.sourceEditMode);
43378 if(sourceEditMode){
43379 Roo.log("disabling buttons");
43380 this.tb.items.each(function(item){
43381 if(item.cmd != 'sourceedit'){
43387 Roo.log("enabling buttons");
43388 if(this.editorcore.initialized){
43389 this.tb.items.each(function(item){
43395 Roo.log("calling toggole on editor");
43396 // tell the editor that it's been pressed..
43397 this.editor.toggleSourceEdit(sourceEditMode);
43401 * Object collection of toolbar tooltips for the buttons in the editor. The key
43402 * is the command id associated with that button and the value is a valid QuickTips object.
43407 title: 'Bold (Ctrl+B)',
43408 text: 'Make the selected text bold.',
43409 cls: 'x-html-editor-tip'
43412 title: 'Italic (Ctrl+I)',
43413 text: 'Make the selected text italic.',
43414 cls: 'x-html-editor-tip'
43422 title: 'Bold (Ctrl+B)',
43423 text: 'Make the selected text bold.',
43424 cls: 'x-html-editor-tip'
43427 title: 'Italic (Ctrl+I)',
43428 text: 'Make the selected text italic.',
43429 cls: 'x-html-editor-tip'
43432 title: 'Underline (Ctrl+U)',
43433 text: 'Underline the selected text.',
43434 cls: 'x-html-editor-tip'
43436 increasefontsize : {
43437 title: 'Grow Text',
43438 text: 'Increase the font size.',
43439 cls: 'x-html-editor-tip'
43441 decreasefontsize : {
43442 title: 'Shrink Text',
43443 text: 'Decrease the font size.',
43444 cls: 'x-html-editor-tip'
43447 title: 'Text Highlight Color',
43448 text: 'Change the background color of the selected text.',
43449 cls: 'x-html-editor-tip'
43452 title: 'Font Color',
43453 text: 'Change the color of the selected text.',
43454 cls: 'x-html-editor-tip'
43457 title: 'Align Text Left',
43458 text: 'Align text to the left.',
43459 cls: 'x-html-editor-tip'
43462 title: 'Center Text',
43463 text: 'Center text in the editor.',
43464 cls: 'x-html-editor-tip'
43467 title: 'Align Text Right',
43468 text: 'Align text to the right.',
43469 cls: 'x-html-editor-tip'
43471 insertunorderedlist : {
43472 title: 'Bullet List',
43473 text: 'Start a bulleted list.',
43474 cls: 'x-html-editor-tip'
43476 insertorderedlist : {
43477 title: 'Numbered List',
43478 text: 'Start a numbered list.',
43479 cls: 'x-html-editor-tip'
43482 title: 'Hyperlink',
43483 text: 'Make the selected text a hyperlink.',
43484 cls: 'x-html-editor-tip'
43487 title: 'Source Edit',
43488 text: 'Switch to source editing mode.',
43489 cls: 'x-html-editor-tip'
43493 onDestroy : function(){
43496 this.tb.items.each(function(item){
43498 item.menu.removeAll();
43500 item.menu.el.destroy();
43508 onFirstFocus: function() {
43509 this.tb.items.each(function(item){
43518 // <script type="text/javascript">
43521 * Ext JS Library 1.1.1
43522 * Copyright(c) 2006-2007, Ext JS, LLC.
43529 * @class Roo.form.HtmlEditor.ToolbarContext
43534 new Roo.form.HtmlEditor({
43537 { xtype: 'ToolbarStandard', styles : {} }
43538 { xtype: 'ToolbarContext', disable : {} }
43544 * @config : {Object} disable List of elements to disable.. (not done yet.)
43545 * @config : {Object} styles Map of styles available.
43549 Roo.form.HtmlEditor.ToolbarContext = function(config)
43552 Roo.apply(this, config);
43553 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43554 // dont call parent... till later.
43555 this.styles = this.styles || {};
43560 Roo.form.HtmlEditor.ToolbarContext.types = {
43572 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43638 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43643 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43653 style : 'fontFamily',
43654 displayField: 'display',
43655 optname : 'font-family',
43704 // should we really allow this??
43705 // should this just be
43716 style : 'fontFamily',
43717 displayField: 'display',
43718 optname : 'font-family',
43725 style : 'fontFamily',
43726 displayField: 'display',
43727 optname : 'font-family',
43734 style : 'fontFamily',
43735 displayField: 'display',
43736 optname : 'font-family',
43747 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43748 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43750 Roo.form.HtmlEditor.ToolbarContext.options = {
43752 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43753 [ 'Courier New', 'Courier New'],
43754 [ 'Tahoma', 'Tahoma'],
43755 [ 'Times New Roman,serif', 'Times'],
43756 [ 'Verdana','Verdana' ]
43760 // fixme - these need to be configurable..
43763 Roo.form.HtmlEditor.ToolbarContext.types
43766 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43773 editorcore : false,
43775 * @cfg {Object} disable List of toolbar elements to disable
43780 * @cfg {Object} styles List of styles
43781 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43783 * These must be defined in the page, so they get rendered correctly..
43794 init : function(editor)
43796 this.editor = editor;
43797 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43798 var editorcore = this.editorcore;
43800 var fid = editorcore.frameId;
43802 function btn(id, toggle, handler){
43803 var xid = fid + '-'+ id ;
43807 cls : 'x-btn-icon x-edit-'+id,
43808 enableToggle:toggle !== false,
43809 scope: editorcore, // was editor...
43810 handler:handler||editorcore.relayBtnCmd,
43811 clickEvent:'mousedown',
43812 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43816 // create a new element.
43817 var wdiv = editor.wrap.createChild({
43819 }, editor.wrap.dom.firstChild.nextSibling, true);
43821 // can we do this more than once??
43823 // stop form submits
43826 // disable everything...
43827 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43828 this.toolbars = {};
43830 for (var i in ty) {
43832 this.toolbars[i] = this.buildToolbar(ty[i],i);
43834 this.tb = this.toolbars.BODY;
43836 this.buildFooter();
43837 this.footer.show();
43838 editor.on('hide', function( ) { this.footer.hide() }, this);
43839 editor.on('show', function( ) { this.footer.show() }, this);
43842 this.rendered = true;
43844 // the all the btns;
43845 editor.on('editorevent', this.updateToolbar, this);
43846 // other toolbars need to implement this..
43847 //editor.on('editmodechange', this.updateToolbar, this);
43853 * Protected method that will not generally be called directly. It triggers
43854 * a toolbar update by reading the markup state of the current selection in the editor.
43856 updateToolbar: function(editor,ev,sel){
43859 // capture mouse up - this is handy for selecting images..
43860 // perhaps should go somewhere else...
43861 if(!this.editorcore.activated){
43862 this.editor.onFirstFocus();
43866 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43867 // selectNode - might want to handle IE?
43869 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43870 ev.target && ev.target.tagName == 'IMG') {
43871 // they have click on an image...
43872 // let's see if we can change the selection...
43875 var nodeRange = sel.ownerDocument.createRange();
43877 nodeRange.selectNode(sel);
43879 nodeRange.selectNodeContents(sel);
43881 //nodeRange.collapse(true);
43882 var s = this.editorcore.win.getSelection();
43883 s.removeAllRanges();
43884 s.addRange(nodeRange);
43888 var updateFooter = sel ? false : true;
43891 var ans = this.editorcore.getAllAncestors();
43894 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43897 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43898 sel = sel ? sel : this.editorcore.doc.body;
43899 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43902 // pick a menu that exists..
43903 var tn = sel.tagName.toUpperCase();
43904 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43906 tn = sel.tagName.toUpperCase();
43908 var lastSel = this.tb.selectedNode
43910 this.tb.selectedNode = sel;
43912 // if current menu does not match..
43913 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43916 ///console.log("show: " + tn);
43917 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43920 this.tb.items.first().el.innerHTML = tn + ': ';
43923 // update attributes
43924 if (this.tb.fields) {
43925 this.tb.fields.each(function(e) {
43927 e.setValue(sel.style[e.stylename]);
43930 e.setValue(sel.getAttribute(e.attrname));
43934 var hasStyles = false;
43935 for(var i in this.styles) {
43942 var st = this.tb.fields.item(0);
43944 st.store.removeAll();
43947 var cn = sel.className.split(/\s+/);
43950 if (this.styles['*']) {
43952 Roo.each(this.styles['*'], function(v) {
43953 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43956 if (this.styles[tn]) {
43957 Roo.each(this.styles[tn], function(v) {
43958 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43962 st.store.loadData(avs);
43966 // flag our selected Node.
43967 this.tb.selectedNode = sel;
43970 Roo.menu.MenuMgr.hideAll();
43974 if (!updateFooter) {
43975 //this.footDisp.dom.innerHTML = '';
43978 // update the footer
43982 this.footerEls = ans.reverse();
43983 Roo.each(this.footerEls, function(a,i) {
43984 if (!a) { return; }
43985 html += html.length ? ' > ' : '';
43987 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43992 var sz = this.footDisp.up('td').getSize();
43993 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43994 this.footDisp.dom.style.marginLeft = '5px';
43996 this.footDisp.dom.style.overflow = 'hidden';
43998 this.footDisp.dom.innerHTML = html;
44000 //this.editorsyncValue();
44007 onDestroy : function(){
44010 this.tb.items.each(function(item){
44012 item.menu.removeAll();
44014 item.menu.el.destroy();
44022 onFirstFocus: function() {
44023 // need to do this for all the toolbars..
44024 this.tb.items.each(function(item){
44028 buildToolbar: function(tlist, nm)
44030 var editor = this.editor;
44031 var editorcore = this.editorcore;
44032 // create a new element.
44033 var wdiv = editor.wrap.createChild({
44035 }, editor.wrap.dom.firstChild.nextSibling, true);
44038 var tb = new Roo.Toolbar(wdiv);
44041 tb.add(nm+ ": ");
44044 for(var i in this.styles) {
44049 if (styles && styles.length) {
44051 // this needs a multi-select checkbox...
44052 tb.addField( new Roo.form.ComboBox({
44053 store: new Roo.data.SimpleStore({
44055 fields: ['val', 'selected'],
44058 name : '-roo-edit-className',
44059 attrname : 'className',
44060 displayField: 'val',
44064 triggerAction: 'all',
44065 emptyText:'Select Style',
44066 selectOnFocus:true,
44069 'select': function(c, r, i) {
44070 // initial support only for on class per el..
44071 tb.selectedNode.className = r ? r.get('val') : '';
44072 editorcore.syncValue();
44079 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44080 var tbops = tbc.options;
44082 for (var i in tlist) {
44084 var item = tlist[i];
44085 tb.add(item.title + ": ");
44088 //optname == used so you can configure the options available..
44089 var opts = item.opts ? item.opts : false;
44090 if (item.optname) {
44091 opts = tbops[item.optname];
44096 // opts == pulldown..
44097 tb.addField( new Roo.form.ComboBox({
44098 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44100 fields: ['val', 'display'],
44103 name : '-roo-edit-' + i,
44105 stylename : item.style ? item.style : false,
44106 displayField: item.displayField ? item.displayField : 'val',
44107 valueField : 'val',
44109 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44111 triggerAction: 'all',
44112 emptyText:'Select',
44113 selectOnFocus:true,
44114 width: item.width ? item.width : 130,
44116 'select': function(c, r, i) {
44118 tb.selectedNode.style[c.stylename] = r.get('val');
44121 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44130 tb.addField( new Roo.form.TextField({
44133 //allowBlank:false,
44138 tb.addField( new Roo.form.TextField({
44139 name: '-roo-edit-' + i,
44146 'change' : function(f, nv, ov) {
44147 tb.selectedNode.setAttribute(f.attrname, nv);
44156 text: 'Remove Tag',
44159 click : function ()
44162 // undo does not work.
44164 var sn = tb.selectedNode;
44166 var pn = sn.parentNode;
44168 var stn = sn.childNodes[0];
44169 var en = sn.childNodes[sn.childNodes.length - 1 ];
44170 while (sn.childNodes.length) {
44171 var node = sn.childNodes[0];
44172 sn.removeChild(node);
44174 pn.insertBefore(node, sn);
44177 pn.removeChild(sn);
44178 var range = editorcore.createRange();
44180 range.setStart(stn,0);
44181 range.setEnd(en,0); //????
44182 //range.selectNode(sel);
44185 var selection = editorcore.getSelection();
44186 selection.removeAllRanges();
44187 selection.addRange(range);
44191 //_this.updateToolbar(null, null, pn);
44192 _this.updateToolbar(null, null, null);
44193 _this.footDisp.dom.innerHTML = '';
44203 tb.el.on('click', function(e){
44204 e.preventDefault(); // what does this do?
44206 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44209 // dont need to disable them... as they will get hidden
44214 buildFooter : function()
44217 var fel = this.editor.wrap.createChild();
44218 this.footer = new Roo.Toolbar(fel);
44219 // toolbar has scrolly on left / right?
44220 var footDisp= new Roo.Toolbar.Fill();
44226 handler : function() {
44227 _t.footDisp.scrollTo('left',0,true)
44231 this.footer.add( footDisp );
44236 handler : function() {
44238 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44242 var fel = Roo.get(footDisp.el);
44243 fel.addClass('x-editor-context');
44244 this.footDispWrap = fel;
44245 this.footDispWrap.overflow = 'hidden';
44247 this.footDisp = fel.createChild();
44248 this.footDispWrap.on('click', this.onContextClick, this)
44252 onContextClick : function (ev,dom)
44254 ev.preventDefault();
44255 var cn = dom.className;
44257 if (!cn.match(/x-ed-loc-/)) {
44260 var n = cn.split('-').pop();
44261 var ans = this.footerEls;
44265 var range = this.editorcore.createRange();
44267 range.selectNodeContents(sel);
44268 //range.selectNode(sel);
44271 var selection = this.editorcore.getSelection();
44272 selection.removeAllRanges();
44273 selection.addRange(range);
44277 this.updateToolbar(null, null, sel);
44294 * Ext JS Library 1.1.1
44295 * Copyright(c) 2006-2007, Ext JS, LLC.
44297 * Originally Released Under LGPL - original licence link has changed is not relivant.
44300 * <script type="text/javascript">
44304 * @class Roo.form.BasicForm
44305 * @extends Roo.util.Observable
44306 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44308 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44309 * @param {Object} config Configuration options
44311 Roo.form.BasicForm = function(el, config){
44312 this.allItems = [];
44313 this.childForms = [];
44314 Roo.apply(this, config);
44316 * The Roo.form.Field items in this form.
44317 * @type MixedCollection
44321 this.items = new Roo.util.MixedCollection(false, function(o){
44322 return o.id || (o.id = Roo.id());
44326 * @event beforeaction
44327 * Fires before any action is performed. Return false to cancel the action.
44328 * @param {Form} this
44329 * @param {Action} action The action to be performed
44331 beforeaction: true,
44333 * @event actionfailed
44334 * Fires when an action fails.
44335 * @param {Form} this
44336 * @param {Action} action The action that failed
44338 actionfailed : true,
44340 * @event actioncomplete
44341 * Fires when an action is completed.
44342 * @param {Form} this
44343 * @param {Action} action The action that completed
44345 actioncomplete : true
44350 Roo.form.BasicForm.superclass.constructor.call(this);
44353 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44355 * @cfg {String} method
44356 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44359 * @cfg {DataReader} reader
44360 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44361 * This is optional as there is built-in support for processing JSON.
44364 * @cfg {DataReader} errorReader
44365 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44366 * This is completely optional as there is built-in support for processing JSON.
44369 * @cfg {String} url
44370 * The URL to use for form actions if one isn't supplied in the action options.
44373 * @cfg {Boolean} fileUpload
44374 * Set to true if this form is a file upload.
44378 * @cfg {Object} baseParams
44379 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44384 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44389 activeAction : null,
44392 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44393 * or setValues() data instead of when the form was first created.
44395 trackResetOnLoad : false,
44399 * childForms - used for multi-tab forms
44402 childForms : false,
44405 * allItems - full list of fields.
44411 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44412 * element by passing it or its id or mask the form itself by passing in true.
44415 waitMsgTarget : false,
44418 initEl : function(el){
44419 this.el = Roo.get(el);
44420 this.id = this.el.id || Roo.id();
44421 this.el.on('submit', this.onSubmit, this);
44422 this.el.addClass('x-form');
44426 onSubmit : function(e){
44431 * Returns true if client-side validation on the form is successful.
44434 isValid : function(){
44436 this.items.each(function(f){
44445 * Returns true if any fields in this form have changed since their original load.
44448 isDirty : function(){
44450 this.items.each(function(f){
44460 * Performs a predefined action (submit or load) or custom actions you define on this form.
44461 * @param {String} actionName The name of the action type
44462 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44463 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44464 * accept other config options):
44466 Property Type Description
44467 ---------------- --------------- ----------------------------------------------------------------------------------
44468 url String The url for the action (defaults to the form's url)
44469 method String The form method to use (defaults to the form's method, or POST if not defined)
44470 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44471 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44472 validate the form on the client (defaults to false)
44474 * @return {BasicForm} this
44476 doAction : function(action, options){
44477 if(typeof action == 'string'){
44478 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44480 if(this.fireEvent('beforeaction', this, action) !== false){
44481 this.beforeAction(action);
44482 action.run.defer(100, action);
44488 * Shortcut to do a submit action.
44489 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44490 * @return {BasicForm} this
44492 submit : function(options){
44493 this.doAction('submit', options);
44498 * Shortcut to do a load action.
44499 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44500 * @return {BasicForm} this
44502 load : function(options){
44503 this.doAction('load', options);
44508 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44509 * @param {Record} record The record to edit
44510 * @return {BasicForm} this
44512 updateRecord : function(record){
44513 record.beginEdit();
44514 var fs = record.fields;
44515 fs.each(function(f){
44516 var field = this.findField(f.name);
44518 record.set(f.name, field.getValue());
44526 * Loads an Roo.data.Record into this form.
44527 * @param {Record} record The record to load
44528 * @return {BasicForm} this
44530 loadRecord : function(record){
44531 this.setValues(record.data);
44536 beforeAction : function(action){
44537 var o = action.options;
44540 if(this.waitMsgTarget === true){
44541 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44542 }else if(this.waitMsgTarget){
44543 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44544 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44546 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44552 afterAction : function(action, success){
44553 this.activeAction = null;
44554 var o = action.options;
44556 if(this.waitMsgTarget === true){
44558 }else if(this.waitMsgTarget){
44559 this.waitMsgTarget.unmask();
44561 Roo.MessageBox.updateProgress(1);
44562 Roo.MessageBox.hide();
44569 Roo.callback(o.success, o.scope, [this, action]);
44570 this.fireEvent('actioncomplete', this, action);
44574 // failure condition..
44575 // we have a scenario where updates need confirming.
44576 // eg. if a locking scenario exists..
44577 // we look for { errors : { needs_confirm : true }} in the response.
44579 (typeof(action.result) != 'undefined') &&
44580 (typeof(action.result.errors) != 'undefined') &&
44581 (typeof(action.result.errors.needs_confirm) != 'undefined')
44584 Roo.MessageBox.confirm(
44585 "Change requires confirmation",
44586 action.result.errorMsg,
44591 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44601 Roo.callback(o.failure, o.scope, [this, action]);
44602 // show an error message if no failed handler is set..
44603 if (!this.hasListener('actionfailed')) {
44604 Roo.MessageBox.alert("Error",
44605 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44606 action.result.errorMsg :
44607 "Saving Failed, please check your entries or try again"
44611 this.fireEvent('actionfailed', this, action);
44617 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44618 * @param {String} id The value to search for
44621 findField : function(id){
44622 var field = this.items.get(id);
44624 this.items.each(function(f){
44625 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44631 return field || null;
44635 * Add a secondary form to this one,
44636 * Used to provide tabbed forms. One form is primary, with hidden values
44637 * which mirror the elements from the other forms.
44639 * @param {Roo.form.Form} form to add.
44642 addForm : function(form)
44645 if (this.childForms.indexOf(form) > -1) {
44649 this.childForms.push(form);
44651 Roo.each(form.allItems, function (fe) {
44653 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44654 if (this.findField(n)) { // already added..
44657 var add = new Roo.form.Hidden({
44660 add.render(this.el);
44667 * Mark fields in this form invalid in bulk.
44668 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44669 * @return {BasicForm} this
44671 markInvalid : function(errors){
44672 if(errors instanceof Array){
44673 for(var i = 0, len = errors.length; i < len; i++){
44674 var fieldError = errors[i];
44675 var f = this.findField(fieldError.id);
44677 f.markInvalid(fieldError.msg);
44683 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44684 field.markInvalid(errors[id]);
44688 Roo.each(this.childForms || [], function (f) {
44689 f.markInvalid(errors);
44696 * Set values for fields in this form in bulk.
44697 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44698 * @return {BasicForm} this
44700 setValues : function(values){
44701 if(values instanceof Array){ // array of objects
44702 for(var i = 0, len = values.length; i < len; i++){
44704 var f = this.findField(v.id);
44706 f.setValue(v.value);
44707 if(this.trackResetOnLoad){
44708 f.originalValue = f.getValue();
44712 }else{ // object hash
44715 if(typeof values[id] != 'function' && (field = this.findField(id))){
44717 if (field.setFromData &&
44718 field.valueField &&
44719 field.displayField &&
44720 // combos' with local stores can
44721 // be queried via setValue()
44722 // to set their value..
44723 (field.store && !field.store.isLocal)
44727 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44728 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44729 field.setFromData(sd);
44732 field.setValue(values[id]);
44736 if(this.trackResetOnLoad){
44737 field.originalValue = field.getValue();
44743 Roo.each(this.childForms || [], function (f) {
44744 f.setValues(values);
44751 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44752 * they are returned as an array.
44753 * @param {Boolean} asString
44756 getValues : function(asString){
44757 if (this.childForms) {
44758 // copy values from the child forms
44759 Roo.each(this.childForms, function (f) {
44760 this.setValues(f.getValues());
44766 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44767 if(asString === true){
44770 return Roo.urlDecode(fs);
44774 * Returns the fields in this form as an object with key/value pairs.
44775 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44778 getFieldValues : function(with_hidden)
44780 if (this.childForms) {
44781 // copy values from the child forms
44782 // should this call getFieldValues - probably not as we do not currently copy
44783 // hidden fields when we generate..
44784 Roo.each(this.childForms, function (f) {
44785 this.setValues(f.getValues());
44790 this.items.each(function(f){
44791 if (!f.getName()) {
44794 var v = f.getValue();
44795 if (f.inputType =='radio') {
44796 if (typeof(ret[f.getName()]) == 'undefined') {
44797 ret[f.getName()] = ''; // empty..
44800 if (!f.el.dom.checked) {
44804 v = f.el.dom.value;
44808 // not sure if this supported any more..
44809 if ((typeof(v) == 'object') && f.getRawValue) {
44810 v = f.getRawValue() ; // dates..
44812 // combo boxes where name != hiddenName...
44813 if (f.name != f.getName()) {
44814 ret[f.name] = f.getRawValue();
44816 ret[f.getName()] = v;
44823 * Clears all invalid messages in this form.
44824 * @return {BasicForm} this
44826 clearInvalid : function(){
44827 this.items.each(function(f){
44831 Roo.each(this.childForms || [], function (f) {
44840 * Resets this form.
44841 * @return {BasicForm} this
44843 reset : function(){
44844 this.items.each(function(f){
44848 Roo.each(this.childForms || [], function (f) {
44857 * Add Roo.form components to this form.
44858 * @param {Field} field1
44859 * @param {Field} field2 (optional)
44860 * @param {Field} etc (optional)
44861 * @return {BasicForm} this
44864 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44870 * Removes a field from the items collection (does NOT remove its markup).
44871 * @param {Field} field
44872 * @return {BasicForm} this
44874 remove : function(field){
44875 this.items.remove(field);
44880 * Looks at the fields in this form, checks them for an id attribute,
44881 * and calls applyTo on the existing dom element with that id.
44882 * @return {BasicForm} this
44884 render : function(){
44885 this.items.each(function(f){
44886 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44894 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44895 * @param {Object} values
44896 * @return {BasicForm} this
44898 applyToFields : function(o){
44899 this.items.each(function(f){
44906 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44907 * @param {Object} values
44908 * @return {BasicForm} this
44910 applyIfToFields : function(o){
44911 this.items.each(function(f){
44919 Roo.BasicForm = Roo.form.BasicForm;/*
44921 * Ext JS Library 1.1.1
44922 * Copyright(c) 2006-2007, Ext JS, LLC.
44924 * Originally Released Under LGPL - original licence link has changed is not relivant.
44927 * <script type="text/javascript">
44931 * @class Roo.form.Form
44932 * @extends Roo.form.BasicForm
44933 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44935 * @param {Object} config Configuration options
44937 Roo.form.Form = function(config){
44939 if (config.items) {
44940 xitems = config.items;
44941 delete config.items;
44945 Roo.form.Form.superclass.constructor.call(this, null, config);
44946 this.url = this.url || this.action;
44948 this.root = new Roo.form.Layout(Roo.applyIf({
44952 this.active = this.root;
44954 * Array of all the buttons that have been added to this form via {@link addButton}
44958 this.allItems = [];
44961 * @event clientvalidation
44962 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44963 * @param {Form} this
44964 * @param {Boolean} valid true if the form has passed client-side validation
44966 clientvalidation: true,
44969 * Fires when the form is rendered
44970 * @param {Roo.form.Form} form
44975 if (this.progressUrl) {
44976 // push a hidden field onto the list of fields..
44980 name : 'UPLOAD_IDENTIFIER'
44985 Roo.each(xitems, this.addxtype, this);
44991 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44993 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44996 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44999 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45001 buttonAlign:'center',
45004 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45009 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45010 * This property cascades to child containers if not set.
45015 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45016 * fires a looping event with that state. This is required to bind buttons to the valid
45017 * state using the config value formBind:true on the button.
45019 monitorValid : false,
45022 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45027 * @cfg {String} progressUrl - Url to return progress data
45030 progressUrl : false,
45033 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45034 * fields are added and the column is closed. If no fields are passed the column remains open
45035 * until end() is called.
45036 * @param {Object} config The config to pass to the column
45037 * @param {Field} field1 (optional)
45038 * @param {Field} field2 (optional)
45039 * @param {Field} etc (optional)
45040 * @return Column The column container object
45042 column : function(c){
45043 var col = new Roo.form.Column(c);
45045 if(arguments.length > 1){ // duplicate code required because of Opera
45046 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45053 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45054 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45055 * until end() is called.
45056 * @param {Object} config The config to pass to the fieldset
45057 * @param {Field} field1 (optional)
45058 * @param {Field} field2 (optional)
45059 * @param {Field} etc (optional)
45060 * @return FieldSet The fieldset container object
45062 fieldset : function(c){
45063 var fs = new Roo.form.FieldSet(c);
45065 if(arguments.length > 1){ // duplicate code required because of Opera
45066 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45073 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45074 * fields are added and the container is closed. If no fields are passed the container remains open
45075 * until end() is called.
45076 * @param {Object} config The config to pass to the Layout
45077 * @param {Field} field1 (optional)
45078 * @param {Field} field2 (optional)
45079 * @param {Field} etc (optional)
45080 * @return Layout The container object
45082 container : function(c){
45083 var l = new Roo.form.Layout(c);
45085 if(arguments.length > 1){ // duplicate code required because of Opera
45086 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45093 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45094 * @param {Object} container A Roo.form.Layout or subclass of Layout
45095 * @return {Form} this
45097 start : function(c){
45098 // cascade label info
45099 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45100 this.active.stack.push(c);
45101 c.ownerCt = this.active;
45107 * Closes the current open container
45108 * @return {Form} this
45111 if(this.active == this.root){
45114 this.active = this.active.ownerCt;
45119 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45120 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45121 * as the label of the field.
45122 * @param {Field} field1
45123 * @param {Field} field2 (optional)
45124 * @param {Field} etc. (optional)
45125 * @return {Form} this
45128 this.active.stack.push.apply(this.active.stack, arguments);
45129 this.allItems.push.apply(this.allItems,arguments);
45131 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45132 if(a[i].isFormField){
45137 Roo.form.Form.superclass.add.apply(this, r);
45147 * Find any element that has been added to a form, using it's ID or name
45148 * This can include framesets, columns etc. along with regular fields..
45149 * @param {String} id - id or name to find.
45151 * @return {Element} e - or false if nothing found.
45153 findbyId : function(id)
45159 Roo.each(this.allItems, function(f){
45160 if (f.id == id || f.name == id ){
45171 * Render this form into the passed container. This should only be called once!
45172 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45173 * @return {Form} this
45175 render : function(ct)
45181 var o = this.autoCreate || {
45183 method : this.method || 'POST',
45184 id : this.id || Roo.id()
45186 this.initEl(ct.createChild(o));
45188 this.root.render(this.el);
45192 this.items.each(function(f){
45193 f.render('x-form-el-'+f.id);
45196 if(this.buttons.length > 0){
45197 // tables are required to maintain order and for correct IE layout
45198 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45199 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45200 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45202 var tr = tb.getElementsByTagName('tr')[0];
45203 for(var i = 0, len = this.buttons.length; i < len; i++) {
45204 var b = this.buttons[i];
45205 var td = document.createElement('td');
45206 td.className = 'x-form-btn-td';
45207 b.render(tr.appendChild(td));
45210 if(this.monitorValid){ // initialize after render
45211 this.startMonitoring();
45213 this.fireEvent('rendered', this);
45218 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45219 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45220 * object or a valid Roo.DomHelper element config
45221 * @param {Function} handler The function called when the button is clicked
45222 * @param {Object} scope (optional) The scope of the handler function
45223 * @return {Roo.Button}
45225 addButton : function(config, handler, scope){
45229 minWidth: this.minButtonWidth,
45232 if(typeof config == "string"){
45235 Roo.apply(bc, config);
45237 var btn = new Roo.Button(null, bc);
45238 this.buttons.push(btn);
45243 * Adds a series of form elements (using the xtype property as the factory method.
45244 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45245 * @param {Object} config
45248 addxtype : function()
45250 var ar = Array.prototype.slice.call(arguments, 0);
45252 for(var i = 0; i < ar.length; i++) {
45254 continue; // skip -- if this happends something invalid got sent, we
45255 // should ignore it, as basically that interface element will not show up
45256 // and that should be pretty obvious!!
45259 if (Roo.form[ar[i].xtype]) {
45261 var fe = Roo.factory(ar[i], Roo.form);
45267 fe.store.form = this;
45272 this.allItems.push(fe);
45273 if (fe.items && fe.addxtype) {
45274 fe.addxtype.apply(fe, fe.items);
45284 // console.log('adding ' + ar[i].xtype);
45286 if (ar[i].xtype == 'Button') {
45287 //console.log('adding button');
45288 //console.log(ar[i]);
45289 this.addButton(ar[i]);
45290 this.allItems.push(fe);
45294 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45295 alert('end is not supported on xtype any more, use items');
45297 // //console.log('adding end');
45305 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45306 * option "monitorValid"
45308 startMonitoring : function(){
45311 Roo.TaskMgr.start({
45312 run : this.bindHandler,
45313 interval : this.monitorPoll || 200,
45320 * Stops monitoring of the valid state of this form
45322 stopMonitoring : function(){
45323 this.bound = false;
45327 bindHandler : function(){
45329 return false; // stops binding
45332 this.items.each(function(f){
45333 if(!f.isValid(true)){
45338 for(var i = 0, len = this.buttons.length; i < len; i++){
45339 var btn = this.buttons[i];
45340 if(btn.formBind === true && btn.disabled === valid){
45341 btn.setDisabled(!valid);
45344 this.fireEvent('clientvalidation', this, valid);
45358 Roo.Form = Roo.form.Form;
45361 * Ext JS Library 1.1.1
45362 * Copyright(c) 2006-2007, Ext JS, LLC.
45364 * Originally Released Under LGPL - original licence link has changed is not relivant.
45367 * <script type="text/javascript">
45370 // as we use this in bootstrap.
45371 Roo.namespace('Roo.form');
45373 * @class Roo.form.Action
45374 * Internal Class used to handle form actions
45376 * @param {Roo.form.BasicForm} el The form element or its id
45377 * @param {Object} config Configuration options
45382 // define the action interface
45383 Roo.form.Action = function(form, options){
45385 this.options = options || {};
45388 * Client Validation Failed
45391 Roo.form.Action.CLIENT_INVALID = 'client';
45393 * Server Validation Failed
45396 Roo.form.Action.SERVER_INVALID = 'server';
45398 * Connect to Server Failed
45401 Roo.form.Action.CONNECT_FAILURE = 'connect';
45403 * Reading Data from Server Failed
45406 Roo.form.Action.LOAD_FAILURE = 'load';
45408 Roo.form.Action.prototype = {
45410 failureType : undefined,
45411 response : undefined,
45412 result : undefined,
45414 // interface method
45415 run : function(options){
45419 // interface method
45420 success : function(response){
45424 // interface method
45425 handleResponse : function(response){
45429 // default connection failure
45430 failure : function(response){
45432 this.response = response;
45433 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45434 this.form.afterAction(this, false);
45437 processResponse : function(response){
45438 this.response = response;
45439 if(!response.responseText){
45442 this.result = this.handleResponse(response);
45443 return this.result;
45446 // utility functions used internally
45447 getUrl : function(appendParams){
45448 var url = this.options.url || this.form.url || this.form.el.dom.action;
45450 var p = this.getParams();
45452 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45458 getMethod : function(){
45459 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45462 getParams : function(){
45463 var bp = this.form.baseParams;
45464 var p = this.options.params;
45466 if(typeof p == "object"){
45467 p = Roo.urlEncode(Roo.applyIf(p, bp));
45468 }else if(typeof p == 'string' && bp){
45469 p += '&' + Roo.urlEncode(bp);
45472 p = Roo.urlEncode(bp);
45477 createCallback : function(){
45479 success: this.success,
45480 failure: this.failure,
45482 timeout: (this.form.timeout*1000),
45483 upload: this.form.fileUpload ? this.success : undefined
45488 Roo.form.Action.Submit = function(form, options){
45489 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45492 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45495 haveProgress : false,
45496 uploadComplete : false,
45498 // uploadProgress indicator.
45499 uploadProgress : function()
45501 if (!this.form.progressUrl) {
45505 if (!this.haveProgress) {
45506 Roo.MessageBox.progress("Uploading", "Uploading");
45508 if (this.uploadComplete) {
45509 Roo.MessageBox.hide();
45513 this.haveProgress = true;
45515 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45517 var c = new Roo.data.Connection();
45519 url : this.form.progressUrl,
45524 success : function(req){
45525 //console.log(data);
45529 rdata = Roo.decode(req.responseText)
45531 Roo.log("Invalid data from server..");
45535 if (!rdata || !rdata.success) {
45537 Roo.MessageBox.alert(Roo.encode(rdata));
45540 var data = rdata.data;
45542 if (this.uploadComplete) {
45543 Roo.MessageBox.hide();
45548 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45549 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45552 this.uploadProgress.defer(2000,this);
45555 failure: function(data) {
45556 Roo.log('progress url failed ');
45567 // run get Values on the form, so it syncs any secondary forms.
45568 this.form.getValues();
45570 var o = this.options;
45571 var method = this.getMethod();
45572 var isPost = method == 'POST';
45573 if(o.clientValidation === false || this.form.isValid()){
45575 if (this.form.progressUrl) {
45576 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45577 (new Date() * 1) + '' + Math.random());
45582 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45583 form:this.form.el.dom,
45584 url:this.getUrl(!isPost),
45586 params:isPost ? this.getParams() : null,
45587 isUpload: this.form.fileUpload
45590 this.uploadProgress();
45592 }else if (o.clientValidation !== false){ // client validation failed
45593 this.failureType = Roo.form.Action.CLIENT_INVALID;
45594 this.form.afterAction(this, false);
45598 success : function(response)
45600 this.uploadComplete= true;
45601 if (this.haveProgress) {
45602 Roo.MessageBox.hide();
45606 var result = this.processResponse(response);
45607 if(result === true || result.success){
45608 this.form.afterAction(this, true);
45612 this.form.markInvalid(result.errors);
45613 this.failureType = Roo.form.Action.SERVER_INVALID;
45615 this.form.afterAction(this, false);
45617 failure : function(response)
45619 this.uploadComplete= true;
45620 if (this.haveProgress) {
45621 Roo.MessageBox.hide();
45624 this.response = response;
45625 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45626 this.form.afterAction(this, false);
45629 handleResponse : function(response){
45630 if(this.form.errorReader){
45631 var rs = this.form.errorReader.read(response);
45634 for(var i = 0, len = rs.records.length; i < len; i++) {
45635 var r = rs.records[i];
45636 errors[i] = r.data;
45639 if(errors.length < 1){
45643 success : rs.success,
45649 ret = Roo.decode(response.responseText);
45653 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45663 Roo.form.Action.Load = function(form, options){
45664 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45665 this.reader = this.form.reader;
45668 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45673 Roo.Ajax.request(Roo.apply(
45674 this.createCallback(), {
45675 method:this.getMethod(),
45676 url:this.getUrl(false),
45677 params:this.getParams()
45681 success : function(response){
45683 var result = this.processResponse(response);
45684 if(result === true || !result.success || !result.data){
45685 this.failureType = Roo.form.Action.LOAD_FAILURE;
45686 this.form.afterAction(this, false);
45689 this.form.clearInvalid();
45690 this.form.setValues(result.data);
45691 this.form.afterAction(this, true);
45694 handleResponse : function(response){
45695 if(this.form.reader){
45696 var rs = this.form.reader.read(response);
45697 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45699 success : rs.success,
45703 return Roo.decode(response.responseText);
45707 Roo.form.Action.ACTION_TYPES = {
45708 'load' : Roo.form.Action.Load,
45709 'submit' : Roo.form.Action.Submit
45712 * Ext JS Library 1.1.1
45713 * Copyright(c) 2006-2007, Ext JS, LLC.
45715 * Originally Released Under LGPL - original licence link has changed is not relivant.
45718 * <script type="text/javascript">
45722 * @class Roo.form.Layout
45723 * @extends Roo.Component
45724 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45726 * @param {Object} config Configuration options
45728 Roo.form.Layout = function(config){
45730 if (config.items) {
45731 xitems = config.items;
45732 delete config.items;
45734 Roo.form.Layout.superclass.constructor.call(this, config);
45736 Roo.each(xitems, this.addxtype, this);
45740 Roo.extend(Roo.form.Layout, Roo.Component, {
45742 * @cfg {String/Object} autoCreate
45743 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45746 * @cfg {String/Object/Function} style
45747 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45748 * a function which returns such a specification.
45751 * @cfg {String} labelAlign
45752 * Valid values are "left," "top" and "right" (defaults to "left")
45755 * @cfg {Number} labelWidth
45756 * Fixed width in pixels of all field labels (defaults to undefined)
45759 * @cfg {Boolean} clear
45760 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45764 * @cfg {String} labelSeparator
45765 * The separator to use after field labels (defaults to ':')
45767 labelSeparator : ':',
45769 * @cfg {Boolean} hideLabels
45770 * True to suppress the display of field labels in this layout (defaults to false)
45772 hideLabels : false,
45775 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45780 onRender : function(ct, position){
45781 if(this.el){ // from markup
45782 this.el = Roo.get(this.el);
45783 }else { // generate
45784 var cfg = this.getAutoCreate();
45785 this.el = ct.createChild(cfg, position);
45788 this.el.applyStyles(this.style);
45790 if(this.labelAlign){
45791 this.el.addClass('x-form-label-'+this.labelAlign);
45793 if(this.hideLabels){
45794 this.labelStyle = "display:none";
45795 this.elementStyle = "padding-left:0;";
45797 if(typeof this.labelWidth == 'number'){
45798 this.labelStyle = "width:"+this.labelWidth+"px;";
45799 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45801 if(this.labelAlign == 'top'){
45802 this.labelStyle = "width:auto;";
45803 this.elementStyle = "padding-left:0;";
45806 var stack = this.stack;
45807 var slen = stack.length;
45809 if(!this.fieldTpl){
45810 var t = new Roo.Template(
45811 '<div class="x-form-item {5}">',
45812 '<label for="{0}" style="{2}">{1}{4}</label>',
45813 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45815 '</div><div class="x-form-clear-left"></div>'
45817 t.disableFormats = true;
45819 Roo.form.Layout.prototype.fieldTpl = t;
45821 for(var i = 0; i < slen; i++) {
45822 if(stack[i].isFormField){
45823 this.renderField(stack[i]);
45825 this.renderComponent(stack[i]);
45830 this.el.createChild({cls:'x-form-clear'});
45835 renderField : function(f){
45836 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45839 f.labelStyle||this.labelStyle||'', //2
45840 this.elementStyle||'', //3
45841 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45842 f.itemCls||this.itemCls||'' //5
45843 ], true).getPrevSibling());
45847 renderComponent : function(c){
45848 c.render(c.isLayout ? this.el : this.el.createChild());
45851 * Adds a object form elements (using the xtype property as the factory method.)
45852 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45853 * @param {Object} config
45855 addxtype : function(o)
45857 // create the lement.
45858 o.form = this.form;
45859 var fe = Roo.factory(o, Roo.form);
45860 this.form.allItems.push(fe);
45861 this.stack.push(fe);
45863 if (fe.isFormField) {
45864 this.form.items.add(fe);
45872 * @class Roo.form.Column
45873 * @extends Roo.form.Layout
45874 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45876 * @param {Object} config Configuration options
45878 Roo.form.Column = function(config){
45879 Roo.form.Column.superclass.constructor.call(this, config);
45882 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45884 * @cfg {Number/String} width
45885 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45888 * @cfg {String/Object} autoCreate
45889 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45893 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45896 onRender : function(ct, position){
45897 Roo.form.Column.superclass.onRender.call(this, ct, position);
45899 this.el.setWidth(this.width);
45906 * @class Roo.form.Row
45907 * @extends Roo.form.Layout
45908 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45910 * @param {Object} config Configuration options
45914 Roo.form.Row = function(config){
45915 Roo.form.Row.superclass.constructor.call(this, config);
45918 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45920 * @cfg {Number/String} width
45921 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45924 * @cfg {Number/String} height
45925 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45927 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45931 onRender : function(ct, position){
45932 //console.log('row render');
45934 var t = new Roo.Template(
45935 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45936 '<label for="{0}" style="{2}">{1}{4}</label>',
45937 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45941 t.disableFormats = true;
45943 Roo.form.Layout.prototype.rowTpl = t;
45945 this.fieldTpl = this.rowTpl;
45947 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45948 var labelWidth = 100;
45950 if ((this.labelAlign != 'top')) {
45951 if (typeof this.labelWidth == 'number') {
45952 labelWidth = this.labelWidth
45954 this.padWidth = 20 + labelWidth;
45958 Roo.form.Column.superclass.onRender.call(this, ct, position);
45960 this.el.setWidth(this.width);
45963 this.el.setHeight(this.height);
45968 renderField : function(f){
45969 f.fieldEl = this.fieldTpl.append(this.el, [
45970 f.id, f.fieldLabel,
45971 f.labelStyle||this.labelStyle||'',
45972 this.elementStyle||'',
45973 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45974 f.itemCls||this.itemCls||'',
45975 f.width ? f.width + this.padWidth : 160 + this.padWidth
45982 * @class Roo.form.FieldSet
45983 * @extends Roo.form.Layout
45984 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45986 * @param {Object} config Configuration options
45988 Roo.form.FieldSet = function(config){
45989 Roo.form.FieldSet.superclass.constructor.call(this, config);
45992 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45994 * @cfg {String} legend
45995 * The text to display as the legend for the FieldSet (defaults to '')
45998 * @cfg {String/Object} autoCreate
45999 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46003 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46006 onRender : function(ct, position){
46007 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46009 this.setLegend(this.legend);
46014 setLegend : function(text){
46016 this.el.child('legend').update(text);
46021 * Ext JS Library 1.1.1
46022 * Copyright(c) 2006-2007, Ext JS, LLC.
46024 * Originally Released Under LGPL - original licence link has changed is not relivant.
46027 * <script type="text/javascript">
46030 * @class Roo.form.VTypes
46031 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46034 Roo.form.VTypes = function(){
46035 // closure these in so they are only created once.
46036 var alpha = /^[a-zA-Z_]+$/;
46037 var alphanum = /^[a-zA-Z0-9_]+$/;
46038 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46039 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46041 // All these messages and functions are configurable
46044 * The function used to validate email addresses
46045 * @param {String} value The email address
46047 'email' : function(v){
46048 return email.test(v);
46051 * The error text to display when the email validation function returns false
46054 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46056 * The keystroke filter mask to be applied on email input
46059 'emailMask' : /[a-z0-9_\.\-@]/i,
46062 * The function used to validate URLs
46063 * @param {String} value The URL
46065 'url' : function(v){
46066 return url.test(v);
46069 * The error text to display when the url validation function returns false
46072 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46075 * The function used to validate alpha values
46076 * @param {String} value The value
46078 'alpha' : function(v){
46079 return alpha.test(v);
46082 * The error text to display when the alpha validation function returns false
46085 'alphaText' : 'This field should only contain letters and _',
46087 * The keystroke filter mask to be applied on alpha input
46090 'alphaMask' : /[a-z_]/i,
46093 * The function used to validate alphanumeric values
46094 * @param {String} value The value
46096 'alphanum' : function(v){
46097 return alphanum.test(v);
46100 * The error text to display when the alphanumeric validation function returns false
46103 'alphanumText' : 'This field should only contain letters, numbers and _',
46105 * The keystroke filter mask to be applied on alphanumeric input
46108 'alphanumMask' : /[a-z0-9_]/i
46110 }();//<script type="text/javascript">
46113 * @class Roo.form.FCKeditor
46114 * @extends Roo.form.TextArea
46115 * Wrapper around the FCKEditor http://www.fckeditor.net
46117 * Creates a new FCKeditor
46118 * @param {Object} config Configuration options
46120 Roo.form.FCKeditor = function(config){
46121 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46124 * @event editorinit
46125 * Fired when the editor is initialized - you can add extra handlers here..
46126 * @param {FCKeditor} this
46127 * @param {Object} the FCK object.
46134 Roo.form.FCKeditor.editors = { };
46135 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46137 //defaultAutoCreate : {
46138 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46142 * @cfg {Object} fck options - see fck manual for details.
46147 * @cfg {Object} fck toolbar set (Basic or Default)
46149 toolbarSet : 'Basic',
46151 * @cfg {Object} fck BasePath
46153 basePath : '/fckeditor/',
46161 onRender : function(ct, position)
46164 this.defaultAutoCreate = {
46166 style:"width:300px;height:60px;",
46167 autocomplete: "off"
46170 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46173 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46174 if(this.preventScrollbars){
46175 this.el.setStyle("overflow", "hidden");
46177 this.el.setHeight(this.growMin);
46180 //console.log('onrender' + this.getId() );
46181 Roo.form.FCKeditor.editors[this.getId()] = this;
46184 this.replaceTextarea() ;
46188 getEditor : function() {
46189 return this.fckEditor;
46192 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46193 * @param {Mixed} value The value to set
46197 setValue : function(value)
46199 //console.log('setValue: ' + value);
46201 if(typeof(value) == 'undefined') { // not sure why this is happending...
46204 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46206 //if(!this.el || !this.getEditor()) {
46207 // this.value = value;
46208 //this.setValue.defer(100,this,[value]);
46212 if(!this.getEditor()) {
46216 this.getEditor().SetData(value);
46223 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46224 * @return {Mixed} value The field value
46226 getValue : function()
46229 if (this.frame && this.frame.dom.style.display == 'none') {
46230 return Roo.form.FCKeditor.superclass.getValue.call(this);
46233 if(!this.el || !this.getEditor()) {
46235 // this.getValue.defer(100,this);
46240 var value=this.getEditor().GetData();
46241 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46242 return Roo.form.FCKeditor.superclass.getValue.call(this);
46248 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46249 * @return {Mixed} value The field value
46251 getRawValue : function()
46253 if (this.frame && this.frame.dom.style.display == 'none') {
46254 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46257 if(!this.el || !this.getEditor()) {
46258 //this.getRawValue.defer(100,this);
46265 var value=this.getEditor().GetData();
46266 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46267 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46271 setSize : function(w,h) {
46275 //if (this.frame && this.frame.dom.style.display == 'none') {
46276 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46279 //if(!this.el || !this.getEditor()) {
46280 // this.setSize.defer(100,this, [w,h]);
46286 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46288 this.frame.dom.setAttribute('width', w);
46289 this.frame.dom.setAttribute('height', h);
46290 this.frame.setSize(w,h);
46294 toggleSourceEdit : function(value) {
46298 this.el.dom.style.display = value ? '' : 'none';
46299 this.frame.dom.style.display = value ? 'none' : '';
46304 focus: function(tag)
46306 if (this.frame.dom.style.display == 'none') {
46307 return Roo.form.FCKeditor.superclass.focus.call(this);
46309 if(!this.el || !this.getEditor()) {
46310 this.focus.defer(100,this, [tag]);
46317 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46318 this.getEditor().Focus();
46320 if (!this.getEditor().Selection.GetSelection()) {
46321 this.focus.defer(100,this, [tag]);
46326 var r = this.getEditor().EditorDocument.createRange();
46327 r.setStart(tgs[0],0);
46328 r.setEnd(tgs[0],0);
46329 this.getEditor().Selection.GetSelection().removeAllRanges();
46330 this.getEditor().Selection.GetSelection().addRange(r);
46331 this.getEditor().Focus();
46338 replaceTextarea : function()
46340 if ( document.getElementById( this.getId() + '___Frame' ) )
46342 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46344 // We must check the elements firstly using the Id and then the name.
46345 var oTextarea = document.getElementById( this.getId() );
46347 var colElementsByName = document.getElementsByName( this.getId() ) ;
46349 oTextarea.style.display = 'none' ;
46351 if ( oTextarea.tabIndex ) {
46352 this.TabIndex = oTextarea.tabIndex ;
46355 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46356 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46357 this.frame = Roo.get(this.getId() + '___Frame')
46360 _getConfigHtml : function()
46364 for ( var o in this.fckconfig ) {
46365 sConfig += sConfig.length > 0 ? '&' : '';
46366 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46369 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46373 _getIFrameHtml : function()
46375 var sFile = 'fckeditor.html' ;
46376 /* no idea what this is about..
46379 if ( (/fcksource=true/i).test( window.top.location.search ) )
46380 sFile = 'fckeditor.original.html' ;
46385 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46386 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46389 var html = '<iframe id="' + this.getId() +
46390 '___Frame" src="' + sLink +
46391 '" width="' + this.width +
46392 '" height="' + this.height + '"' +
46393 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46394 ' frameborder="0" scrolling="no"></iframe>' ;
46399 _insertHtmlBefore : function( html, element )
46401 if ( element.insertAdjacentHTML ) {
46403 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46405 var oRange = document.createRange() ;
46406 oRange.setStartBefore( element ) ;
46407 var oFragment = oRange.createContextualFragment( html );
46408 element.parentNode.insertBefore( oFragment, element ) ;
46421 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46423 function FCKeditor_OnComplete(editorInstance){
46424 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46425 f.fckEditor = editorInstance;
46426 //console.log("loaded");
46427 f.fireEvent('editorinit', f, editorInstance);
46447 //<script type="text/javascript">
46449 * @class Roo.form.GridField
46450 * @extends Roo.form.Field
46451 * Embed a grid (or editable grid into a form)
46454 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46456 * xgrid.store = Roo.data.Store
46457 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46458 * xgrid.store.reader = Roo.data.JsonReader
46462 * Creates a new GridField
46463 * @param {Object} config Configuration options
46465 Roo.form.GridField = function(config){
46466 Roo.form.GridField.superclass.constructor.call(this, config);
46470 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46472 * @cfg {Number} width - used to restrict width of grid..
46476 * @cfg {Number} height - used to restrict height of grid..
46480 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46486 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46487 * {tag: "input", type: "checkbox", autocomplete: "off"})
46489 // defaultAutoCreate : { tag: 'div' },
46490 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46492 * @cfg {String} addTitle Text to include for adding a title.
46496 onResize : function(){
46497 Roo.form.Field.superclass.onResize.apply(this, arguments);
46500 initEvents : function(){
46501 // Roo.form.Checkbox.superclass.initEvents.call(this);
46502 // has no events...
46507 getResizeEl : function(){
46511 getPositionEl : function(){
46516 onRender : function(ct, position){
46518 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46519 var style = this.style;
46522 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46523 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46524 this.viewEl = this.wrap.createChild({ tag: 'div' });
46526 this.viewEl.applyStyles(style);
46529 this.viewEl.setWidth(this.width);
46532 this.viewEl.setHeight(this.height);
46534 //if(this.inputValue !== undefined){
46535 //this.setValue(this.value);
46538 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46541 this.grid.render();
46542 this.grid.getDataSource().on('remove', this.refreshValue, this);
46543 this.grid.getDataSource().on('update', this.refreshValue, this);
46544 this.grid.on('afteredit', this.refreshValue, this);
46550 * Sets the value of the item.
46551 * @param {String} either an object or a string..
46553 setValue : function(v){
46555 v = v || []; // empty set..
46556 // this does not seem smart - it really only affects memoryproxy grids..
46557 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46558 var ds = this.grid.getDataSource();
46559 // assumes a json reader..
46561 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46562 ds.loadData( data);
46564 // clear selection so it does not get stale.
46565 if (this.grid.sm) {
46566 this.grid.sm.clearSelections();
46569 Roo.form.GridField.superclass.setValue.call(this, v);
46570 this.refreshValue();
46571 // should load data in the grid really....
46575 refreshValue: function() {
46577 this.grid.getDataSource().each(function(r) {
46580 this.el.dom.value = Roo.encode(val);
46588 * Ext JS Library 1.1.1
46589 * Copyright(c) 2006-2007, Ext JS, LLC.
46591 * Originally Released Under LGPL - original licence link has changed is not relivant.
46594 * <script type="text/javascript">
46597 * @class Roo.form.DisplayField
46598 * @extends Roo.form.Field
46599 * A generic Field to display non-editable data.
46601 * Creates a new Display Field item.
46602 * @param {Object} config Configuration options
46604 Roo.form.DisplayField = function(config){
46605 Roo.form.DisplayField.superclass.constructor.call(this, config);
46609 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46610 inputType: 'hidden',
46616 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46618 focusClass : undefined,
46620 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46622 fieldClass: 'x-form-field',
46625 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46627 valueRenderer: undefined,
46631 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46632 * {tag: "input", type: "checkbox", autocomplete: "off"})
46635 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46637 onResize : function(){
46638 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46642 initEvents : function(){
46643 // Roo.form.Checkbox.superclass.initEvents.call(this);
46644 // has no events...
46649 getResizeEl : function(){
46653 getPositionEl : function(){
46658 onRender : function(ct, position){
46660 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46661 //if(this.inputValue !== undefined){
46662 this.wrap = this.el.wrap();
46664 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46666 if (this.bodyStyle) {
46667 this.viewEl.applyStyles(this.bodyStyle);
46669 //this.viewEl.setStyle('padding', '2px');
46671 this.setValue(this.value);
46676 initValue : Roo.emptyFn,
46681 onClick : function(){
46686 * Sets the checked state of the checkbox.
46687 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46689 setValue : function(v){
46691 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46692 // this might be called before we have a dom element..
46693 if (!this.viewEl) {
46696 this.viewEl.dom.innerHTML = html;
46697 Roo.form.DisplayField.superclass.setValue.call(this, v);
46707 * @class Roo.form.DayPicker
46708 * @extends Roo.form.Field
46709 * A Day picker show [M] [T] [W] ....
46711 * Creates a new Day Picker
46712 * @param {Object} config Configuration options
46714 Roo.form.DayPicker= function(config){
46715 Roo.form.DayPicker.superclass.constructor.call(this, config);
46719 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46721 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46723 focusClass : undefined,
46725 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46727 fieldClass: "x-form-field",
46730 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46731 * {tag: "input", type: "checkbox", autocomplete: "off"})
46733 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46736 actionMode : 'viewEl',
46740 inputType : 'hidden',
46743 inputElement: false, // real input element?
46744 basedOn: false, // ????
46746 isFormField: true, // not sure where this is needed!!!!
46748 onResize : function(){
46749 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46750 if(!this.boxLabel){
46751 this.el.alignTo(this.wrap, 'c-c');
46755 initEvents : function(){
46756 Roo.form.Checkbox.superclass.initEvents.call(this);
46757 this.el.on("click", this.onClick, this);
46758 this.el.on("change", this.onClick, this);
46762 getResizeEl : function(){
46766 getPositionEl : function(){
46772 onRender : function(ct, position){
46773 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46775 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46777 var r1 = '<table><tr>';
46778 var r2 = '<tr class="x-form-daypick-icons">';
46779 for (var i=0; i < 7; i++) {
46780 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46781 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46784 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46785 viewEl.select('img').on('click', this.onClick, this);
46786 this.viewEl = viewEl;
46789 // this will not work on Chrome!!!
46790 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46791 this.el.on('propertychange', this.setFromHidden, this); //ie
46799 initValue : Roo.emptyFn,
46802 * Returns the checked state of the checkbox.
46803 * @return {Boolean} True if checked, else false
46805 getValue : function(){
46806 return this.el.dom.value;
46811 onClick : function(e){
46812 //this.setChecked(!this.checked);
46813 Roo.get(e.target).toggleClass('x-menu-item-checked');
46814 this.refreshValue();
46815 //if(this.el.dom.checked != this.checked){
46816 // this.setValue(this.el.dom.checked);
46821 refreshValue : function()
46824 this.viewEl.select('img',true).each(function(e,i,n) {
46825 val += e.is(".x-menu-item-checked") ? String(n) : '';
46827 this.setValue(val, true);
46831 * Sets the checked state of the checkbox.
46832 * On is always based on a string comparison between inputValue and the param.
46833 * @param {Boolean/String} value - the value to set
46834 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46836 setValue : function(v,suppressEvent){
46837 if (!this.el.dom) {
46840 var old = this.el.dom.value ;
46841 this.el.dom.value = v;
46842 if (suppressEvent) {
46846 // update display..
46847 this.viewEl.select('img',true).each(function(e,i,n) {
46849 var on = e.is(".x-menu-item-checked");
46850 var newv = v.indexOf(String(n)) > -1;
46852 e.toggleClass('x-menu-item-checked');
46858 this.fireEvent('change', this, v, old);
46863 // handle setting of hidden value by some other method!!?!?
46864 setFromHidden: function()
46869 //console.log("SET FROM HIDDEN");
46870 //alert('setFrom hidden');
46871 this.setValue(this.el.dom.value);
46874 onDestroy : function()
46877 Roo.get(this.viewEl).remove();
46880 Roo.form.DayPicker.superclass.onDestroy.call(this);
46884 * RooJS Library 1.1.1
46885 * Copyright(c) 2008-2011 Alan Knowles
46892 * @class Roo.form.ComboCheck
46893 * @extends Roo.form.ComboBox
46894 * A combobox for multiple select items.
46896 * FIXME - could do with a reset button..
46899 * Create a new ComboCheck
46900 * @param {Object} config Configuration options
46902 Roo.form.ComboCheck = function(config){
46903 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46904 // should verify some data...
46906 // hiddenName = required..
46907 // displayField = required
46908 // valudField == required
46909 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46911 Roo.each(req, function(e) {
46912 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46913 throw "Roo.form.ComboCheck : missing value for: " + e;
46920 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46925 selectedClass: 'x-menu-item-checked',
46928 onRender : function(ct, position){
46934 var cls = 'x-combo-list';
46937 this.tpl = new Roo.Template({
46938 html : '<div class="'+cls+'-item x-menu-check-item">' +
46939 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46940 '<span>{' + this.displayField + '}</span>' +
46947 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46948 this.view.singleSelect = false;
46949 this.view.multiSelect = true;
46950 this.view.toggleSelect = true;
46951 this.pageTb.add(new Roo.Toolbar.Fill(), {
46954 handler: function()
46961 onViewOver : function(e, t){
46967 onViewClick : function(doFocus,index){
46971 select: function () {
46972 //Roo.log("SELECT CALLED");
46975 selectByValue : function(xv, scrollIntoView){
46976 var ar = this.getValueArray();
46979 Roo.each(ar, function(v) {
46980 if(v === undefined || v === null){
46983 var r = this.findRecord(this.valueField, v);
46985 sels.push(this.store.indexOf(r))
46989 this.view.select(sels);
46995 onSelect : function(record, index){
46996 // Roo.log("onselect Called");
46997 // this is only called by the clear button now..
46998 this.view.clearSelections();
46999 this.setValue('[]');
47000 if (this.value != this.valueBefore) {
47001 this.fireEvent('change', this, this.value, this.valueBefore);
47002 this.valueBefore = this.value;
47005 getValueArray : function()
47010 //Roo.log(this.value);
47011 if (typeof(this.value) == 'undefined') {
47014 var ar = Roo.decode(this.value);
47015 return ar instanceof Array ? ar : []; //?? valid?
47018 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47023 expand : function ()
47026 Roo.form.ComboCheck.superclass.expand.call(this);
47027 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47028 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47033 collapse : function(){
47034 Roo.form.ComboCheck.superclass.collapse.call(this);
47035 var sl = this.view.getSelectedIndexes();
47036 var st = this.store;
47040 Roo.each(sl, function(i) {
47042 nv.push(r.get(this.valueField));
47044 this.setValue(Roo.encode(nv));
47045 if (this.value != this.valueBefore) {
47047 this.fireEvent('change', this, this.value, this.valueBefore);
47048 this.valueBefore = this.value;
47053 setValue : function(v){
47057 var vals = this.getValueArray();
47059 Roo.each(vals, function(k) {
47060 var r = this.findRecord(this.valueField, k);
47062 tv.push(r.data[this.displayField]);
47063 }else if(this.valueNotFoundText !== undefined){
47064 tv.push( this.valueNotFoundText );
47069 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47070 this.hiddenField.value = v;
47076 * Ext JS Library 1.1.1
47077 * Copyright(c) 2006-2007, Ext JS, LLC.
47079 * Originally Released Under LGPL - original licence link has changed is not relivant.
47082 * <script type="text/javascript">
47086 * @class Roo.form.Signature
47087 * @extends Roo.form.Field
47091 * @param {Object} config Configuration options
47094 Roo.form.Signature = function(config){
47095 Roo.form.Signature.superclass.constructor.call(this, config);
47097 this.addEvents({// not in used??
47100 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47101 * @param {Roo.form.Signature} combo This combo box
47106 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47107 * @param {Roo.form.ComboBox} combo This combo box
47108 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47114 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47116 * @cfg {Object} labels Label to use when rendering a form.
47120 * confirm : "Confirm"
47125 confirm : "Confirm"
47128 * @cfg {Number} width The signature panel width (defaults to 300)
47132 * @cfg {Number} height The signature panel height (defaults to 100)
47136 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47138 allowBlank : false,
47141 // {Object} signPanel The signature SVG panel element (defaults to {})
47143 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47144 isMouseDown : false,
47145 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47146 isConfirmed : false,
47147 // {String} signatureTmp SVG mapping string (defaults to empty string)
47151 defaultAutoCreate : { // modified by initCompnoent..
47157 onRender : function(ct, position){
47159 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47161 this.wrap = this.el.wrap({
47162 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47165 this.createToolbar(this);
47166 this.signPanel = this.wrap.createChild({
47168 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47172 this.svgID = Roo.id();
47173 this.svgEl = this.signPanel.createChild({
47174 xmlns : 'http://www.w3.org/2000/svg',
47176 id : this.svgID + "-svg",
47178 height: this.height,
47179 viewBox: '0 0 '+this.width+' '+this.height,
47183 id: this.svgID + "-svg-r",
47185 height: this.height,
47190 id: this.svgID + "-svg-l",
47192 y1: (this.height*0.8), // start set the line in 80% of height
47193 x2: this.width, // end
47194 y2: (this.height*0.8), // end set the line in 80% of height
47196 'stroke-width': "1",
47197 'stroke-dasharray': "3",
47198 'shape-rendering': "crispEdges",
47199 'pointer-events': "none"
47203 id: this.svgID + "-svg-p",
47205 'stroke-width': "3",
47207 'pointer-events': 'none'
47212 this.svgBox = this.svgEl.dom.getScreenCTM();
47214 createSVG : function(){
47215 var svg = this.signPanel;
47216 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47219 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47220 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47221 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47222 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47223 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47224 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47225 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47228 isTouchEvent : function(e){
47229 return e.type.match(/^touch/);
47231 getCoords : function (e) {
47232 var pt = this.svgEl.dom.createSVGPoint();
47235 if (this.isTouchEvent(e)) {
47236 pt.x = e.targetTouches[0].clientX
47237 pt.y = e.targetTouches[0].clientY;
47239 var a = this.svgEl.dom.getScreenCTM();
47240 var b = a.inverse();
47241 var mx = pt.matrixTransform(b);
47242 return mx.x + ',' + mx.y;
47244 //mouse event headler
47245 down : function (e) {
47246 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47247 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47249 this.isMouseDown = true;
47251 e.preventDefault();
47253 move : function (e) {
47254 if (this.isMouseDown) {
47255 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47256 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47259 e.preventDefault();
47261 up : function (e) {
47262 this.isMouseDown = false;
47263 var sp = this.signatureTmp.split(' ');
47266 if(!sp[sp.length-2].match(/^L/)){
47270 this.signatureTmp = sp.join(" ");
47273 if(this.getValue() != this.signatureTmp){
47274 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47275 this.isConfirmed = false;
47277 e.preventDefault();
47281 * Protected method that will not generally be called directly. It
47282 * is called when the editor creates its toolbar. Override this method if you need to
47283 * add custom toolbar buttons.
47284 * @param {HtmlEditor} editor
47286 createToolbar : function(editor){
47287 function btn(id, toggle, handler){
47288 var xid = fid + '-'+ id ;
47292 cls : 'x-btn-icon x-edit-'+id,
47293 enableToggle:toggle !== false,
47294 scope: editor, // was editor...
47295 handler:handler||editor.relayBtnCmd,
47296 clickEvent:'mousedown',
47297 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47303 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47307 cls : ' x-signature-btn x-signature-'+id,
47308 scope: editor, // was editor...
47309 handler: this.reset,
47310 clickEvent:'mousedown',
47311 text: this.labels.clear
47318 cls : ' x-signature-btn x-signature-'+id,
47319 scope: editor, // was editor...
47320 handler: this.confirmHandler,
47321 clickEvent:'mousedown',
47322 text: this.labels.confirm
47329 * when user is clicked confirm then show this image.....
47331 * @return {String} Image Data URI
47333 getImageDataURI : function(){
47334 var svg = this.svgEl.dom.parentNode.innerHTML;
47335 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47340 * @return {Boolean} this.isConfirmed
47342 getConfirmed : function(){
47343 return this.isConfirmed;
47347 * @return {Number} this.width
47349 getWidth : function(){
47354 * @return {Number} this.height
47356 getHeight : function(){
47357 return this.height;
47360 getSignature : function(){
47361 return this.signatureTmp;
47364 reset : function(){
47365 this.signatureTmp = '';
47366 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47367 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47368 this.isConfirmed = false;
47369 Roo.form.Signature.superclass.reset.call(this);
47371 setSignature : function(s){
47372 this.signatureTmp = s;
47373 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47374 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47376 this.isConfirmed = false;
47377 Roo.form.Signature.superclass.reset.call(this);
47380 // Roo.log(this.signPanel.dom.contentWindow.up())
47383 setConfirmed : function(){
47387 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47390 confirmHandler : function(){
47391 if(!this.getSignature()){
47395 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47396 this.setValue(this.getSignature());
47397 this.isConfirmed = true;
47399 this.fireEvent('confirm', this);
47402 // Subclasses should provide the validation implementation by overriding this
47403 validateValue : function(value){
47404 if(this.allowBlank){
47408 if(this.isConfirmed){
47415 * Ext JS Library 1.1.1
47416 * Copyright(c) 2006-2007, Ext JS, LLC.
47418 * Originally Released Under LGPL - original licence link has changed is not relivant.
47421 * <script type="text/javascript">
47426 * @class Roo.form.ComboBox
47427 * @extends Roo.form.TriggerField
47428 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47430 * Create a new ComboBox.
47431 * @param {Object} config Configuration options
47433 Roo.form.Select = function(config){
47434 Roo.form.Select.superclass.constructor.call(this, config);
47438 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47440 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47443 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47444 * rendering into an Roo.Editor, defaults to false)
47447 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47448 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47451 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47454 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47455 * the dropdown list (defaults to undefined, with no header element)
47459 * @cfg {String/Roo.Template} tpl The template to use to render the output
47463 defaultAutoCreate : {tag: "select" },
47465 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47467 listWidth: undefined,
47469 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47470 * mode = 'remote' or 'text' if mode = 'local')
47472 displayField: undefined,
47474 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47475 * mode = 'remote' or 'value' if mode = 'local').
47476 * Note: use of a valueField requires the user make a selection
47477 * in order for a value to be mapped.
47479 valueField: undefined,
47483 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47484 * field's data value (defaults to the underlying DOM element's name)
47486 hiddenName: undefined,
47488 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47492 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47494 selectedClass: 'x-combo-selected',
47496 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47497 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47498 * which displays a downward arrow icon).
47500 triggerClass : 'x-form-arrow-trigger',
47502 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47506 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47507 * anchor positions (defaults to 'tl-bl')
47509 listAlign: 'tl-bl?',
47511 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47515 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47516 * query specified by the allQuery config option (defaults to 'query')
47518 triggerAction: 'query',
47520 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47521 * (defaults to 4, does not apply if editable = false)
47525 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47526 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47530 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47531 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47535 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47536 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47540 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47541 * when editable = true (defaults to false)
47543 selectOnFocus:false,
47545 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47547 queryParam: 'query',
47549 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47550 * when mode = 'remote' (defaults to 'Loading...')
47552 loadingText: 'Loading...',
47554 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47558 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47562 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47563 * traditional select (defaults to true)
47567 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47571 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47575 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47576 * listWidth has a higher value)
47580 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47581 * allow the user to set arbitrary text into the field (defaults to false)
47583 forceSelection:false,
47585 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47586 * if typeAhead = true (defaults to 250)
47588 typeAheadDelay : 250,
47590 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47591 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47593 valueNotFoundText : undefined,
47596 * @cfg {String} defaultValue The value displayed after loading the store.
47601 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47603 blockFocus : false,
47606 * @cfg {Boolean} disableClear Disable showing of clear button.
47608 disableClear : false,
47610 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47612 alwaysQuery : false,
47618 // element that contains real text value.. (when hidden is used..)
47621 onRender : function(ct, position){
47622 Roo.form.Field.prototype.onRender.call(this, ct, position);
47625 this.store.on('beforeload', this.onBeforeLoad, this);
47626 this.store.on('load', this.onLoad, this);
47627 this.store.on('loadexception', this.onLoadException, this);
47628 this.store.load({});
47636 initEvents : function(){
47637 //Roo.form.ComboBox.superclass.initEvents.call(this);
47641 onDestroy : function(){
47644 this.store.un('beforeload', this.onBeforeLoad, this);
47645 this.store.un('load', this.onLoad, this);
47646 this.store.un('loadexception', this.onLoadException, this);
47648 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47652 fireKey : function(e){
47653 if(e.isNavKeyPress() && !this.list.isVisible()){
47654 this.fireEvent("specialkey", this, e);
47659 onResize: function(w, h){
47667 * Allow or prevent the user from directly editing the field text. If false is passed,
47668 * the user will only be able to select from the items defined in the dropdown list. This method
47669 * is the runtime equivalent of setting the 'editable' config option at config time.
47670 * @param {Boolean} value True to allow the user to directly edit the field text
47672 setEditable : function(value){
47677 onBeforeLoad : function(){
47679 Roo.log("Select before load");
47682 this.innerList.update(this.loadingText ?
47683 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47684 //this.restrictHeight();
47685 this.selectedIndex = -1;
47689 onLoad : function(){
47692 var dom = this.el.dom;
47693 dom.innerHTML = '';
47694 var od = dom.ownerDocument;
47696 if (this.emptyText) {
47697 var op = od.createElement('option');
47698 op.setAttribute('value', '');
47699 op.innerHTML = String.format('{0}', this.emptyText);
47700 dom.appendChild(op);
47702 if(this.store.getCount() > 0){
47704 var vf = this.valueField;
47705 var df = this.displayField;
47706 this.store.data.each(function(r) {
47707 // which colmsn to use... testing - cdoe / title..
47708 var op = od.createElement('option');
47709 op.setAttribute('value', r.data[vf]);
47710 op.innerHTML = String.format('{0}', r.data[df]);
47711 dom.appendChild(op);
47713 if (typeof(this.defaultValue != 'undefined')) {
47714 this.setValue(this.defaultValue);
47719 //this.onEmptyResults();
47724 onLoadException : function()
47726 dom.innerHTML = '';
47728 Roo.log("Select on load exception");
47732 Roo.log(this.store.reader.jsonData);
47733 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47734 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47740 onTypeAhead : function(){
47745 onSelect : function(record, index){
47746 Roo.log('on select?');
47748 if(this.fireEvent('beforeselect', this, record, index) !== false){
47749 this.setFromData(index > -1 ? record.data : false);
47751 this.fireEvent('select', this, record, index);
47756 * Returns the currently selected field value or empty string if no value is set.
47757 * @return {String} value The selected value
47759 getValue : function(){
47760 var dom = this.el.dom;
47761 this.value = dom.options[dom.selectedIndex].value;
47767 * Clears any text/value currently set in the field
47769 clearValue : function(){
47771 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47776 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47777 * will be displayed in the field. If the value does not match the data value of an existing item,
47778 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47779 * Otherwise the field will be blank (although the value will still be set).
47780 * @param {String} value The value to match
47782 setValue : function(v){
47783 var d = this.el.dom;
47784 for (var i =0; i < d.options.length;i++) {
47785 if (v == d.options[i].value) {
47786 d.selectedIndex = i;
47794 * @property {Object} the last set data for the element
47799 * Sets the value of the field based on a object which is related to the record format for the store.
47800 * @param {Object} value the value to set as. or false on reset?
47802 setFromData : function(o){
47803 Roo.log('setfrom data?');
47809 reset : function(){
47813 findRecord : function(prop, value){
47818 if(this.store.getCount() > 0){
47819 this.store.each(function(r){
47820 if(r.data[prop] == value){
47830 getName: function()
47832 // returns hidden if it's set..
47833 if (!this.rendered) {return ''};
47834 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47842 onEmptyResults : function(){
47843 Roo.log('empty results');
47848 * Returns true if the dropdown list is expanded, else false.
47850 isExpanded : function(){
47855 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47856 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47857 * @param {String} value The data value of the item to select
47858 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47859 * selected item if it is not currently in view (defaults to true)
47860 * @return {Boolean} True if the value matched an item in the list, else false
47862 selectByValue : function(v, scrollIntoView){
47863 Roo.log('select By Value');
47866 if(v !== undefined && v !== null){
47867 var r = this.findRecord(this.valueField || this.displayField, v);
47869 this.select(this.store.indexOf(r), scrollIntoView);
47877 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47878 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47879 * @param {Number} index The zero-based index of the list item to select
47880 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47881 * selected item if it is not currently in view (defaults to true)
47883 select : function(index, scrollIntoView){
47884 Roo.log('select ');
47887 this.selectedIndex = index;
47888 this.view.select(index);
47889 if(scrollIntoView !== false){
47890 var el = this.view.getNode(index);
47892 this.innerList.scrollChildIntoView(el, false);
47900 validateBlur : function(){
47907 initQuery : function(){
47908 this.doQuery(this.getRawValue());
47912 doForce : function(){
47913 if(this.el.dom.value.length > 0){
47914 this.el.dom.value =
47915 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47921 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47922 * query allowing the query action to be canceled if needed.
47923 * @param {String} query The SQL query to execute
47924 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47925 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47926 * saved in the current store (defaults to false)
47928 doQuery : function(q, forceAll){
47930 Roo.log('doQuery?');
47931 if(q === undefined || q === null){
47936 forceAll: forceAll,
47940 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47944 forceAll = qe.forceAll;
47945 if(forceAll === true || (q.length >= this.minChars)){
47946 if(this.lastQuery != q || this.alwaysQuery){
47947 this.lastQuery = q;
47948 if(this.mode == 'local'){
47949 this.selectedIndex = -1;
47951 this.store.clearFilter();
47953 this.store.filter(this.displayField, q);
47957 this.store.baseParams[this.queryParam] = q;
47959 params: this.getParams(q)
47964 this.selectedIndex = -1;
47971 getParams : function(q){
47973 //p[this.queryParam] = q;
47976 p.limit = this.pageSize;
47982 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47984 collapse : function(){
47989 collapseIf : function(e){
47994 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47996 expand : function(){
48004 * @cfg {Boolean} grow
48008 * @cfg {Number} growMin
48012 * @cfg {Number} growMax
48020 setWidth : function()
48024 getResizeEl : function(){
48027 });//<script type="text/javasscript">
48031 * @class Roo.DDView
48032 * A DnD enabled version of Roo.View.
48033 * @param {Element/String} container The Element in which to create the View.
48034 * @param {String} tpl The template string used to create the markup for each element of the View
48035 * @param {Object} config The configuration properties. These include all the config options of
48036 * {@link Roo.View} plus some specific to this class.<br>
48038 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48039 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48041 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48042 .x-view-drag-insert-above {
48043 border-top:1px dotted #3366cc;
48045 .x-view-drag-insert-below {
48046 border-bottom:1px dotted #3366cc;
48052 Roo.DDView = function(container, tpl, config) {
48053 Roo.DDView.superclass.constructor.apply(this, arguments);
48054 this.getEl().setStyle("outline", "0px none");
48055 this.getEl().unselectable();
48056 if (this.dragGroup) {
48057 this.setDraggable(this.dragGroup.split(","));
48059 if (this.dropGroup) {
48060 this.setDroppable(this.dropGroup.split(","));
48062 if (this.deletable) {
48063 this.setDeletable();
48065 this.isDirtyFlag = false;
48071 Roo.extend(Roo.DDView, Roo.View, {
48072 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48073 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48074 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48075 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48079 reset: Roo.emptyFn,
48081 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48083 validate: function() {
48087 destroy: function() {
48088 this.purgeListeners();
48089 this.getEl.removeAllListeners();
48090 this.getEl().remove();
48091 if (this.dragZone) {
48092 if (this.dragZone.destroy) {
48093 this.dragZone.destroy();
48096 if (this.dropZone) {
48097 if (this.dropZone.destroy) {
48098 this.dropZone.destroy();
48103 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48104 getName: function() {
48108 /** Loads the View from a JSON string representing the Records to put into the Store. */
48109 setValue: function(v) {
48111 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48114 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48115 this.store.proxy = new Roo.data.MemoryProxy(data);
48119 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48120 getValue: function() {
48122 this.store.each(function(rec) {
48123 result += rec.id + ',';
48125 return result.substr(0, result.length - 1) + ')';
48128 getIds: function() {
48129 var i = 0, result = new Array(this.store.getCount());
48130 this.store.each(function(rec) {
48131 result[i++] = rec.id;
48136 isDirty: function() {
48137 return this.isDirtyFlag;
48141 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48142 * whole Element becomes the target, and this causes the drop gesture to append.
48144 getTargetFromEvent : function(e) {
48145 var target = e.getTarget();
48146 while ((target !== null) && (target.parentNode != this.el.dom)) {
48147 target = target.parentNode;
48150 target = this.el.dom.lastChild || this.el.dom;
48156 * Create the drag data which consists of an object which has the property "ddel" as
48157 * the drag proxy element.
48159 getDragData : function(e) {
48160 var target = this.findItemFromChild(e.getTarget());
48162 this.handleSelection(e);
48163 var selNodes = this.getSelectedNodes();
48166 copy: this.copy || (this.allowCopy && e.ctrlKey),
48170 var selectedIndices = this.getSelectedIndexes();
48171 for (var i = 0; i < selectedIndices.length; i++) {
48172 dragData.records.push(this.store.getAt(selectedIndices[i]));
48174 if (selNodes.length == 1) {
48175 dragData.ddel = target.cloneNode(true); // the div element
48177 var div = document.createElement('div'); // create the multi element drag "ghost"
48178 div.className = 'multi-proxy';
48179 for (var i = 0, len = selNodes.length; i < len; i++) {
48180 div.appendChild(selNodes[i].cloneNode(true));
48182 dragData.ddel = div;
48184 //console.log(dragData)
48185 //console.log(dragData.ddel.innerHTML)
48188 //console.log('nodragData')
48192 /** Specify to which ddGroup items in this DDView may be dragged. */
48193 setDraggable: function(ddGroup) {
48194 if (ddGroup instanceof Array) {
48195 Roo.each(ddGroup, this.setDraggable, this);
48198 if (this.dragZone) {
48199 this.dragZone.addToGroup(ddGroup);
48201 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48202 containerScroll: true,
48206 // Draggability implies selection. DragZone's mousedown selects the element.
48207 if (!this.multiSelect) { this.singleSelect = true; }
48209 // Wire the DragZone's handlers up to methods in *this*
48210 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48214 /** Specify from which ddGroup this DDView accepts drops. */
48215 setDroppable: function(ddGroup) {
48216 if (ddGroup instanceof Array) {
48217 Roo.each(ddGroup, this.setDroppable, this);
48220 if (this.dropZone) {
48221 this.dropZone.addToGroup(ddGroup);
48223 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48224 containerScroll: true,
48228 // Wire the DropZone's handlers up to methods in *this*
48229 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48230 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48231 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48232 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48233 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48237 /** Decide whether to drop above or below a View node. */
48238 getDropPoint : function(e, n, dd){
48239 if (n == this.el.dom) { return "above"; }
48240 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48241 var c = t + (b - t) / 2;
48242 var y = Roo.lib.Event.getPageY(e);
48250 onNodeEnter : function(n, dd, e, data){
48254 onNodeOver : function(n, dd, e, data){
48255 var pt = this.getDropPoint(e, n, dd);
48256 // set the insert point style on the target node
48257 var dragElClass = this.dropNotAllowed;
48260 if (pt == "above"){
48261 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48262 targetElClass = "x-view-drag-insert-above";
48264 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48265 targetElClass = "x-view-drag-insert-below";
48267 if (this.lastInsertClass != targetElClass){
48268 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48269 this.lastInsertClass = targetElClass;
48272 return dragElClass;
48275 onNodeOut : function(n, dd, e, data){
48276 this.removeDropIndicators(n);
48279 onNodeDrop : function(n, dd, e, data){
48280 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48283 var pt = this.getDropPoint(e, n, dd);
48284 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48285 if (pt == "below") { insertAt++; }
48286 for (var i = 0; i < data.records.length; i++) {
48287 var r = data.records[i];
48288 var dup = this.store.getById(r.id);
48289 if (dup && (dd != this.dragZone)) {
48290 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48293 this.store.insert(insertAt++, r.copy());
48295 data.source.isDirtyFlag = true;
48297 this.store.insert(insertAt++, r);
48299 this.isDirtyFlag = true;
48302 this.dragZone.cachedTarget = null;
48306 removeDropIndicators : function(n){
48308 Roo.fly(n).removeClass([
48309 "x-view-drag-insert-above",
48310 "x-view-drag-insert-below"]);
48311 this.lastInsertClass = "_noclass";
48316 * Utility method. Add a delete option to the DDView's context menu.
48317 * @param {String} imageUrl The URL of the "delete" icon image.
48319 setDeletable: function(imageUrl) {
48320 if (!this.singleSelect && !this.multiSelect) {
48321 this.singleSelect = true;
48323 var c = this.getContextMenu();
48324 this.contextMenu.on("itemclick", function(item) {
48327 this.remove(this.getSelectedIndexes());
48331 this.contextMenu.add({
48338 /** Return the context menu for this DDView. */
48339 getContextMenu: function() {
48340 if (!this.contextMenu) {
48341 // Create the View's context menu
48342 this.contextMenu = new Roo.menu.Menu({
48343 id: this.id + "-contextmenu"
48345 this.el.on("contextmenu", this.showContextMenu, this);
48347 return this.contextMenu;
48350 disableContextMenu: function() {
48351 if (this.contextMenu) {
48352 this.el.un("contextmenu", this.showContextMenu, this);
48356 showContextMenu: function(e, item) {
48357 item = this.findItemFromChild(e.getTarget());
48360 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48361 this.contextMenu.showAt(e.getXY());
48366 * Remove {@link Roo.data.Record}s at the specified indices.
48367 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48369 remove: function(selectedIndices) {
48370 selectedIndices = [].concat(selectedIndices);
48371 for (var i = 0; i < selectedIndices.length; i++) {
48372 var rec = this.store.getAt(selectedIndices[i]);
48373 this.store.remove(rec);
48378 * Double click fires the event, but also, if this is draggable, and there is only one other
48379 * related DropZone, it transfers the selected node.
48381 onDblClick : function(e){
48382 var item = this.findItemFromChild(e.getTarget());
48384 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48387 if (this.dragGroup) {
48388 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48389 while (targets.indexOf(this.dropZone) > -1) {
48390 targets.remove(this.dropZone);
48392 if (targets.length == 1) {
48393 this.dragZone.cachedTarget = null;
48394 var el = Roo.get(targets[0].getEl());
48395 var box = el.getBox(true);
48396 targets[0].onNodeDrop(el.dom, {
48398 xy: [box.x, box.y + box.height - 1]
48399 }, null, this.getDragData(e));
48405 handleSelection: function(e) {
48406 this.dragZone.cachedTarget = null;
48407 var item = this.findItemFromChild(e.getTarget());
48409 this.clearSelections(true);
48412 if (item && (this.multiSelect || this.singleSelect)){
48413 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48414 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48415 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48416 this.unselect(item);
48418 this.select(item, this.multiSelect && e.ctrlKey);
48419 this.lastSelection = item;
48424 onItemClick : function(item, index, e){
48425 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48431 unselect : function(nodeInfo, suppressEvent){
48432 var node = this.getNode(nodeInfo);
48433 if(node && this.isSelected(node)){
48434 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48435 Roo.fly(node).removeClass(this.selectedClass);
48436 this.selections.remove(node);
48437 if(!suppressEvent){
48438 this.fireEvent("selectionchange", this, this.selections);
48446 * Ext JS Library 1.1.1
48447 * Copyright(c) 2006-2007, Ext JS, LLC.
48449 * Originally Released Under LGPL - original licence link has changed is not relivant.
48452 * <script type="text/javascript">
48456 * @class Roo.LayoutManager
48457 * @extends Roo.util.Observable
48458 * Base class for layout managers.
48460 Roo.LayoutManager = function(container, config){
48461 Roo.LayoutManager.superclass.constructor.call(this);
48462 this.el = Roo.get(container);
48463 // ie scrollbar fix
48464 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48465 document.body.scroll = "no";
48466 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48467 this.el.position('relative');
48469 this.id = this.el.id;
48470 this.el.addClass("x-layout-container");
48471 /** false to disable window resize monitoring @type Boolean */
48472 this.monitorWindowResize = true;
48477 * Fires when a layout is performed.
48478 * @param {Roo.LayoutManager} this
48482 * @event regionresized
48483 * Fires when the user resizes a region.
48484 * @param {Roo.LayoutRegion} region The resized region
48485 * @param {Number} newSize The new size (width for east/west, height for north/south)
48487 "regionresized" : true,
48489 * @event regioncollapsed
48490 * Fires when a region is collapsed.
48491 * @param {Roo.LayoutRegion} region The collapsed region
48493 "regioncollapsed" : true,
48495 * @event regionexpanded
48496 * Fires when a region is expanded.
48497 * @param {Roo.LayoutRegion} region The expanded region
48499 "regionexpanded" : true
48501 this.updating = false;
48502 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48505 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48507 * Returns true if this layout is currently being updated
48508 * @return {Boolean}
48510 isUpdating : function(){
48511 return this.updating;
48515 * Suspend the LayoutManager from doing auto-layouts while
48516 * making multiple add or remove calls
48518 beginUpdate : function(){
48519 this.updating = true;
48523 * Restore auto-layouts and optionally disable the manager from performing a layout
48524 * @param {Boolean} noLayout true to disable a layout update
48526 endUpdate : function(noLayout){
48527 this.updating = false;
48533 layout: function(){
48537 onRegionResized : function(region, newSize){
48538 this.fireEvent("regionresized", region, newSize);
48542 onRegionCollapsed : function(region){
48543 this.fireEvent("regioncollapsed", region);
48546 onRegionExpanded : function(region){
48547 this.fireEvent("regionexpanded", region);
48551 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48552 * performs box-model adjustments.
48553 * @return {Object} The size as an object {width: (the width), height: (the height)}
48555 getViewSize : function(){
48557 if(this.el.dom != document.body){
48558 size = this.el.getSize();
48560 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48562 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48563 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48568 * Returns the Element this layout is bound to.
48569 * @return {Roo.Element}
48571 getEl : function(){
48576 * Returns the specified region.
48577 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48578 * @return {Roo.LayoutRegion}
48580 getRegion : function(target){
48581 return this.regions[target.toLowerCase()];
48584 onWindowResize : function(){
48585 if(this.monitorWindowResize){
48591 * Ext JS Library 1.1.1
48592 * Copyright(c) 2006-2007, Ext JS, LLC.
48594 * Originally Released Under LGPL - original licence link has changed is not relivant.
48597 * <script type="text/javascript">
48600 * @class Roo.BorderLayout
48601 * @extends Roo.LayoutManager
48602 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48603 * please see: <br><br>
48604 * <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>
48605 * <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>
48608 var layout = new Roo.BorderLayout(document.body, {
48642 preferredTabWidth: 150
48647 var CP = Roo.ContentPanel;
48649 layout.beginUpdate();
48650 layout.add("north", new CP("north", "North"));
48651 layout.add("south", new CP("south", {title: "South", closable: true}));
48652 layout.add("west", new CP("west", {title: "West"}));
48653 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48654 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48655 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48656 layout.getRegion("center").showPanel("center1");
48657 layout.endUpdate();
48660 <b>The container the layout is rendered into can be either the body element or any other element.
48661 If it is not the body element, the container needs to either be an absolute positioned element,
48662 or you will need to add "position:relative" to the css of the container. You will also need to specify
48663 the container size if it is not the body element.</b>
48666 * Create a new BorderLayout
48667 * @param {String/HTMLElement/Element} container The container this layout is bound to
48668 * @param {Object} config Configuration options
48670 Roo.BorderLayout = function(container, config){
48671 config = config || {};
48672 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48673 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48674 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48675 var target = this.factory.validRegions[i];
48676 if(config[target]){
48677 this.addRegion(target, config[target]);
48682 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48684 * Creates and adds a new region if it doesn't already exist.
48685 * @param {String} target The target region key (north, south, east, west or center).
48686 * @param {Object} config The regions config object
48687 * @return {BorderLayoutRegion} The new region
48689 addRegion : function(target, config){
48690 if(!this.regions[target]){
48691 var r = this.factory.create(target, this, config);
48692 this.bindRegion(target, r);
48694 return this.regions[target];
48698 bindRegion : function(name, r){
48699 this.regions[name] = r;
48700 r.on("visibilitychange", this.layout, this);
48701 r.on("paneladded", this.layout, this);
48702 r.on("panelremoved", this.layout, this);
48703 r.on("invalidated", this.layout, this);
48704 r.on("resized", this.onRegionResized, this);
48705 r.on("collapsed", this.onRegionCollapsed, this);
48706 r.on("expanded", this.onRegionExpanded, this);
48710 * Performs a layout update.
48712 layout : function(){
48713 if(this.updating) return;
48714 var size = this.getViewSize();
48715 var w = size.width;
48716 var h = size.height;
48721 //var x = 0, y = 0;
48723 var rs = this.regions;
48724 var north = rs["north"];
48725 var south = rs["south"];
48726 var west = rs["west"];
48727 var east = rs["east"];
48728 var center = rs["center"];
48729 //if(this.hideOnLayout){ // not supported anymore
48730 //c.el.setStyle("display", "none");
48732 if(north && north.isVisible()){
48733 var b = north.getBox();
48734 var m = north.getMargins();
48735 b.width = w - (m.left+m.right);
48738 centerY = b.height + b.y + m.bottom;
48739 centerH -= centerY;
48740 north.updateBox(this.safeBox(b));
48742 if(south && south.isVisible()){
48743 var b = south.getBox();
48744 var m = south.getMargins();
48745 b.width = w - (m.left+m.right);
48747 var totalHeight = (b.height + m.top + m.bottom);
48748 b.y = h - totalHeight + m.top;
48749 centerH -= totalHeight;
48750 south.updateBox(this.safeBox(b));
48752 if(west && west.isVisible()){
48753 var b = west.getBox();
48754 var m = west.getMargins();
48755 b.height = centerH - (m.top+m.bottom);
48757 b.y = centerY + m.top;
48758 var totalWidth = (b.width + m.left + m.right);
48759 centerX += totalWidth;
48760 centerW -= totalWidth;
48761 west.updateBox(this.safeBox(b));
48763 if(east && east.isVisible()){
48764 var b = east.getBox();
48765 var m = east.getMargins();
48766 b.height = centerH - (m.top+m.bottom);
48767 var totalWidth = (b.width + m.left + m.right);
48768 b.x = w - totalWidth + m.left;
48769 b.y = centerY + m.top;
48770 centerW -= totalWidth;
48771 east.updateBox(this.safeBox(b));
48774 var m = center.getMargins();
48776 x: centerX + m.left,
48777 y: centerY + m.top,
48778 width: centerW - (m.left+m.right),
48779 height: centerH - (m.top+m.bottom)
48781 //if(this.hideOnLayout){
48782 //center.el.setStyle("display", "block");
48784 center.updateBox(this.safeBox(centerBox));
48787 this.fireEvent("layout", this);
48791 safeBox : function(box){
48792 box.width = Math.max(0, box.width);
48793 box.height = Math.max(0, box.height);
48798 * Adds a ContentPanel (or subclass) to this layout.
48799 * @param {String} target The target region key (north, south, east, west or center).
48800 * @param {Roo.ContentPanel} panel The panel to add
48801 * @return {Roo.ContentPanel} The added panel
48803 add : function(target, panel){
48805 target = target.toLowerCase();
48806 return this.regions[target].add(panel);
48810 * Remove a ContentPanel (or subclass) to this layout.
48811 * @param {String} target The target region key (north, south, east, west or center).
48812 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48813 * @return {Roo.ContentPanel} The removed panel
48815 remove : function(target, panel){
48816 target = target.toLowerCase();
48817 return this.regions[target].remove(panel);
48821 * Searches all regions for a panel with the specified id
48822 * @param {String} panelId
48823 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48825 findPanel : function(panelId){
48826 var rs = this.regions;
48827 for(var target in rs){
48828 if(typeof rs[target] != "function"){
48829 var p = rs[target].getPanel(panelId);
48839 * Searches all regions for a panel with the specified id and activates (shows) it.
48840 * @param {String/ContentPanel} panelId The panels id or the panel itself
48841 * @return {Roo.ContentPanel} The shown panel or null
48843 showPanel : function(panelId) {
48844 var rs = this.regions;
48845 for(var target in rs){
48846 var r = rs[target];
48847 if(typeof r != "function"){
48848 if(r.hasPanel(panelId)){
48849 return r.showPanel(panelId);
48857 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48858 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48860 restoreState : function(provider){
48862 provider = Roo.state.Manager;
48864 var sm = new Roo.LayoutStateManager();
48865 sm.init(this, provider);
48869 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48870 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48871 * a valid ContentPanel config object. Example:
48873 // Create the main layout
48874 var layout = new Roo.BorderLayout('main-ct', {
48885 // Create and add multiple ContentPanels at once via configs
48888 id: 'source-files',
48890 title:'Ext Source Files',
48903 * @param {Object} regions An object containing ContentPanel configs by region name
48905 batchAdd : function(regions){
48906 this.beginUpdate();
48907 for(var rname in regions){
48908 var lr = this.regions[rname];
48910 this.addTypedPanels(lr, regions[rname]);
48917 addTypedPanels : function(lr, ps){
48918 if(typeof ps == 'string'){
48919 lr.add(new Roo.ContentPanel(ps));
48921 else if(ps instanceof Array){
48922 for(var i =0, len = ps.length; i < len; i++){
48923 this.addTypedPanels(lr, ps[i]);
48926 else if(!ps.events){ // raw config?
48928 delete ps.el; // prevent conflict
48929 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48931 else { // panel object assumed!
48936 * Adds a xtype elements to the layout.
48940 xtype : 'ContentPanel',
48947 xtype : 'NestedLayoutPanel',
48953 items : [ ... list of content panels or nested layout panels.. ]
48957 * @param {Object} cfg Xtype definition of item to add.
48959 addxtype : function(cfg)
48961 // basically accepts a pannel...
48962 // can accept a layout region..!?!?
48963 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48965 if (!cfg.xtype.match(/Panel$/)) {
48970 if (typeof(cfg.region) == 'undefined') {
48971 Roo.log("Failed to add Panel, region was not set");
48975 var region = cfg.region;
48981 xitems = cfg.items;
48988 case 'ContentPanel': // ContentPanel (el, cfg)
48989 case 'ScrollPanel': // ContentPanel (el, cfg)
48991 if(cfg.autoCreate) {
48992 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48994 var el = this.el.createChild();
48995 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48998 this.add(region, ret);
49002 case 'TreePanel': // our new panel!
49003 cfg.el = this.el.createChild();
49004 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49005 this.add(region, ret);
49008 case 'NestedLayoutPanel':
49009 // create a new Layout (which is a Border Layout...
49010 var el = this.el.createChild();
49011 var clayout = cfg.layout;
49013 clayout.items = clayout.items || [];
49014 // replace this exitems with the clayout ones..
49015 xitems = clayout.items;
49018 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49019 cfg.background = false;
49021 var layout = new Roo.BorderLayout(el, clayout);
49023 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49024 //console.log('adding nested layout panel ' + cfg.toSource());
49025 this.add(region, ret);
49026 nb = {}; /// find first...
49031 // needs grid and region
49033 //var el = this.getRegion(region).el.createChild();
49034 var el = this.el.createChild();
49035 // create the grid first...
49037 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49039 if (region == 'center' && this.active ) {
49040 cfg.background = false;
49042 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49044 this.add(region, ret);
49045 if (cfg.background) {
49046 ret.on('activate', function(gp) {
49047 if (!gp.grid.rendered) {
49062 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49064 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49065 this.add(region, ret);
49068 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49072 // GridPanel (grid, cfg)
49075 this.beginUpdate();
49079 Roo.each(xitems, function(i) {
49080 region = nb && i.region ? i.region : false;
49082 var add = ret.addxtype(i);
49085 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49086 if (!i.background) {
49087 abn[region] = nb[region] ;
49094 // make the last non-background panel active..
49095 //if (nb) { Roo.log(abn); }
49098 for(var r in abn) {
49099 region = this.getRegion(r);
49101 // tried using nb[r], but it does not work..
49103 region.showPanel(abn[r]);
49114 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49115 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49116 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49117 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49120 var CP = Roo.ContentPanel;
49122 var layout = Roo.BorderLayout.create({
49126 panels: [new CP("north", "North")]
49135 panels: [new CP("west", {title: "West"})]
49144 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49153 panels: [new CP("south", {title: "South", closable: true})]
49160 preferredTabWidth: 150,
49162 new CP("center1", {title: "Close Me", closable: true}),
49163 new CP("center2", {title: "Center Panel", closable: false})
49168 layout.getRegion("center").showPanel("center1");
49173 Roo.BorderLayout.create = function(config, targetEl){
49174 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49175 layout.beginUpdate();
49176 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49177 for(var j = 0, jlen = regions.length; j < jlen; j++){
49178 var lr = regions[j];
49179 if(layout.regions[lr] && config[lr].panels){
49180 var r = layout.regions[lr];
49181 var ps = config[lr].panels;
49182 layout.addTypedPanels(r, ps);
49185 layout.endUpdate();
49190 Roo.BorderLayout.RegionFactory = {
49192 validRegions : ["north","south","east","west","center"],
49195 create : function(target, mgr, config){
49196 target = target.toLowerCase();
49197 if(config.lightweight || config.basic){
49198 return new Roo.BasicLayoutRegion(mgr, config, target);
49202 return new Roo.NorthLayoutRegion(mgr, config);
49204 return new Roo.SouthLayoutRegion(mgr, config);
49206 return new Roo.EastLayoutRegion(mgr, config);
49208 return new Roo.WestLayoutRegion(mgr, config);
49210 return new Roo.CenterLayoutRegion(mgr, config);
49212 throw 'Layout region "'+target+'" not supported.';
49216 * Ext JS Library 1.1.1
49217 * Copyright(c) 2006-2007, Ext JS, LLC.
49219 * Originally Released Under LGPL - original licence link has changed is not relivant.
49222 * <script type="text/javascript">
49226 * @class Roo.BasicLayoutRegion
49227 * @extends Roo.util.Observable
49228 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49229 * and does not have a titlebar, tabs or any other features. All it does is size and position
49230 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49232 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49234 this.position = pos;
49237 * @scope Roo.BasicLayoutRegion
49241 * @event beforeremove
49242 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49243 * @param {Roo.LayoutRegion} this
49244 * @param {Roo.ContentPanel} panel The panel
49245 * @param {Object} e The cancel event object
49247 "beforeremove" : true,
49249 * @event invalidated
49250 * Fires when the layout for this region is changed.
49251 * @param {Roo.LayoutRegion} this
49253 "invalidated" : true,
49255 * @event visibilitychange
49256 * Fires when this region is shown or hidden
49257 * @param {Roo.LayoutRegion} this
49258 * @param {Boolean} visibility true or false
49260 "visibilitychange" : true,
49262 * @event paneladded
49263 * Fires when a panel is added.
49264 * @param {Roo.LayoutRegion} this
49265 * @param {Roo.ContentPanel} panel The panel
49267 "paneladded" : true,
49269 * @event panelremoved
49270 * Fires when a panel is removed.
49271 * @param {Roo.LayoutRegion} this
49272 * @param {Roo.ContentPanel} panel The panel
49274 "panelremoved" : true,
49277 * Fires when this region is collapsed.
49278 * @param {Roo.LayoutRegion} this
49280 "collapsed" : true,
49283 * Fires when this region is expanded.
49284 * @param {Roo.LayoutRegion} this
49289 * Fires when this region is slid into view.
49290 * @param {Roo.LayoutRegion} this
49292 "slideshow" : true,
49295 * Fires when this region slides out of view.
49296 * @param {Roo.LayoutRegion} this
49298 "slidehide" : true,
49300 * @event panelactivated
49301 * Fires when a panel is activated.
49302 * @param {Roo.LayoutRegion} this
49303 * @param {Roo.ContentPanel} panel The activated panel
49305 "panelactivated" : true,
49308 * Fires when the user resizes this region.
49309 * @param {Roo.LayoutRegion} this
49310 * @param {Number} newSize The new size (width for east/west, height for north/south)
49314 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49315 this.panels = new Roo.util.MixedCollection();
49316 this.panels.getKey = this.getPanelId.createDelegate(this);
49318 this.activePanel = null;
49319 // ensure listeners are added...
49321 if (config.listeners || config.events) {
49322 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49323 listeners : config.listeners || {},
49324 events : config.events || {}
49328 if(skipConfig !== true){
49329 this.applyConfig(config);
49333 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49334 getPanelId : function(p){
49338 applyConfig : function(config){
49339 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49340 this.config = config;
49345 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49346 * the width, for horizontal (north, south) the height.
49347 * @param {Number} newSize The new width or height
49349 resizeTo : function(newSize){
49350 var el = this.el ? this.el :
49351 (this.activePanel ? this.activePanel.getEl() : null);
49353 switch(this.position){
49356 el.setWidth(newSize);
49357 this.fireEvent("resized", this, newSize);
49361 el.setHeight(newSize);
49362 this.fireEvent("resized", this, newSize);
49368 getBox : function(){
49369 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49372 getMargins : function(){
49373 return this.margins;
49376 updateBox : function(box){
49378 var el = this.activePanel.getEl();
49379 el.dom.style.left = box.x + "px";
49380 el.dom.style.top = box.y + "px";
49381 this.activePanel.setSize(box.width, box.height);
49385 * Returns the container element for this region.
49386 * @return {Roo.Element}
49388 getEl : function(){
49389 return this.activePanel;
49393 * Returns true if this region is currently visible.
49394 * @return {Boolean}
49396 isVisible : function(){
49397 return this.activePanel ? true : false;
49400 setActivePanel : function(panel){
49401 panel = this.getPanel(panel);
49402 if(this.activePanel && this.activePanel != panel){
49403 this.activePanel.setActiveState(false);
49404 this.activePanel.getEl().setLeftTop(-10000,-10000);
49406 this.activePanel = panel;
49407 panel.setActiveState(true);
49409 panel.setSize(this.box.width, this.box.height);
49411 this.fireEvent("panelactivated", this, panel);
49412 this.fireEvent("invalidated");
49416 * Show the specified panel.
49417 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49418 * @return {Roo.ContentPanel} The shown panel or null
49420 showPanel : function(panel){
49421 if(panel = this.getPanel(panel)){
49422 this.setActivePanel(panel);
49428 * Get the active panel for this region.
49429 * @return {Roo.ContentPanel} The active panel or null
49431 getActivePanel : function(){
49432 return this.activePanel;
49436 * Add the passed ContentPanel(s)
49437 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49438 * @return {Roo.ContentPanel} The panel added (if only one was added)
49440 add : function(panel){
49441 if(arguments.length > 1){
49442 for(var i = 0, len = arguments.length; i < len; i++) {
49443 this.add(arguments[i]);
49447 if(this.hasPanel(panel)){
49448 this.showPanel(panel);
49451 var el = panel.getEl();
49452 if(el.dom.parentNode != this.mgr.el.dom){
49453 this.mgr.el.dom.appendChild(el.dom);
49455 if(panel.setRegion){
49456 panel.setRegion(this);
49458 this.panels.add(panel);
49459 el.setStyle("position", "absolute");
49460 if(!panel.background){
49461 this.setActivePanel(panel);
49462 if(this.config.initialSize && this.panels.getCount()==1){
49463 this.resizeTo(this.config.initialSize);
49466 this.fireEvent("paneladded", this, panel);
49471 * Returns true if the panel is in this region.
49472 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49473 * @return {Boolean}
49475 hasPanel : function(panel){
49476 if(typeof panel == "object"){ // must be panel obj
49477 panel = panel.getId();
49479 return this.getPanel(panel) ? true : false;
49483 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49484 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49485 * @param {Boolean} preservePanel Overrides the config preservePanel option
49486 * @return {Roo.ContentPanel} The panel that was removed
49488 remove : function(panel, preservePanel){
49489 panel = this.getPanel(panel);
49494 this.fireEvent("beforeremove", this, panel, e);
49495 if(e.cancel === true){
49498 var panelId = panel.getId();
49499 this.panels.removeKey(panelId);
49504 * Returns the panel specified or null if it's not in this region.
49505 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49506 * @return {Roo.ContentPanel}
49508 getPanel : function(id){
49509 if(typeof id == "object"){ // must be panel obj
49512 return this.panels.get(id);
49516 * Returns this regions position (north/south/east/west/center).
49519 getPosition: function(){
49520 return this.position;
49524 * Ext JS Library 1.1.1
49525 * Copyright(c) 2006-2007, Ext JS, LLC.
49527 * Originally Released Under LGPL - original licence link has changed is not relivant.
49530 * <script type="text/javascript">
49534 * @class Roo.LayoutRegion
49535 * @extends Roo.BasicLayoutRegion
49536 * This class represents a region in a layout manager.
49537 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49538 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49539 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49540 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49541 * @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})
49542 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49543 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49544 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49545 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49546 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49547 * @cfg {String} title The title for the region (overrides panel titles)
49548 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49549 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49550 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49551 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49552 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49553 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49554 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49555 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49556 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49557 * @cfg {Boolean} showPin True to show a pin button
49558 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49559 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49560 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49561 * @cfg {Number} width For East/West panels
49562 * @cfg {Number} height For North/South panels
49563 * @cfg {Boolean} split To show the splitter
49564 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49566 Roo.LayoutRegion = function(mgr, config, pos){
49567 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49568 var dh = Roo.DomHelper;
49569 /** This region's container element
49570 * @type Roo.Element */
49571 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49572 /** This region's title element
49573 * @type Roo.Element */
49575 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49576 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49577 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49579 this.titleEl.enableDisplayMode();
49580 /** This region's title text element
49581 * @type HTMLElement */
49582 this.titleTextEl = this.titleEl.dom.firstChild;
49583 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49584 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49585 this.closeBtn.enableDisplayMode();
49586 this.closeBtn.on("click", this.closeClicked, this);
49587 this.closeBtn.hide();
49589 this.createBody(config);
49590 this.visible = true;
49591 this.collapsed = false;
49593 if(config.hideWhenEmpty){
49595 this.on("paneladded", this.validateVisibility, this);
49596 this.on("panelremoved", this.validateVisibility, this);
49598 this.applyConfig(config);
49601 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49603 createBody : function(){
49604 /** This region's body element
49605 * @type Roo.Element */
49606 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49609 applyConfig : function(c){
49610 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49611 var dh = Roo.DomHelper;
49612 if(c.titlebar !== false){
49613 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49614 this.collapseBtn.on("click", this.collapse, this);
49615 this.collapseBtn.enableDisplayMode();
49617 if(c.showPin === true || this.showPin){
49618 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49619 this.stickBtn.enableDisplayMode();
49620 this.stickBtn.on("click", this.expand, this);
49621 this.stickBtn.hide();
49624 /** This region's collapsed element
49625 * @type Roo.Element */
49626 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49627 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49629 if(c.floatable !== false){
49630 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49631 this.collapsedEl.on("click", this.collapseClick, this);
49634 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49635 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49636 id: "message", unselectable: "on", style:{"float":"left"}});
49637 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49639 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49640 this.expandBtn.on("click", this.expand, this);
49642 if(this.collapseBtn){
49643 this.collapseBtn.setVisible(c.collapsible == true);
49645 this.cmargins = c.cmargins || this.cmargins ||
49646 (this.position == "west" || this.position == "east" ?
49647 {top: 0, left: 2, right:2, bottom: 0} :
49648 {top: 2, left: 0, right:0, bottom: 2});
49649 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49650 this.bottomTabs = c.tabPosition != "top";
49651 this.autoScroll = c.autoScroll || false;
49652 if(this.autoScroll){
49653 this.bodyEl.setStyle("overflow", "auto");
49655 this.bodyEl.setStyle("overflow", "hidden");
49657 //if(c.titlebar !== false){
49658 if((!c.titlebar && !c.title) || c.titlebar === false){
49659 this.titleEl.hide();
49661 this.titleEl.show();
49663 this.titleTextEl.innerHTML = c.title;
49667 this.duration = c.duration || .30;
49668 this.slideDuration = c.slideDuration || .45;
49671 this.collapse(true);
49678 * Returns true if this region is currently visible.
49679 * @return {Boolean}
49681 isVisible : function(){
49682 return this.visible;
49686 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49687 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49689 setCollapsedTitle : function(title){
49690 title = title || " ";
49691 if(this.collapsedTitleTextEl){
49692 this.collapsedTitleTextEl.innerHTML = title;
49696 getBox : function(){
49698 if(!this.collapsed){
49699 b = this.el.getBox(false, true);
49701 b = this.collapsedEl.getBox(false, true);
49706 getMargins : function(){
49707 return this.collapsed ? this.cmargins : this.margins;
49710 highlight : function(){
49711 this.el.addClass("x-layout-panel-dragover");
49714 unhighlight : function(){
49715 this.el.removeClass("x-layout-panel-dragover");
49718 updateBox : function(box){
49720 if(!this.collapsed){
49721 this.el.dom.style.left = box.x + "px";
49722 this.el.dom.style.top = box.y + "px";
49723 this.updateBody(box.width, box.height);
49725 this.collapsedEl.dom.style.left = box.x + "px";
49726 this.collapsedEl.dom.style.top = box.y + "px";
49727 this.collapsedEl.setSize(box.width, box.height);
49730 this.tabs.autoSizeTabs();
49734 updateBody : function(w, h){
49736 this.el.setWidth(w);
49737 w -= this.el.getBorderWidth("rl");
49738 if(this.config.adjustments){
49739 w += this.config.adjustments[0];
49743 this.el.setHeight(h);
49744 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49745 h -= this.el.getBorderWidth("tb");
49746 if(this.config.adjustments){
49747 h += this.config.adjustments[1];
49749 this.bodyEl.setHeight(h);
49751 h = this.tabs.syncHeight(h);
49754 if(this.panelSize){
49755 w = w !== null ? w : this.panelSize.width;
49756 h = h !== null ? h : this.panelSize.height;
49758 if(this.activePanel){
49759 var el = this.activePanel.getEl();
49760 w = w !== null ? w : el.getWidth();
49761 h = h !== null ? h : el.getHeight();
49762 this.panelSize = {width: w, height: h};
49763 this.activePanel.setSize(w, h);
49765 if(Roo.isIE && this.tabs){
49766 this.tabs.el.repaint();
49771 * Returns the container element for this region.
49772 * @return {Roo.Element}
49774 getEl : function(){
49779 * Hides this region.
49782 if(!this.collapsed){
49783 this.el.dom.style.left = "-2000px";
49786 this.collapsedEl.dom.style.left = "-2000px";
49787 this.collapsedEl.hide();
49789 this.visible = false;
49790 this.fireEvent("visibilitychange", this, false);
49794 * Shows this region if it was previously hidden.
49797 if(!this.collapsed){
49800 this.collapsedEl.show();
49802 this.visible = true;
49803 this.fireEvent("visibilitychange", this, true);
49806 closeClicked : function(){
49807 if(this.activePanel){
49808 this.remove(this.activePanel);
49812 collapseClick : function(e){
49814 e.stopPropagation();
49817 e.stopPropagation();
49823 * Collapses this region.
49824 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49826 collapse : function(skipAnim){
49827 if(this.collapsed) return;
49828 this.collapsed = true;
49830 this.split.el.hide();
49832 if(this.config.animate && skipAnim !== true){
49833 this.fireEvent("invalidated", this);
49834 this.animateCollapse();
49836 this.el.setLocation(-20000,-20000);
49838 this.collapsedEl.show();
49839 this.fireEvent("collapsed", this);
49840 this.fireEvent("invalidated", this);
49844 animateCollapse : function(){
49849 * Expands this region if it was previously collapsed.
49850 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49851 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49853 expand : function(e, skipAnim){
49854 if(e) e.stopPropagation();
49855 if(!this.collapsed || this.el.hasActiveFx()) return;
49857 this.afterSlideIn();
49860 this.collapsed = false;
49861 if(this.config.animate && skipAnim !== true){
49862 this.animateExpand();
49866 this.split.el.show();
49868 this.collapsedEl.setLocation(-2000,-2000);
49869 this.collapsedEl.hide();
49870 this.fireEvent("invalidated", this);
49871 this.fireEvent("expanded", this);
49875 animateExpand : function(){
49879 initTabs : function()
49881 this.bodyEl.setStyle("overflow", "hidden");
49882 var ts = new Roo.TabPanel(
49885 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49886 disableTooltips: this.config.disableTabTips,
49887 toolbar : this.config.toolbar
49890 if(this.config.hideTabs){
49891 ts.stripWrap.setDisplayed(false);
49894 ts.resizeTabs = this.config.resizeTabs === true;
49895 ts.minTabWidth = this.config.minTabWidth || 40;
49896 ts.maxTabWidth = this.config.maxTabWidth || 250;
49897 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49898 ts.monitorResize = false;
49899 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49900 ts.bodyEl.addClass('x-layout-tabs-body');
49901 this.panels.each(this.initPanelAsTab, this);
49904 initPanelAsTab : function(panel){
49905 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49906 this.config.closeOnTab && panel.isClosable());
49907 if(panel.tabTip !== undefined){
49908 ti.setTooltip(panel.tabTip);
49910 ti.on("activate", function(){
49911 this.setActivePanel(panel);
49913 if(this.config.closeOnTab){
49914 ti.on("beforeclose", function(t, e){
49916 this.remove(panel);
49922 updatePanelTitle : function(panel, title){
49923 if(this.activePanel == panel){
49924 this.updateTitle(title);
49927 var ti = this.tabs.getTab(panel.getEl().id);
49929 if(panel.tabTip !== undefined){
49930 ti.setTooltip(panel.tabTip);
49935 updateTitle : function(title){
49936 if(this.titleTextEl && !this.config.title){
49937 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49941 setActivePanel : function(panel){
49942 panel = this.getPanel(panel);
49943 if(this.activePanel && this.activePanel != panel){
49944 this.activePanel.setActiveState(false);
49946 this.activePanel = panel;
49947 panel.setActiveState(true);
49948 if(this.panelSize){
49949 panel.setSize(this.panelSize.width, this.panelSize.height);
49952 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49954 this.updateTitle(panel.getTitle());
49956 this.fireEvent("invalidated", this);
49958 this.fireEvent("panelactivated", this, panel);
49962 * Shows the specified panel.
49963 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49964 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49966 showPanel : function(panel){
49967 if(panel = this.getPanel(panel)){
49969 var tab = this.tabs.getTab(panel.getEl().id);
49970 if(tab.isHidden()){
49971 this.tabs.unhideTab(tab.id);
49975 this.setActivePanel(panel);
49982 * Get the active panel for this region.
49983 * @return {Roo.ContentPanel} The active panel or null
49985 getActivePanel : function(){
49986 return this.activePanel;
49989 validateVisibility : function(){
49990 if(this.panels.getCount() < 1){
49991 this.updateTitle(" ");
49992 this.closeBtn.hide();
49995 if(!this.isVisible()){
50002 * Adds the passed ContentPanel(s) to this region.
50003 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50004 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50006 add : function(panel){
50007 if(arguments.length > 1){
50008 for(var i = 0, len = arguments.length; i < len; i++) {
50009 this.add(arguments[i]);
50013 if(this.hasPanel(panel)){
50014 this.showPanel(panel);
50017 panel.setRegion(this);
50018 this.panels.add(panel);
50019 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50020 this.bodyEl.dom.appendChild(panel.getEl().dom);
50021 if(panel.background !== true){
50022 this.setActivePanel(panel);
50024 this.fireEvent("paneladded", this, panel);
50030 this.initPanelAsTab(panel);
50032 if(panel.background !== true){
50033 this.tabs.activate(panel.getEl().id);
50035 this.fireEvent("paneladded", this, panel);
50040 * Hides the tab for the specified panel.
50041 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50043 hidePanel : function(panel){
50044 if(this.tabs && (panel = this.getPanel(panel))){
50045 this.tabs.hideTab(panel.getEl().id);
50050 * Unhides the tab for a previously hidden panel.
50051 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50053 unhidePanel : function(panel){
50054 if(this.tabs && (panel = this.getPanel(panel))){
50055 this.tabs.unhideTab(panel.getEl().id);
50059 clearPanels : function(){
50060 while(this.panels.getCount() > 0){
50061 this.remove(this.panels.first());
50066 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50067 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50068 * @param {Boolean} preservePanel Overrides the config preservePanel option
50069 * @return {Roo.ContentPanel} The panel that was removed
50071 remove : function(panel, preservePanel){
50072 panel = this.getPanel(panel);
50077 this.fireEvent("beforeremove", this, panel, e);
50078 if(e.cancel === true){
50081 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50082 var panelId = panel.getId();
50083 this.panels.removeKey(panelId);
50085 document.body.appendChild(panel.getEl().dom);
50088 this.tabs.removeTab(panel.getEl().id);
50089 }else if (!preservePanel){
50090 this.bodyEl.dom.removeChild(panel.getEl().dom);
50092 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50093 var p = this.panels.first();
50094 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50095 tempEl.appendChild(p.getEl().dom);
50096 this.bodyEl.update("");
50097 this.bodyEl.dom.appendChild(p.getEl().dom);
50099 this.updateTitle(p.getTitle());
50101 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50102 this.setActivePanel(p);
50104 panel.setRegion(null);
50105 if(this.activePanel == panel){
50106 this.activePanel = null;
50108 if(this.config.autoDestroy !== false && preservePanel !== true){
50109 try{panel.destroy();}catch(e){}
50111 this.fireEvent("panelremoved", this, panel);
50116 * Returns the TabPanel component used by this region
50117 * @return {Roo.TabPanel}
50119 getTabs : function(){
50123 createTool : function(parentEl, className){
50124 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50125 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50126 btn.addClassOnOver("x-layout-tools-button-over");
50131 * Ext JS Library 1.1.1
50132 * Copyright(c) 2006-2007, Ext JS, LLC.
50134 * Originally Released Under LGPL - original licence link has changed is not relivant.
50137 * <script type="text/javascript">
50143 * @class Roo.SplitLayoutRegion
50144 * @extends Roo.LayoutRegion
50145 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50147 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50148 this.cursor = cursor;
50149 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50152 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50153 splitTip : "Drag to resize.",
50154 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50155 useSplitTips : false,
50157 applyConfig : function(config){
50158 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50161 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50162 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50163 /** The SplitBar for this region
50164 * @type Roo.SplitBar */
50165 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50166 this.split.on("moved", this.onSplitMove, this);
50167 this.split.useShim = config.useShim === true;
50168 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50169 if(this.useSplitTips){
50170 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50172 if(config.collapsible){
50173 this.split.el.on("dblclick", this.collapse, this);
50176 if(typeof config.minSize != "undefined"){
50177 this.split.minSize = config.minSize;
50179 if(typeof config.maxSize != "undefined"){
50180 this.split.maxSize = config.maxSize;
50182 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50183 this.hideSplitter();
50188 getHMaxSize : function(){
50189 var cmax = this.config.maxSize || 10000;
50190 var center = this.mgr.getRegion("center");
50191 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50194 getVMaxSize : function(){
50195 var cmax = this.config.maxSize || 10000;
50196 var center = this.mgr.getRegion("center");
50197 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50200 onSplitMove : function(split, newSize){
50201 this.fireEvent("resized", this, newSize);
50205 * Returns the {@link Roo.SplitBar} for this region.
50206 * @return {Roo.SplitBar}
50208 getSplitBar : function(){
50213 this.hideSplitter();
50214 Roo.SplitLayoutRegion.superclass.hide.call(this);
50217 hideSplitter : function(){
50219 this.split.el.setLocation(-2000,-2000);
50220 this.split.el.hide();
50226 this.split.el.show();
50228 Roo.SplitLayoutRegion.superclass.show.call(this);
50231 beforeSlide: function(){
50232 if(Roo.isGecko){// firefox overflow auto bug workaround
50233 this.bodyEl.clip();
50234 if(this.tabs) this.tabs.bodyEl.clip();
50235 if(this.activePanel){
50236 this.activePanel.getEl().clip();
50238 if(this.activePanel.beforeSlide){
50239 this.activePanel.beforeSlide();
50245 afterSlide : function(){
50246 if(Roo.isGecko){// firefox overflow auto bug workaround
50247 this.bodyEl.unclip();
50248 if(this.tabs) this.tabs.bodyEl.unclip();
50249 if(this.activePanel){
50250 this.activePanel.getEl().unclip();
50251 if(this.activePanel.afterSlide){
50252 this.activePanel.afterSlide();
50258 initAutoHide : function(){
50259 if(this.autoHide !== false){
50260 if(!this.autoHideHd){
50261 var st = new Roo.util.DelayedTask(this.slideIn, this);
50262 this.autoHideHd = {
50263 "mouseout": function(e){
50264 if(!e.within(this.el, true)){
50268 "mouseover" : function(e){
50274 this.el.on(this.autoHideHd);
50278 clearAutoHide : function(){
50279 if(this.autoHide !== false){
50280 this.el.un("mouseout", this.autoHideHd.mouseout);
50281 this.el.un("mouseover", this.autoHideHd.mouseover);
50285 clearMonitor : function(){
50286 Roo.get(document).un("click", this.slideInIf, this);
50289 // these names are backwards but not changed for compat
50290 slideOut : function(){
50291 if(this.isSlid || this.el.hasActiveFx()){
50294 this.isSlid = true;
50295 if(this.collapseBtn){
50296 this.collapseBtn.hide();
50298 this.closeBtnState = this.closeBtn.getStyle('display');
50299 this.closeBtn.hide();
50301 this.stickBtn.show();
50304 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50305 this.beforeSlide();
50306 this.el.setStyle("z-index", 10001);
50307 this.el.slideIn(this.getSlideAnchor(), {
50308 callback: function(){
50310 this.initAutoHide();
50311 Roo.get(document).on("click", this.slideInIf, this);
50312 this.fireEvent("slideshow", this);
50319 afterSlideIn : function(){
50320 this.clearAutoHide();
50321 this.isSlid = false;
50322 this.clearMonitor();
50323 this.el.setStyle("z-index", "");
50324 if(this.collapseBtn){
50325 this.collapseBtn.show();
50327 this.closeBtn.setStyle('display', this.closeBtnState);
50329 this.stickBtn.hide();
50331 this.fireEvent("slidehide", this);
50334 slideIn : function(cb){
50335 if(!this.isSlid || this.el.hasActiveFx()){
50339 this.isSlid = false;
50340 this.beforeSlide();
50341 this.el.slideOut(this.getSlideAnchor(), {
50342 callback: function(){
50343 this.el.setLeftTop(-10000, -10000);
50345 this.afterSlideIn();
50353 slideInIf : function(e){
50354 if(!e.within(this.el)){
50359 animateCollapse : function(){
50360 this.beforeSlide();
50361 this.el.setStyle("z-index", 20000);
50362 var anchor = this.getSlideAnchor();
50363 this.el.slideOut(anchor, {
50364 callback : function(){
50365 this.el.setStyle("z-index", "");
50366 this.collapsedEl.slideIn(anchor, {duration:.3});
50368 this.el.setLocation(-10000,-10000);
50370 this.fireEvent("collapsed", this);
50377 animateExpand : function(){
50378 this.beforeSlide();
50379 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50380 this.el.setStyle("z-index", 20000);
50381 this.collapsedEl.hide({
50384 this.el.slideIn(this.getSlideAnchor(), {
50385 callback : function(){
50386 this.el.setStyle("z-index", "");
50389 this.split.el.show();
50391 this.fireEvent("invalidated", this);
50392 this.fireEvent("expanded", this);
50420 getAnchor : function(){
50421 return this.anchors[this.position];
50424 getCollapseAnchor : function(){
50425 return this.canchors[this.position];
50428 getSlideAnchor : function(){
50429 return this.sanchors[this.position];
50432 getAlignAdj : function(){
50433 var cm = this.cmargins;
50434 switch(this.position){
50450 getExpandAdj : function(){
50451 var c = this.collapsedEl, cm = this.cmargins;
50452 switch(this.position){
50454 return [-(cm.right+c.getWidth()+cm.left), 0];
50457 return [cm.right+c.getWidth()+cm.left, 0];
50460 return [0, -(cm.top+cm.bottom+c.getHeight())];
50463 return [0, cm.top+cm.bottom+c.getHeight()];
50469 * Ext JS Library 1.1.1
50470 * Copyright(c) 2006-2007, Ext JS, LLC.
50472 * Originally Released Under LGPL - original licence link has changed is not relivant.
50475 * <script type="text/javascript">
50478 * These classes are private internal classes
50480 Roo.CenterLayoutRegion = function(mgr, config){
50481 Roo.LayoutRegion.call(this, mgr, config, "center");
50482 this.visible = true;
50483 this.minWidth = config.minWidth || 20;
50484 this.minHeight = config.minHeight || 20;
50487 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50489 // center panel can't be hidden
50493 // center panel can't be hidden
50496 getMinWidth: function(){
50497 return this.minWidth;
50500 getMinHeight: function(){
50501 return this.minHeight;
50506 Roo.NorthLayoutRegion = function(mgr, config){
50507 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50509 this.split.placement = Roo.SplitBar.TOP;
50510 this.split.orientation = Roo.SplitBar.VERTICAL;
50511 this.split.el.addClass("x-layout-split-v");
50513 var size = config.initialSize || config.height;
50514 if(typeof size != "undefined"){
50515 this.el.setHeight(size);
50518 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50519 orientation: Roo.SplitBar.VERTICAL,
50520 getBox : function(){
50521 if(this.collapsed){
50522 return this.collapsedEl.getBox();
50524 var box = this.el.getBox();
50526 box.height += this.split.el.getHeight();
50531 updateBox : function(box){
50532 if(this.split && !this.collapsed){
50533 box.height -= this.split.el.getHeight();
50534 this.split.el.setLeft(box.x);
50535 this.split.el.setTop(box.y+box.height);
50536 this.split.el.setWidth(box.width);
50538 if(this.collapsed){
50539 this.updateBody(box.width, null);
50541 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50545 Roo.SouthLayoutRegion = function(mgr, config){
50546 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50548 this.split.placement = Roo.SplitBar.BOTTOM;
50549 this.split.orientation = Roo.SplitBar.VERTICAL;
50550 this.split.el.addClass("x-layout-split-v");
50552 var size = config.initialSize || config.height;
50553 if(typeof size != "undefined"){
50554 this.el.setHeight(size);
50557 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50558 orientation: Roo.SplitBar.VERTICAL,
50559 getBox : function(){
50560 if(this.collapsed){
50561 return this.collapsedEl.getBox();
50563 var box = this.el.getBox();
50565 var sh = this.split.el.getHeight();
50572 updateBox : function(box){
50573 if(this.split && !this.collapsed){
50574 var sh = this.split.el.getHeight();
50577 this.split.el.setLeft(box.x);
50578 this.split.el.setTop(box.y-sh);
50579 this.split.el.setWidth(box.width);
50581 if(this.collapsed){
50582 this.updateBody(box.width, null);
50584 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50588 Roo.EastLayoutRegion = function(mgr, config){
50589 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50591 this.split.placement = Roo.SplitBar.RIGHT;
50592 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50593 this.split.el.addClass("x-layout-split-h");
50595 var size = config.initialSize || config.width;
50596 if(typeof size != "undefined"){
50597 this.el.setWidth(size);
50600 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50601 orientation: Roo.SplitBar.HORIZONTAL,
50602 getBox : function(){
50603 if(this.collapsed){
50604 return this.collapsedEl.getBox();
50606 var box = this.el.getBox();
50608 var sw = this.split.el.getWidth();
50615 updateBox : function(box){
50616 if(this.split && !this.collapsed){
50617 var sw = this.split.el.getWidth();
50619 this.split.el.setLeft(box.x);
50620 this.split.el.setTop(box.y);
50621 this.split.el.setHeight(box.height);
50624 if(this.collapsed){
50625 this.updateBody(null, box.height);
50627 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50631 Roo.WestLayoutRegion = function(mgr, config){
50632 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50634 this.split.placement = Roo.SplitBar.LEFT;
50635 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50636 this.split.el.addClass("x-layout-split-h");
50638 var size = config.initialSize || config.width;
50639 if(typeof size != "undefined"){
50640 this.el.setWidth(size);
50643 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50644 orientation: Roo.SplitBar.HORIZONTAL,
50645 getBox : function(){
50646 if(this.collapsed){
50647 return this.collapsedEl.getBox();
50649 var box = this.el.getBox();
50651 box.width += this.split.el.getWidth();
50656 updateBox : function(box){
50657 if(this.split && !this.collapsed){
50658 var sw = this.split.el.getWidth();
50660 this.split.el.setLeft(box.x+box.width);
50661 this.split.el.setTop(box.y);
50662 this.split.el.setHeight(box.height);
50664 if(this.collapsed){
50665 this.updateBody(null, box.height);
50667 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50672 * Ext JS Library 1.1.1
50673 * Copyright(c) 2006-2007, Ext JS, LLC.
50675 * Originally Released Under LGPL - original licence link has changed is not relivant.
50678 * <script type="text/javascript">
50683 * Private internal class for reading and applying state
50685 Roo.LayoutStateManager = function(layout){
50686 // default empty state
50695 Roo.LayoutStateManager.prototype = {
50696 init : function(layout, provider){
50697 this.provider = provider;
50698 var state = provider.get(layout.id+"-layout-state");
50700 var wasUpdating = layout.isUpdating();
50702 layout.beginUpdate();
50704 for(var key in state){
50705 if(typeof state[key] != "function"){
50706 var rstate = state[key];
50707 var r = layout.getRegion(key);
50710 r.resizeTo(rstate.size);
50712 if(rstate.collapsed == true){
50715 r.expand(null, true);
50721 layout.endUpdate();
50723 this.state = state;
50725 this.layout = layout;
50726 layout.on("regionresized", this.onRegionResized, this);
50727 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50728 layout.on("regionexpanded", this.onRegionExpanded, this);
50731 storeState : function(){
50732 this.provider.set(this.layout.id+"-layout-state", this.state);
50735 onRegionResized : function(region, newSize){
50736 this.state[region.getPosition()].size = newSize;
50740 onRegionCollapsed : function(region){
50741 this.state[region.getPosition()].collapsed = true;
50745 onRegionExpanded : function(region){
50746 this.state[region.getPosition()].collapsed = false;
50751 * Ext JS Library 1.1.1
50752 * Copyright(c) 2006-2007, Ext JS, LLC.
50754 * Originally Released Under LGPL - original licence link has changed is not relivant.
50757 * <script type="text/javascript">
50760 * @class Roo.ContentPanel
50761 * @extends Roo.util.Observable
50762 * A basic ContentPanel element.
50763 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50764 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50765 * @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
50766 * @cfg {Boolean} closable True if the panel can be closed/removed
50767 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50768 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50769 * @cfg {Toolbar} toolbar A toolbar for this panel
50770 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50771 * @cfg {String} title The title for this panel
50772 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50773 * @cfg {String} url Calls {@link #setUrl} with this value
50774 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50775 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50776 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50777 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50780 * Create a new ContentPanel.
50781 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50782 * @param {String/Object} config A string to set only the title or a config object
50783 * @param {String} content (optional) Set the HTML content for this panel
50784 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50786 Roo.ContentPanel = function(el, config, content){
50790 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50794 if (config && config.parentLayout) {
50795 el = config.parentLayout.el.createChild();
50798 if(el.autoCreate){ // xtype is available if this is called from factory
50802 this.el = Roo.get(el);
50803 if(!this.el && config && config.autoCreate){
50804 if(typeof config.autoCreate == "object"){
50805 if(!config.autoCreate.id){
50806 config.autoCreate.id = config.id||el;
50808 this.el = Roo.DomHelper.append(document.body,
50809 config.autoCreate, true);
50811 this.el = Roo.DomHelper.append(document.body,
50812 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50815 this.closable = false;
50816 this.loaded = false;
50817 this.active = false;
50818 if(typeof config == "string"){
50819 this.title = config;
50821 Roo.apply(this, config);
50824 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50825 this.wrapEl = this.el.wrap();
50826 this.toolbar.container = this.el.insertSibling(false, 'before');
50827 this.toolbar = new Roo.Toolbar(this.toolbar);
50830 // xtype created footer. - not sure if will work as we normally have to render first..
50831 if (this.footer && !this.footer.el && this.footer.xtype) {
50832 if (!this.wrapEl) {
50833 this.wrapEl = this.el.wrap();
50836 this.footer.container = this.wrapEl.createChild();
50838 this.footer = Roo.factory(this.footer, Roo);
50843 this.resizeEl = Roo.get(this.resizeEl, true);
50845 this.resizeEl = this.el;
50847 // handle view.xtype
50855 * Fires when this panel is activated.
50856 * @param {Roo.ContentPanel} this
50860 * @event deactivate
50861 * Fires when this panel is activated.
50862 * @param {Roo.ContentPanel} this
50864 "deactivate" : true,
50868 * Fires when this panel is resized if fitToFrame is true.
50869 * @param {Roo.ContentPanel} this
50870 * @param {Number} width The width after any component adjustments
50871 * @param {Number} height The height after any component adjustments
50877 * Fires when this tab is created
50878 * @param {Roo.ContentPanel} this
50889 if(this.autoScroll){
50890 this.resizeEl.setStyle("overflow", "auto");
50892 // fix randome scrolling
50893 this.el.on('scroll', function() {
50894 Roo.log('fix random scolling');
50895 this.scrollTo('top',0);
50898 content = content || this.content;
50900 this.setContent(content);
50902 if(config && config.url){
50903 this.setUrl(this.url, this.params, this.loadOnce);
50908 Roo.ContentPanel.superclass.constructor.call(this);
50910 if (this.view && typeof(this.view.xtype) != 'undefined') {
50911 this.view.el = this.el.appendChild(document.createElement("div"));
50912 this.view = Roo.factory(this.view);
50913 this.view.render && this.view.render(false, '');
50917 this.fireEvent('render', this);
50920 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50922 setRegion : function(region){
50923 this.region = region;
50925 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50927 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50932 * Returns the toolbar for this Panel if one was configured.
50933 * @return {Roo.Toolbar}
50935 getToolbar : function(){
50936 return this.toolbar;
50939 setActiveState : function(active){
50940 this.active = active;
50942 this.fireEvent("deactivate", this);
50944 this.fireEvent("activate", this);
50948 * Updates this panel's element
50949 * @param {String} content The new content
50950 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50952 setContent : function(content, loadScripts){
50953 this.el.update(content, loadScripts);
50956 ignoreResize : function(w, h){
50957 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50960 this.lastSize = {width: w, height: h};
50965 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50966 * @return {Roo.UpdateManager} The UpdateManager
50968 getUpdateManager : function(){
50969 return this.el.getUpdateManager();
50972 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50973 * @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:
50976 url: "your-url.php",
50977 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50978 callback: yourFunction,
50979 scope: yourObject, //(optional scope)
50982 text: "Loading...",
50987 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50988 * 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.
50989 * @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}
50990 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50991 * @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.
50992 * @return {Roo.ContentPanel} this
50995 var um = this.el.getUpdateManager();
50996 um.update.apply(um, arguments);
51002 * 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.
51003 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51004 * @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)
51005 * @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)
51006 * @return {Roo.UpdateManager} The UpdateManager
51008 setUrl : function(url, params, loadOnce){
51009 if(this.refreshDelegate){
51010 this.removeListener("activate", this.refreshDelegate);
51012 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51013 this.on("activate", this.refreshDelegate);
51014 return this.el.getUpdateManager();
51017 _handleRefresh : function(url, params, loadOnce){
51018 if(!loadOnce || !this.loaded){
51019 var updater = this.el.getUpdateManager();
51020 updater.update(url, params, this._setLoaded.createDelegate(this));
51024 _setLoaded : function(){
51025 this.loaded = true;
51029 * Returns this panel's id
51032 getId : function(){
51037 * Returns this panel's element - used by regiosn to add.
51038 * @return {Roo.Element}
51040 getEl : function(){
51041 return this.wrapEl || this.el;
51044 adjustForComponents : function(width, height)
51046 //Roo.log('adjustForComponents ');
51047 if(this.resizeEl != this.el){
51048 width -= this.el.getFrameWidth('lr');
51049 height -= this.el.getFrameWidth('tb');
51052 var te = this.toolbar.getEl();
51053 height -= te.getHeight();
51054 te.setWidth(width);
51057 var te = this.footer.getEl();
51058 Roo.log("footer:" + te.getHeight());
51060 height -= te.getHeight();
51061 te.setWidth(width);
51065 if(this.adjustments){
51066 width += this.adjustments[0];
51067 height += this.adjustments[1];
51069 return {"width": width, "height": height};
51072 setSize : function(width, height){
51073 if(this.fitToFrame && !this.ignoreResize(width, height)){
51074 if(this.fitContainer && this.resizeEl != this.el){
51075 this.el.setSize(width, height);
51077 var size = this.adjustForComponents(width, height);
51078 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51079 this.fireEvent('resize', this, size.width, size.height);
51084 * Returns this panel's title
51087 getTitle : function(){
51092 * Set this panel's title
51093 * @param {String} title
51095 setTitle : function(title){
51096 this.title = title;
51098 this.region.updatePanelTitle(this, title);
51103 * Returns true is this panel was configured to be closable
51104 * @return {Boolean}
51106 isClosable : function(){
51107 return this.closable;
51110 beforeSlide : function(){
51112 this.resizeEl.clip();
51115 afterSlide : function(){
51117 this.resizeEl.unclip();
51121 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51122 * Will fail silently if the {@link #setUrl} method has not been called.
51123 * This does not activate the panel, just updates its content.
51125 refresh : function(){
51126 if(this.refreshDelegate){
51127 this.loaded = false;
51128 this.refreshDelegate();
51133 * Destroys this panel
51135 destroy : function(){
51136 this.el.removeAllListeners();
51137 var tempEl = document.createElement("span");
51138 tempEl.appendChild(this.el.dom);
51139 tempEl.innerHTML = "";
51145 * form - if the content panel contains a form - this is a reference to it.
51146 * @type {Roo.form.Form}
51150 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51151 * This contains a reference to it.
51157 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51167 * @param {Object} cfg Xtype definition of item to add.
51170 addxtype : function(cfg) {
51172 if (cfg.xtype.match(/^Form$/)) {
51175 //if (this.footer) {
51176 // el = this.footer.container.insertSibling(false, 'before');
51178 el = this.el.createChild();
51181 this.form = new Roo.form.Form(cfg);
51184 if ( this.form.allItems.length) this.form.render(el.dom);
51187 // should only have one of theses..
51188 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51189 // views.. should not be just added - used named prop 'view''
51191 cfg.el = this.el.appendChild(document.createElement("div"));
51194 var ret = new Roo.factory(cfg);
51196 ret.render && ret.render(false, ''); // render blank..
51205 * @class Roo.GridPanel
51206 * @extends Roo.ContentPanel
51208 * Create a new GridPanel.
51209 * @param {Roo.grid.Grid} grid The grid for this panel
51210 * @param {String/Object} config A string to set only the panel's title, or a config object
51212 Roo.GridPanel = function(grid, config){
51215 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51216 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51218 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51220 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51223 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51225 // xtype created footer. - not sure if will work as we normally have to render first..
51226 if (this.footer && !this.footer.el && this.footer.xtype) {
51228 this.footer.container = this.grid.getView().getFooterPanel(true);
51229 this.footer.dataSource = this.grid.dataSource;
51230 this.footer = Roo.factory(this.footer, Roo);
51234 grid.monitorWindowResize = false; // turn off autosizing
51235 grid.autoHeight = false;
51236 grid.autoWidth = false;
51238 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51241 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51242 getId : function(){
51243 return this.grid.id;
51247 * Returns the grid for this panel
51248 * @return {Roo.grid.Grid}
51250 getGrid : function(){
51254 setSize : function(width, height){
51255 if(!this.ignoreResize(width, height)){
51256 var grid = this.grid;
51257 var size = this.adjustForComponents(width, height);
51258 grid.getGridEl().setSize(size.width, size.height);
51263 beforeSlide : function(){
51264 this.grid.getView().scroller.clip();
51267 afterSlide : function(){
51268 this.grid.getView().scroller.unclip();
51271 destroy : function(){
51272 this.grid.destroy();
51274 Roo.GridPanel.superclass.destroy.call(this);
51280 * @class Roo.NestedLayoutPanel
51281 * @extends Roo.ContentPanel
51283 * Create a new NestedLayoutPanel.
51286 * @param {Roo.BorderLayout} layout The layout for this panel
51287 * @param {String/Object} config A string to set only the title or a config object
51289 Roo.NestedLayoutPanel = function(layout, config)
51291 // construct with only one argument..
51292 /* FIXME - implement nicer consturctors
51293 if (layout.layout) {
51295 layout = config.layout;
51296 delete config.layout;
51298 if (layout.xtype && !layout.getEl) {
51299 // then layout needs constructing..
51300 layout = Roo.factory(layout, Roo);
51305 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51307 layout.monitorWindowResize = false; // turn off autosizing
51308 this.layout = layout;
51309 this.layout.getEl().addClass("x-layout-nested-layout");
51316 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51318 setSize : function(width, height){
51319 if(!this.ignoreResize(width, height)){
51320 var size = this.adjustForComponents(width, height);
51321 var el = this.layout.getEl();
51322 el.setSize(size.width, size.height);
51323 var touch = el.dom.offsetWidth;
51324 this.layout.layout();
51325 // ie requires a double layout on the first pass
51326 if(Roo.isIE && !this.initialized){
51327 this.initialized = true;
51328 this.layout.layout();
51333 // activate all subpanels if not currently active..
51335 setActiveState : function(active){
51336 this.active = active;
51338 this.fireEvent("deactivate", this);
51342 this.fireEvent("activate", this);
51343 // not sure if this should happen before or after..
51344 if (!this.layout) {
51345 return; // should not happen..
51348 for (var r in this.layout.regions) {
51349 reg = this.layout.getRegion(r);
51350 if (reg.getActivePanel()) {
51351 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51352 reg.setActivePanel(reg.getActivePanel());
51355 if (!reg.panels.length) {
51358 reg.showPanel(reg.getPanel(0));
51367 * Returns the nested BorderLayout for this panel
51368 * @return {Roo.BorderLayout}
51370 getLayout : function(){
51371 return this.layout;
51375 * Adds a xtype elements to the layout of the nested panel
51379 xtype : 'ContentPanel',
51386 xtype : 'NestedLayoutPanel',
51392 items : [ ... list of content panels or nested layout panels.. ]
51396 * @param {Object} cfg Xtype definition of item to add.
51398 addxtype : function(cfg) {
51399 return this.layout.addxtype(cfg);
51404 Roo.ScrollPanel = function(el, config, content){
51405 config = config || {};
51406 config.fitToFrame = true;
51407 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51409 this.el.dom.style.overflow = "hidden";
51410 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51411 this.el.removeClass("x-layout-inactive-content");
51412 this.el.on("mousewheel", this.onWheel, this);
51414 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51415 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51416 up.unselectable(); down.unselectable();
51417 up.on("click", this.scrollUp, this);
51418 down.on("click", this.scrollDown, this);
51419 up.addClassOnOver("x-scroller-btn-over");
51420 down.addClassOnOver("x-scroller-btn-over");
51421 up.addClassOnClick("x-scroller-btn-click");
51422 down.addClassOnClick("x-scroller-btn-click");
51423 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51425 this.resizeEl = this.el;
51426 this.el = wrap; this.up = up; this.down = down;
51429 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51431 wheelIncrement : 5,
51432 scrollUp : function(){
51433 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51436 scrollDown : function(){
51437 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51440 afterScroll : function(){
51441 var el = this.resizeEl;
51442 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51443 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51444 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51447 setSize : function(){
51448 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51449 this.afterScroll();
51452 onWheel : function(e){
51453 var d = e.getWheelDelta();
51454 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51455 this.afterScroll();
51459 setContent : function(content, loadScripts){
51460 this.resizeEl.update(content, loadScripts);
51474 * @class Roo.TreePanel
51475 * @extends Roo.ContentPanel
51477 * Create a new TreePanel. - defaults to fit/scoll contents.
51478 * @param {String/Object} config A string to set only the panel's title, or a config object
51479 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51481 Roo.TreePanel = function(config){
51482 var el = config.el;
51483 var tree = config.tree;
51484 delete config.tree;
51485 delete config.el; // hopefull!
51487 // wrapper for IE7 strict & safari scroll issue
51489 var treeEl = el.createChild();
51490 config.resizeEl = treeEl;
51494 Roo.TreePanel.superclass.constructor.call(this, el, config);
51497 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51498 //console.log(tree);
51499 this.on('activate', function()
51501 if (this.tree.rendered) {
51504 //console.log('render tree');
51505 this.tree.render();
51507 // this should not be needed.. - it's actually the 'el' that resizes?
51508 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51510 //this.on('resize', function (cp, w, h) {
51511 // this.tree.innerCt.setWidth(w);
51512 // this.tree.innerCt.setHeight(h);
51513 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51520 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51537 * Ext JS Library 1.1.1
51538 * Copyright(c) 2006-2007, Ext JS, LLC.
51540 * Originally Released Under LGPL - original licence link has changed is not relivant.
51543 * <script type="text/javascript">
51548 * @class Roo.ReaderLayout
51549 * @extends Roo.BorderLayout
51550 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51551 * center region containing two nested regions (a top one for a list view and one for item preview below),
51552 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51553 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51554 * expedites the setup of the overall layout and regions for this common application style.
51557 var reader = new Roo.ReaderLayout();
51558 var CP = Roo.ContentPanel; // shortcut for adding
51560 reader.beginUpdate();
51561 reader.add("north", new CP("north", "North"));
51562 reader.add("west", new CP("west", {title: "West"}));
51563 reader.add("east", new CP("east", {title: "East"}));
51565 reader.regions.listView.add(new CP("listView", "List"));
51566 reader.regions.preview.add(new CP("preview", "Preview"));
51567 reader.endUpdate();
51570 * Create a new ReaderLayout
51571 * @param {Object} config Configuration options
51572 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51573 * document.body if omitted)
51575 Roo.ReaderLayout = function(config, renderTo){
51576 var c = config || {size:{}};
51577 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51578 north: c.north !== false ? Roo.apply({
51582 }, c.north) : false,
51583 west: c.west !== false ? Roo.apply({
51591 margins:{left:5,right:0,bottom:5,top:5},
51592 cmargins:{left:5,right:5,bottom:5,top:5}
51593 }, c.west) : false,
51594 east: c.east !== false ? Roo.apply({
51602 margins:{left:0,right:5,bottom:5,top:5},
51603 cmargins:{left:5,right:5,bottom:5,top:5}
51604 }, c.east) : false,
51605 center: Roo.apply({
51606 tabPosition: 'top',
51610 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51614 this.el.addClass('x-reader');
51616 this.beginUpdate();
51618 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51619 south: c.preview !== false ? Roo.apply({
51626 cmargins:{top:5,left:0, right:0, bottom:0}
51627 }, c.preview) : false,
51628 center: Roo.apply({
51634 this.add('center', new Roo.NestedLayoutPanel(inner,
51635 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51639 this.regions.preview = inner.getRegion('south');
51640 this.regions.listView = inner.getRegion('center');
51643 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51645 * Ext JS Library 1.1.1
51646 * Copyright(c) 2006-2007, Ext JS, LLC.
51648 * Originally Released Under LGPL - original licence link has changed is not relivant.
51651 * <script type="text/javascript">
51655 * @class Roo.grid.Grid
51656 * @extends Roo.util.Observable
51657 * This class represents the primary interface of a component based grid control.
51658 * <br><br>Usage:<pre><code>
51659 var grid = new Roo.grid.Grid("my-container-id", {
51662 selModel: mySelectionModel,
51663 autoSizeColumns: true,
51664 monitorWindowResize: false,
51665 trackMouseOver: true
51670 * <b>Common Problems:</b><br/>
51671 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51672 * element will correct this<br/>
51673 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51674 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51675 * are unpredictable.<br/>
51676 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51677 * grid to calculate dimensions/offsets.<br/>
51679 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51680 * The container MUST have some type of size defined for the grid to fill. The container will be
51681 * automatically set to position relative if it isn't already.
51682 * @param {Object} config A config object that sets properties on this grid.
51684 Roo.grid.Grid = function(container, config){
51685 // initialize the container
51686 this.container = Roo.get(container);
51687 this.container.update("");
51688 this.container.setStyle("overflow", "hidden");
51689 this.container.addClass('x-grid-container');
51691 this.id = this.container.id;
51693 Roo.apply(this, config);
51694 // check and correct shorthanded configs
51696 this.dataSource = this.ds;
51700 this.colModel = this.cm;
51704 this.selModel = this.sm;
51708 if (this.selModel) {
51709 this.selModel = Roo.factory(this.selModel, Roo.grid);
51710 this.sm = this.selModel;
51711 this.sm.xmodule = this.xmodule || false;
51713 if (typeof(this.colModel.config) == 'undefined') {
51714 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51715 this.cm = this.colModel;
51716 this.cm.xmodule = this.xmodule || false;
51718 if (this.dataSource) {
51719 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51720 this.ds = this.dataSource;
51721 this.ds.xmodule = this.xmodule || false;
51728 this.container.setWidth(this.width);
51732 this.container.setHeight(this.height);
51739 * The raw click event for the entire grid.
51740 * @param {Roo.EventObject} e
51745 * The raw dblclick event for the entire grid.
51746 * @param {Roo.EventObject} e
51750 * @event contextmenu
51751 * The raw contextmenu event for the entire grid.
51752 * @param {Roo.EventObject} e
51754 "contextmenu" : true,
51757 * The raw mousedown event for the entire grid.
51758 * @param {Roo.EventObject} e
51760 "mousedown" : true,
51763 * The raw mouseup event for the entire grid.
51764 * @param {Roo.EventObject} e
51769 * The raw mouseover event for the entire grid.
51770 * @param {Roo.EventObject} e
51772 "mouseover" : true,
51775 * The raw mouseout event for the entire grid.
51776 * @param {Roo.EventObject} e
51781 * The raw keypress event for the entire grid.
51782 * @param {Roo.EventObject} e
51787 * The raw keydown event for the entire grid.
51788 * @param {Roo.EventObject} e
51796 * Fires when a cell is clicked
51797 * @param {Grid} this
51798 * @param {Number} rowIndex
51799 * @param {Number} columnIndex
51800 * @param {Roo.EventObject} e
51802 "cellclick" : true,
51804 * @event celldblclick
51805 * Fires when a cell is double clicked
51806 * @param {Grid} this
51807 * @param {Number} rowIndex
51808 * @param {Number} columnIndex
51809 * @param {Roo.EventObject} e
51811 "celldblclick" : true,
51814 * Fires when a row is clicked
51815 * @param {Grid} this
51816 * @param {Number} rowIndex
51817 * @param {Roo.EventObject} e
51821 * @event rowdblclick
51822 * Fires when a row is double clicked
51823 * @param {Grid} this
51824 * @param {Number} rowIndex
51825 * @param {Roo.EventObject} e
51827 "rowdblclick" : true,
51829 * @event headerclick
51830 * Fires when a header is clicked
51831 * @param {Grid} this
51832 * @param {Number} columnIndex
51833 * @param {Roo.EventObject} e
51835 "headerclick" : true,
51837 * @event headerdblclick
51838 * Fires when a header cell is double clicked
51839 * @param {Grid} this
51840 * @param {Number} columnIndex
51841 * @param {Roo.EventObject} e
51843 "headerdblclick" : true,
51845 * @event rowcontextmenu
51846 * Fires when a row is right clicked
51847 * @param {Grid} this
51848 * @param {Number} rowIndex
51849 * @param {Roo.EventObject} e
51851 "rowcontextmenu" : true,
51853 * @event cellcontextmenu
51854 * Fires when a cell is right clicked
51855 * @param {Grid} this
51856 * @param {Number} rowIndex
51857 * @param {Number} cellIndex
51858 * @param {Roo.EventObject} e
51860 "cellcontextmenu" : true,
51862 * @event headercontextmenu
51863 * Fires when a header is right clicked
51864 * @param {Grid} this
51865 * @param {Number} columnIndex
51866 * @param {Roo.EventObject} e
51868 "headercontextmenu" : true,
51870 * @event bodyscroll
51871 * Fires when the body element is scrolled
51872 * @param {Number} scrollLeft
51873 * @param {Number} scrollTop
51875 "bodyscroll" : true,
51877 * @event columnresize
51878 * Fires when the user resizes a column
51879 * @param {Number} columnIndex
51880 * @param {Number} newSize
51882 "columnresize" : true,
51884 * @event columnmove
51885 * Fires when the user moves a column
51886 * @param {Number} oldIndex
51887 * @param {Number} newIndex
51889 "columnmove" : true,
51892 * Fires when row(s) start being dragged
51893 * @param {Grid} this
51894 * @param {Roo.GridDD} dd The drag drop object
51895 * @param {event} e The raw browser event
51897 "startdrag" : true,
51900 * Fires when a drag operation is complete
51901 * @param {Grid} this
51902 * @param {Roo.GridDD} dd The drag drop object
51903 * @param {event} e The raw browser event
51908 * Fires when dragged row(s) are dropped on a valid DD target
51909 * @param {Grid} this
51910 * @param {Roo.GridDD} dd The drag drop object
51911 * @param {String} targetId The target drag drop object
51912 * @param {event} e The raw browser event
51917 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51918 * @param {Grid} this
51919 * @param {Roo.GridDD} dd The drag drop object
51920 * @param {String} targetId The target drag drop object
51921 * @param {event} e The raw browser event
51926 * Fires when the dragged row(s) first cross another DD target while being dragged
51927 * @param {Grid} this
51928 * @param {Roo.GridDD} dd The drag drop object
51929 * @param {String} targetId The target drag drop object
51930 * @param {event} e The raw browser event
51932 "dragenter" : true,
51935 * Fires when the dragged row(s) leave another DD target while being dragged
51936 * @param {Grid} this
51937 * @param {Roo.GridDD} dd The drag drop object
51938 * @param {String} targetId The target drag drop object
51939 * @param {event} e The raw browser event
51944 * Fires when a row is rendered, so you can change add a style to it.
51945 * @param {GridView} gridview The grid view
51946 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51952 * Fires when the grid is rendered
51953 * @param {Grid} grid
51958 Roo.grid.Grid.superclass.constructor.call(this);
51960 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51963 * @cfg {String} ddGroup - drag drop group.
51967 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51969 minColumnWidth : 25,
51972 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51973 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51974 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51976 autoSizeColumns : false,
51979 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51981 autoSizeHeaders : true,
51984 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51986 monitorWindowResize : true,
51989 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51990 * rows measured to get a columns size. Default is 0 (all rows).
51992 maxRowsToMeasure : 0,
51995 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51997 trackMouseOver : true,
52000 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52004 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52006 enableDragDrop : false,
52009 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52011 enableColumnMove : true,
52014 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52016 enableColumnHide : true,
52019 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52021 enableRowHeightSync : false,
52024 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52029 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52031 autoHeight : false,
52034 * @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.
52036 autoExpandColumn : false,
52039 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52042 autoExpandMin : 50,
52045 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52047 autoExpandMax : 1000,
52050 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52055 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52059 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52069 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52070 * of a fixed width. Default is false.
52073 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52076 * Called once after all setup has been completed and the grid is ready to be rendered.
52077 * @return {Roo.grid.Grid} this
52079 render : function()
52081 var c = this.container;
52082 // try to detect autoHeight/width mode
52083 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52084 this.autoHeight = true;
52086 var view = this.getView();
52089 c.on("click", this.onClick, this);
52090 c.on("dblclick", this.onDblClick, this);
52091 c.on("contextmenu", this.onContextMenu, this);
52092 c.on("keydown", this.onKeyDown, this);
52094 c.on("touchstart", this.onTouchStart, this);
52097 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52099 this.getSelectionModel().init(this);
52104 this.loadMask = new Roo.LoadMask(this.container,
52105 Roo.apply({store:this.dataSource}, this.loadMask));
52109 if (this.toolbar && this.toolbar.xtype) {
52110 this.toolbar.container = this.getView().getHeaderPanel(true);
52111 this.toolbar = new Roo.Toolbar(this.toolbar);
52113 if (this.footer && this.footer.xtype) {
52114 this.footer.dataSource = this.getDataSource();
52115 this.footer.container = this.getView().getFooterPanel(true);
52116 this.footer = Roo.factory(this.footer, Roo);
52118 if (this.dropTarget && this.dropTarget.xtype) {
52119 delete this.dropTarget.xtype;
52120 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52124 this.rendered = true;
52125 this.fireEvent('render', this);
52130 * Reconfigures the grid to use a different Store and Column Model.
52131 * The View will be bound to the new objects and refreshed.
52132 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52133 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52135 reconfigure : function(dataSource, colModel){
52137 this.loadMask.destroy();
52138 this.loadMask = new Roo.LoadMask(this.container,
52139 Roo.apply({store:dataSource}, this.loadMask));
52141 this.view.bind(dataSource, colModel);
52142 this.dataSource = dataSource;
52143 this.colModel = colModel;
52144 this.view.refresh(true);
52148 onKeyDown : function(e){
52149 this.fireEvent("keydown", e);
52153 * Destroy this grid.
52154 * @param {Boolean} removeEl True to remove the element
52156 destroy : function(removeEl, keepListeners){
52158 this.loadMask.destroy();
52160 var c = this.container;
52161 c.removeAllListeners();
52162 this.view.destroy();
52163 this.colModel.purgeListeners();
52164 if(!keepListeners){
52165 this.purgeListeners();
52168 if(removeEl === true){
52174 processEvent : function(name, e){
52175 // does this fire select???
52176 Roo.log('grid:processEvent ' + name);
52178 if (name != 'touchstart' ) {
52179 this.fireEvent(name, e);
52182 var t = e.getTarget();
52184 var header = v.findHeaderIndex(t);
52185 if(header !== false){
52186 var ename = name == 'touchstart' ? 'click' : name;
52188 this.fireEvent("header" + ename, this, header, e);
52190 var row = v.findRowIndex(t);
52191 var cell = v.findCellIndex(t);
52192 if (name == 'touchstart') {
52193 // first touch is always a click.
52194 // hopefull this happens after selection is updated.?
52197 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52198 var cs = this.selModel.getSelectedCell();
52199 if (row == cs[0] && cell == cs[1]){
52203 if (typeof(this.selModel.getSelections) != 'undefined') {
52204 var cs = this.selModel.getSelections();
52205 var ds = this.dataSource;
52206 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52217 this.fireEvent("row" + name, this, row, e);
52218 if(cell !== false){
52219 this.fireEvent("cell" + name, this, row, cell, e);
52226 onClick : function(e){
52227 this.processEvent("click", e);
52230 onTouchStart : function(e){
52231 this.processEvent("touchstart", e);
52235 onContextMenu : function(e, t){
52236 this.processEvent("contextmenu", e);
52240 onDblClick : function(e){
52241 this.processEvent("dblclick", e);
52245 walkCells : function(row, col, step, fn, scope){
52246 var cm = this.colModel, clen = cm.getColumnCount();
52247 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52259 if(fn.call(scope || this, row, col, cm) === true){
52277 if(fn.call(scope || this, row, col, cm) === true){
52289 getSelections : function(){
52290 return this.selModel.getSelections();
52294 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52295 * but if manual update is required this method will initiate it.
52297 autoSize : function(){
52299 this.view.layout();
52300 if(this.view.adjustForScroll){
52301 this.view.adjustForScroll();
52307 * Returns the grid's underlying element.
52308 * @return {Element} The element
52310 getGridEl : function(){
52311 return this.container;
52314 // private for compatibility, overridden by editor grid
52315 stopEditing : function(){},
52318 * Returns the grid's SelectionModel.
52319 * @return {SelectionModel}
52321 getSelectionModel : function(){
52322 if(!this.selModel){
52323 this.selModel = new Roo.grid.RowSelectionModel();
52325 return this.selModel;
52329 * Returns the grid's DataSource.
52330 * @return {DataSource}
52332 getDataSource : function(){
52333 return this.dataSource;
52337 * Returns the grid's ColumnModel.
52338 * @return {ColumnModel}
52340 getColumnModel : function(){
52341 return this.colModel;
52345 * Returns the grid's GridView object.
52346 * @return {GridView}
52348 getView : function(){
52350 this.view = new Roo.grid.GridView(this.viewConfig);
52355 * Called to get grid's drag proxy text, by default returns this.ddText.
52358 getDragDropText : function(){
52359 var count = this.selModel.getCount();
52360 return String.format(this.ddText, count, count == 1 ? '' : 's');
52364 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52365 * %0 is replaced with the number of selected rows.
52368 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52370 * Ext JS Library 1.1.1
52371 * Copyright(c) 2006-2007, Ext JS, LLC.
52373 * Originally Released Under LGPL - original licence link has changed is not relivant.
52376 * <script type="text/javascript">
52379 Roo.grid.AbstractGridView = function(){
52383 "beforerowremoved" : true,
52384 "beforerowsinserted" : true,
52385 "beforerefresh" : true,
52386 "rowremoved" : true,
52387 "rowsinserted" : true,
52388 "rowupdated" : true,
52391 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52394 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52395 rowClass : "x-grid-row",
52396 cellClass : "x-grid-cell",
52397 tdClass : "x-grid-td",
52398 hdClass : "x-grid-hd",
52399 splitClass : "x-grid-hd-split",
52401 init: function(grid){
52403 var cid = this.grid.getGridEl().id;
52404 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52405 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52406 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52407 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52410 getColumnRenderers : function(){
52411 var renderers = [];
52412 var cm = this.grid.colModel;
52413 var colCount = cm.getColumnCount();
52414 for(var i = 0; i < colCount; i++){
52415 renderers[i] = cm.getRenderer(i);
52420 getColumnIds : function(){
52422 var cm = this.grid.colModel;
52423 var colCount = cm.getColumnCount();
52424 for(var i = 0; i < colCount; i++){
52425 ids[i] = cm.getColumnId(i);
52430 getDataIndexes : function(){
52431 if(!this.indexMap){
52432 this.indexMap = this.buildIndexMap();
52434 return this.indexMap.colToData;
52437 getColumnIndexByDataIndex : function(dataIndex){
52438 if(!this.indexMap){
52439 this.indexMap = this.buildIndexMap();
52441 return this.indexMap.dataToCol[dataIndex];
52445 * Set a css style for a column dynamically.
52446 * @param {Number} colIndex The index of the column
52447 * @param {String} name The css property name
52448 * @param {String} value The css value
52450 setCSSStyle : function(colIndex, name, value){
52451 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52452 Roo.util.CSS.updateRule(selector, name, value);
52455 generateRules : function(cm){
52456 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52457 Roo.util.CSS.removeStyleSheet(rulesId);
52458 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52459 var cid = cm.getColumnId(i);
52460 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52461 this.tdSelector, cid, " {\n}\n",
52462 this.hdSelector, cid, " {\n}\n",
52463 this.splitSelector, cid, " {\n}\n");
52465 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52469 * Ext JS Library 1.1.1
52470 * Copyright(c) 2006-2007, Ext JS, LLC.
52472 * Originally Released Under LGPL - original licence link has changed is not relivant.
52475 * <script type="text/javascript">
52479 // This is a support class used internally by the Grid components
52480 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52482 this.view = grid.getView();
52483 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52484 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52486 this.setHandleElId(Roo.id(hd));
52487 this.setOuterHandleElId(Roo.id(hd2));
52489 this.scroll = false;
52491 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52493 getDragData : function(e){
52494 var t = Roo.lib.Event.getTarget(e);
52495 var h = this.view.findHeaderCell(t);
52497 return {ddel: h.firstChild, header:h};
52502 onInitDrag : function(e){
52503 this.view.headersDisabled = true;
52504 var clone = this.dragData.ddel.cloneNode(true);
52505 clone.id = Roo.id();
52506 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52507 this.proxy.update(clone);
52511 afterValidDrop : function(){
52513 setTimeout(function(){
52514 v.headersDisabled = false;
52518 afterInvalidDrop : function(){
52520 setTimeout(function(){
52521 v.headersDisabled = false;
52527 * Ext JS Library 1.1.1
52528 * Copyright(c) 2006-2007, Ext JS, LLC.
52530 * Originally Released Under LGPL - original licence link has changed is not relivant.
52533 * <script type="text/javascript">
52536 // This is a support class used internally by the Grid components
52537 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52539 this.view = grid.getView();
52540 // split the proxies so they don't interfere with mouse events
52541 this.proxyTop = Roo.DomHelper.append(document.body, {
52542 cls:"col-move-top", html:" "
52544 this.proxyBottom = Roo.DomHelper.append(document.body, {
52545 cls:"col-move-bottom", html:" "
52547 this.proxyTop.hide = this.proxyBottom.hide = function(){
52548 this.setLeftTop(-100,-100);
52549 this.setStyle("visibility", "hidden");
52551 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52552 // temporarily disabled
52553 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52554 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52556 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52557 proxyOffsets : [-4, -9],
52558 fly: Roo.Element.fly,
52560 getTargetFromEvent : function(e){
52561 var t = Roo.lib.Event.getTarget(e);
52562 var cindex = this.view.findCellIndex(t);
52563 if(cindex !== false){
52564 return this.view.getHeaderCell(cindex);
52569 nextVisible : function(h){
52570 var v = this.view, cm = this.grid.colModel;
52573 if(!cm.isHidden(v.getCellIndex(h))){
52581 prevVisible : function(h){
52582 var v = this.view, cm = this.grid.colModel;
52585 if(!cm.isHidden(v.getCellIndex(h))){
52593 positionIndicator : function(h, n, e){
52594 var x = Roo.lib.Event.getPageX(e);
52595 var r = Roo.lib.Dom.getRegion(n.firstChild);
52596 var px, pt, py = r.top + this.proxyOffsets[1];
52597 if((r.right - x) <= (r.right-r.left)/2){
52598 px = r.right+this.view.borderWidth;
52604 var oldIndex = this.view.getCellIndex(h);
52605 var newIndex = this.view.getCellIndex(n);
52607 if(this.grid.colModel.isFixed(newIndex)){
52611 var locked = this.grid.colModel.isLocked(newIndex);
52616 if(oldIndex < newIndex){
52619 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52622 px += this.proxyOffsets[0];
52623 this.proxyTop.setLeftTop(px, py);
52624 this.proxyTop.show();
52625 if(!this.bottomOffset){
52626 this.bottomOffset = this.view.mainHd.getHeight();
52628 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52629 this.proxyBottom.show();
52633 onNodeEnter : function(n, dd, e, data){
52634 if(data.header != n){
52635 this.positionIndicator(data.header, n, e);
52639 onNodeOver : function(n, dd, e, data){
52640 var result = false;
52641 if(data.header != n){
52642 result = this.positionIndicator(data.header, n, e);
52645 this.proxyTop.hide();
52646 this.proxyBottom.hide();
52648 return result ? this.dropAllowed : this.dropNotAllowed;
52651 onNodeOut : function(n, dd, e, data){
52652 this.proxyTop.hide();
52653 this.proxyBottom.hide();
52656 onNodeDrop : function(n, dd, e, data){
52657 var h = data.header;
52659 var cm = this.grid.colModel;
52660 var x = Roo.lib.Event.getPageX(e);
52661 var r = Roo.lib.Dom.getRegion(n.firstChild);
52662 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52663 var oldIndex = this.view.getCellIndex(h);
52664 var newIndex = this.view.getCellIndex(n);
52665 var locked = cm.isLocked(newIndex);
52669 if(oldIndex < newIndex){
52672 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52675 cm.setLocked(oldIndex, locked, true);
52676 cm.moveColumn(oldIndex, newIndex);
52677 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52685 * Ext JS Library 1.1.1
52686 * Copyright(c) 2006-2007, Ext JS, LLC.
52688 * Originally Released Under LGPL - original licence link has changed is not relivant.
52691 * <script type="text/javascript">
52695 * @class Roo.grid.GridView
52696 * @extends Roo.util.Observable
52699 * @param {Object} config
52701 Roo.grid.GridView = function(config){
52702 Roo.grid.GridView.superclass.constructor.call(this);
52705 Roo.apply(this, config);
52708 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52710 unselectable : 'unselectable="on"',
52711 unselectableCls : 'x-unselectable',
52714 rowClass : "x-grid-row",
52716 cellClass : "x-grid-col",
52718 tdClass : "x-grid-td",
52720 hdClass : "x-grid-hd",
52722 splitClass : "x-grid-split",
52724 sortClasses : ["sort-asc", "sort-desc"],
52726 enableMoveAnim : false,
52730 dh : Roo.DomHelper,
52732 fly : Roo.Element.fly,
52734 css : Roo.util.CSS,
52740 scrollIncrement : 22,
52742 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52744 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52746 bind : function(ds, cm){
52748 this.ds.un("load", this.onLoad, this);
52749 this.ds.un("datachanged", this.onDataChange, this);
52750 this.ds.un("add", this.onAdd, this);
52751 this.ds.un("remove", this.onRemove, this);
52752 this.ds.un("update", this.onUpdate, this);
52753 this.ds.un("clear", this.onClear, this);
52756 ds.on("load", this.onLoad, this);
52757 ds.on("datachanged", this.onDataChange, this);
52758 ds.on("add", this.onAdd, this);
52759 ds.on("remove", this.onRemove, this);
52760 ds.on("update", this.onUpdate, this);
52761 ds.on("clear", this.onClear, this);
52766 this.cm.un("widthchange", this.onColWidthChange, this);
52767 this.cm.un("headerchange", this.onHeaderChange, this);
52768 this.cm.un("hiddenchange", this.onHiddenChange, this);
52769 this.cm.un("columnmoved", this.onColumnMove, this);
52770 this.cm.un("columnlockchange", this.onColumnLock, this);
52773 this.generateRules(cm);
52774 cm.on("widthchange", this.onColWidthChange, this);
52775 cm.on("headerchange", this.onHeaderChange, this);
52776 cm.on("hiddenchange", this.onHiddenChange, this);
52777 cm.on("columnmoved", this.onColumnMove, this);
52778 cm.on("columnlockchange", this.onColumnLock, this);
52783 init: function(grid){
52784 Roo.grid.GridView.superclass.init.call(this, grid);
52786 this.bind(grid.dataSource, grid.colModel);
52788 grid.on("headerclick", this.handleHeaderClick, this);
52790 if(grid.trackMouseOver){
52791 grid.on("mouseover", this.onRowOver, this);
52792 grid.on("mouseout", this.onRowOut, this);
52794 grid.cancelTextSelection = function(){};
52795 this.gridId = grid.id;
52797 var tpls = this.templates || {};
52800 tpls.master = new Roo.Template(
52801 '<div class="x-grid" hidefocus="true">',
52802 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52803 '<div class="x-grid-topbar"></div>',
52804 '<div class="x-grid-scroller"><div></div></div>',
52805 '<div class="x-grid-locked">',
52806 '<div class="x-grid-header">{lockedHeader}</div>',
52807 '<div class="x-grid-body">{lockedBody}</div>',
52809 '<div class="x-grid-viewport">',
52810 '<div class="x-grid-header">{header}</div>',
52811 '<div class="x-grid-body">{body}</div>',
52813 '<div class="x-grid-bottombar"></div>',
52815 '<div class="x-grid-resize-proxy"> </div>',
52818 tpls.master.disableformats = true;
52822 tpls.header = new Roo.Template(
52823 '<table border="0" cellspacing="0" cellpadding="0">',
52824 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52827 tpls.header.disableformats = true;
52829 tpls.header.compile();
52832 tpls.hcell = new Roo.Template(
52833 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52834 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52837 tpls.hcell.disableFormats = true;
52839 tpls.hcell.compile();
52842 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52843 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52844 tpls.hsplit.disableFormats = true;
52846 tpls.hsplit.compile();
52849 tpls.body = new Roo.Template(
52850 '<table border="0" cellspacing="0" cellpadding="0">',
52851 "<tbody>{rows}</tbody>",
52854 tpls.body.disableFormats = true;
52856 tpls.body.compile();
52859 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52860 tpls.row.disableFormats = true;
52862 tpls.row.compile();
52865 tpls.cell = new Roo.Template(
52866 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52867 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52868 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52871 tpls.cell.disableFormats = true;
52873 tpls.cell.compile();
52875 this.templates = tpls;
52878 // remap these for backwards compat
52879 onColWidthChange : function(){
52880 this.updateColumns.apply(this, arguments);
52882 onHeaderChange : function(){
52883 this.updateHeaders.apply(this, arguments);
52885 onHiddenChange : function(){
52886 this.handleHiddenChange.apply(this, arguments);
52888 onColumnMove : function(){
52889 this.handleColumnMove.apply(this, arguments);
52891 onColumnLock : function(){
52892 this.handleLockChange.apply(this, arguments);
52895 onDataChange : function(){
52897 this.updateHeaderSortState();
52900 onClear : function(){
52904 onUpdate : function(ds, record){
52905 this.refreshRow(record);
52908 refreshRow : function(record){
52909 var ds = this.ds, index;
52910 if(typeof record == 'number'){
52912 record = ds.getAt(index);
52914 index = ds.indexOf(record);
52916 this.insertRows(ds, index, index, true);
52917 this.onRemove(ds, record, index+1, true);
52918 this.syncRowHeights(index, index);
52920 this.fireEvent("rowupdated", this, index, record);
52923 onAdd : function(ds, records, index){
52924 this.insertRows(ds, index, index + (records.length-1));
52927 onRemove : function(ds, record, index, isUpdate){
52928 if(isUpdate !== true){
52929 this.fireEvent("beforerowremoved", this, index, record);
52931 var bt = this.getBodyTable(), lt = this.getLockedTable();
52932 if(bt.rows[index]){
52933 bt.firstChild.removeChild(bt.rows[index]);
52935 if(lt.rows[index]){
52936 lt.firstChild.removeChild(lt.rows[index]);
52938 if(isUpdate !== true){
52939 this.stripeRows(index);
52940 this.syncRowHeights(index, index);
52942 this.fireEvent("rowremoved", this, index, record);
52946 onLoad : function(){
52947 this.scrollToTop();
52951 * Scrolls the grid to the top
52953 scrollToTop : function(){
52955 this.scroller.dom.scrollTop = 0;
52961 * Gets a panel in the header of the grid that can be used for toolbars etc.
52962 * After modifying the contents of this panel a call to grid.autoSize() may be
52963 * required to register any changes in size.
52964 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52965 * @return Roo.Element
52967 getHeaderPanel : function(doShow){
52969 this.headerPanel.show();
52971 return this.headerPanel;
52975 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52976 * After modifying the contents of this panel a call to grid.autoSize() may be
52977 * required to register any changes in size.
52978 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52979 * @return Roo.Element
52981 getFooterPanel : function(doShow){
52983 this.footerPanel.show();
52985 return this.footerPanel;
52988 initElements : function(){
52989 var E = Roo.Element;
52990 var el = this.grid.getGridEl().dom.firstChild;
52991 var cs = el.childNodes;
52993 this.el = new E(el);
52995 this.focusEl = new E(el.firstChild);
52996 this.focusEl.swallowEvent("click", true);
52998 this.headerPanel = new E(cs[1]);
52999 this.headerPanel.enableDisplayMode("block");
53001 this.scroller = new E(cs[2]);
53002 this.scrollSizer = new E(this.scroller.dom.firstChild);
53004 this.lockedWrap = new E(cs[3]);
53005 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53006 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53008 this.mainWrap = new E(cs[4]);
53009 this.mainHd = new E(this.mainWrap.dom.firstChild);
53010 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53012 this.footerPanel = new E(cs[5]);
53013 this.footerPanel.enableDisplayMode("block");
53015 this.resizeProxy = new E(cs[6]);
53017 this.headerSelector = String.format(
53018 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53019 this.lockedHd.id, this.mainHd.id
53022 this.splitterSelector = String.format(
53023 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53024 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53027 idToCssName : function(s)
53029 return s.replace(/[^a-z0-9]+/ig, '-');
53032 getHeaderCell : function(index){
53033 return Roo.DomQuery.select(this.headerSelector)[index];
53036 getHeaderCellMeasure : function(index){
53037 return this.getHeaderCell(index).firstChild;
53040 getHeaderCellText : function(index){
53041 return this.getHeaderCell(index).firstChild.firstChild;
53044 getLockedTable : function(){
53045 return this.lockedBody.dom.firstChild;
53048 getBodyTable : function(){
53049 return this.mainBody.dom.firstChild;
53052 getLockedRow : function(index){
53053 return this.getLockedTable().rows[index];
53056 getRow : function(index){
53057 return this.getBodyTable().rows[index];
53060 getRowComposite : function(index){
53062 this.rowEl = new Roo.CompositeElementLite();
53064 var els = [], lrow, mrow;
53065 if(lrow = this.getLockedRow(index)){
53068 if(mrow = this.getRow(index)){
53071 this.rowEl.elements = els;
53075 * Gets the 'td' of the cell
53077 * @param {Integer} rowIndex row to select
53078 * @param {Integer} colIndex column to select
53082 getCell : function(rowIndex, colIndex){
53083 var locked = this.cm.getLockedCount();
53085 if(colIndex < locked){
53086 source = this.lockedBody.dom.firstChild;
53088 source = this.mainBody.dom.firstChild;
53089 colIndex -= locked;
53091 return source.rows[rowIndex].childNodes[colIndex];
53094 getCellText : function(rowIndex, colIndex){
53095 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53098 getCellBox : function(cell){
53099 var b = this.fly(cell).getBox();
53100 if(Roo.isOpera){ // opera fails to report the Y
53101 b.y = cell.offsetTop + this.mainBody.getY();
53106 getCellIndex : function(cell){
53107 var id = String(cell.className).match(this.cellRE);
53109 return parseInt(id[1], 10);
53114 findHeaderIndex : function(n){
53115 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53116 return r ? this.getCellIndex(r) : false;
53119 findHeaderCell : function(n){
53120 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53121 return r ? r : false;
53124 findRowIndex : function(n){
53128 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53129 return r ? r.rowIndex : false;
53132 findCellIndex : function(node){
53133 var stop = this.el.dom;
53134 while(node && node != stop){
53135 if(this.findRE.test(node.className)){
53136 return this.getCellIndex(node);
53138 node = node.parentNode;
53143 getColumnId : function(index){
53144 return this.cm.getColumnId(index);
53147 getSplitters : function()
53149 if(this.splitterSelector){
53150 return Roo.DomQuery.select(this.splitterSelector);
53156 getSplitter : function(index){
53157 return this.getSplitters()[index];
53160 onRowOver : function(e, t){
53162 if((row = this.findRowIndex(t)) !== false){
53163 this.getRowComposite(row).addClass("x-grid-row-over");
53167 onRowOut : function(e, t){
53169 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53170 this.getRowComposite(row).removeClass("x-grid-row-over");
53174 renderHeaders : function(){
53176 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53177 var cb = [], lb = [], sb = [], lsb = [], p = {};
53178 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53179 p.cellId = "x-grid-hd-0-" + i;
53180 p.splitId = "x-grid-csplit-0-" + i;
53181 p.id = cm.getColumnId(i);
53182 p.title = cm.getColumnTooltip(i) || "";
53183 p.value = cm.getColumnHeader(i) || "";
53184 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53185 if(!cm.isLocked(i)){
53186 cb[cb.length] = ct.apply(p);
53187 sb[sb.length] = st.apply(p);
53189 lb[lb.length] = ct.apply(p);
53190 lsb[lsb.length] = st.apply(p);
53193 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53194 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53197 updateHeaders : function(){
53198 var html = this.renderHeaders();
53199 this.lockedHd.update(html[0]);
53200 this.mainHd.update(html[1]);
53204 * Focuses the specified row.
53205 * @param {Number} row The row index
53207 focusRow : function(row)
53209 //Roo.log('GridView.focusRow');
53210 var x = this.scroller.dom.scrollLeft;
53211 this.focusCell(row, 0, false);
53212 this.scroller.dom.scrollLeft = x;
53216 * Focuses the specified cell.
53217 * @param {Number} row The row index
53218 * @param {Number} col The column index
53219 * @param {Boolean} hscroll false to disable horizontal scrolling
53221 focusCell : function(row, col, hscroll)
53223 //Roo.log('GridView.focusCell');
53224 var el = this.ensureVisible(row, col, hscroll);
53225 this.focusEl.alignTo(el, "tl-tl");
53227 this.focusEl.focus();
53229 this.focusEl.focus.defer(1, this.focusEl);
53234 * Scrolls the specified cell into view
53235 * @param {Number} row The row index
53236 * @param {Number} col The column index
53237 * @param {Boolean} hscroll false to disable horizontal scrolling
53239 ensureVisible : function(row, col, hscroll)
53241 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53242 //return null; //disable for testing.
53243 if(typeof row != "number"){
53244 row = row.rowIndex;
53246 if(row < 0 && row >= this.ds.getCount()){
53249 col = (col !== undefined ? col : 0);
53250 var cm = this.grid.colModel;
53251 while(cm.isHidden(col)){
53255 var el = this.getCell(row, col);
53259 var c = this.scroller.dom;
53261 var ctop = parseInt(el.offsetTop, 10);
53262 var cleft = parseInt(el.offsetLeft, 10);
53263 var cbot = ctop + el.offsetHeight;
53264 var cright = cleft + el.offsetWidth;
53266 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53267 var stop = parseInt(c.scrollTop, 10);
53268 var sleft = parseInt(c.scrollLeft, 10);
53269 var sbot = stop + ch;
53270 var sright = sleft + c.clientWidth;
53272 Roo.log('GridView.ensureVisible:' +
53274 ' c.clientHeight:' + c.clientHeight +
53275 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53283 c.scrollTop = ctop;
53284 //Roo.log("set scrolltop to ctop DISABLE?");
53285 }else if(cbot > sbot){
53286 //Roo.log("set scrolltop to cbot-ch");
53287 c.scrollTop = cbot-ch;
53290 if(hscroll !== false){
53292 c.scrollLeft = cleft;
53293 }else if(cright > sright){
53294 c.scrollLeft = cright-c.clientWidth;
53301 updateColumns : function(){
53302 this.grid.stopEditing();
53303 var cm = this.grid.colModel, colIds = this.getColumnIds();
53304 //var totalWidth = cm.getTotalWidth();
53306 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53307 //if(cm.isHidden(i)) continue;
53308 var w = cm.getColumnWidth(i);
53309 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53310 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53312 this.updateSplitters();
53315 generateRules : function(cm){
53316 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53317 Roo.util.CSS.removeStyleSheet(rulesId);
53318 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53319 var cid = cm.getColumnId(i);
53321 if(cm.config[i].align){
53322 align = 'text-align:'+cm.config[i].align+';';
53325 if(cm.isHidden(i)){
53326 hidden = 'display:none;';
53328 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53330 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53331 this.hdSelector, cid, " {\n", align, width, "}\n",
53332 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53333 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53335 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53338 updateSplitters : function(){
53339 var cm = this.cm, s = this.getSplitters();
53340 if(s){ // splitters not created yet
53341 var pos = 0, locked = true;
53342 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53343 if(cm.isHidden(i)) continue;
53344 var w = cm.getColumnWidth(i); // make sure it's a number
53345 if(!cm.isLocked(i) && locked){
53350 s[i].style.left = (pos-this.splitOffset) + "px";
53355 handleHiddenChange : function(colModel, colIndex, hidden){
53357 this.hideColumn(colIndex);
53359 this.unhideColumn(colIndex);
53363 hideColumn : function(colIndex){
53364 var cid = this.getColumnId(colIndex);
53365 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53366 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53368 this.updateHeaders();
53370 this.updateSplitters();
53374 unhideColumn : function(colIndex){
53375 var cid = this.getColumnId(colIndex);
53376 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53377 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53380 this.updateHeaders();
53382 this.updateSplitters();
53386 insertRows : function(dm, firstRow, lastRow, isUpdate){
53387 if(firstRow == 0 && lastRow == dm.getCount()-1){
53391 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53393 var s = this.getScrollState();
53394 var markup = this.renderRows(firstRow, lastRow);
53395 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53396 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53397 this.restoreScroll(s);
53399 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53400 this.syncRowHeights(firstRow, lastRow);
53401 this.stripeRows(firstRow);
53407 bufferRows : function(markup, target, index){
53408 var before = null, trows = target.rows, tbody = target.tBodies[0];
53409 if(index < trows.length){
53410 before = trows[index];
53412 var b = document.createElement("div");
53413 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53414 var rows = b.firstChild.rows;
53415 for(var i = 0, len = rows.length; i < len; i++){
53417 tbody.insertBefore(rows[0], before);
53419 tbody.appendChild(rows[0]);
53426 deleteRows : function(dm, firstRow, lastRow){
53427 if(dm.getRowCount()<1){
53428 this.fireEvent("beforerefresh", this);
53429 this.mainBody.update("");
53430 this.lockedBody.update("");
53431 this.fireEvent("refresh", this);
53433 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53434 var bt = this.getBodyTable();
53435 var tbody = bt.firstChild;
53436 var rows = bt.rows;
53437 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53438 tbody.removeChild(rows[firstRow]);
53440 this.stripeRows(firstRow);
53441 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53445 updateRows : function(dataSource, firstRow, lastRow){
53446 var s = this.getScrollState();
53448 this.restoreScroll(s);
53451 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53455 this.updateHeaderSortState();
53458 getScrollState : function(){
53460 var sb = this.scroller.dom;
53461 return {left: sb.scrollLeft, top: sb.scrollTop};
53464 stripeRows : function(startRow){
53465 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53468 startRow = startRow || 0;
53469 var rows = this.getBodyTable().rows;
53470 var lrows = this.getLockedTable().rows;
53471 var cls = ' x-grid-row-alt ';
53472 for(var i = startRow, len = rows.length; i < len; i++){
53473 var row = rows[i], lrow = lrows[i];
53474 var isAlt = ((i+1) % 2 == 0);
53475 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53476 if(isAlt == hasAlt){
53480 row.className += " x-grid-row-alt";
53482 row.className = row.className.replace("x-grid-row-alt", "");
53485 lrow.className = row.className;
53490 restoreScroll : function(state){
53491 //Roo.log('GridView.restoreScroll');
53492 var sb = this.scroller.dom;
53493 sb.scrollLeft = state.left;
53494 sb.scrollTop = state.top;
53498 syncScroll : function(){
53499 //Roo.log('GridView.syncScroll');
53500 var sb = this.scroller.dom;
53501 var sh = this.mainHd.dom;
53502 var bs = this.mainBody.dom;
53503 var lv = this.lockedBody.dom;
53504 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53505 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53508 handleScroll : function(e){
53510 var sb = this.scroller.dom;
53511 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53515 handleWheel : function(e){
53516 var d = e.getWheelDelta();
53517 this.scroller.dom.scrollTop -= d*22;
53518 // set this here to prevent jumpy scrolling on large tables
53519 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53523 renderRows : function(startRow, endRow){
53524 // pull in all the crap needed to render rows
53525 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53526 var colCount = cm.getColumnCount();
53528 if(ds.getCount() < 1){
53532 // build a map for all the columns
53534 for(var i = 0; i < colCount; i++){
53535 var name = cm.getDataIndex(i);
53537 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53538 renderer : cm.getRenderer(i),
53539 id : cm.getColumnId(i),
53540 locked : cm.isLocked(i)
53544 startRow = startRow || 0;
53545 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53547 // records to render
53548 var rs = ds.getRange(startRow, endRow);
53550 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53553 // As much as I hate to duplicate code, this was branched because FireFox really hates
53554 // [].join("") on strings. The performance difference was substantial enough to
53555 // branch this function
53556 doRender : Roo.isGecko ?
53557 function(cs, rs, ds, startRow, colCount, stripe){
53558 var ts = this.templates, ct = ts.cell, rt = ts.row;
53560 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53562 var hasListener = this.grid.hasListener('rowclass');
53564 for(var j = 0, len = rs.length; j < len; j++){
53565 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53566 for(var i = 0; i < colCount; i++){
53568 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53570 p.css = p.attr = "";
53571 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53572 if(p.value == undefined || p.value === "") p.value = " ";
53573 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53574 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53576 var markup = ct.apply(p);
53584 if(stripe && ((rowIndex+1) % 2 == 0)){
53585 alt.push("x-grid-row-alt")
53588 alt.push( " x-grid-dirty-row");
53591 if(this.getRowClass){
53592 alt.push(this.getRowClass(r, rowIndex));
53598 rowIndex : rowIndex,
53601 this.grid.fireEvent('rowclass', this, rowcfg);
53602 alt.push(rowcfg.rowClass);
53604 rp.alt = alt.join(" ");
53605 lbuf+= rt.apply(rp);
53607 buf+= rt.apply(rp);
53609 return [lbuf, buf];
53611 function(cs, rs, ds, startRow, colCount, stripe){
53612 var ts = this.templates, ct = ts.cell, rt = ts.row;
53614 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53615 var hasListener = this.grid.hasListener('rowclass');
53618 for(var j = 0, len = rs.length; j < len; j++){
53619 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53620 for(var i = 0; i < colCount; i++){
53622 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53624 p.css = p.attr = "";
53625 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53626 if(p.value == undefined || p.value === "") p.value = " ";
53627 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53628 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53631 var markup = ct.apply(p);
53633 cb[cb.length] = markup;
53635 lcb[lcb.length] = markup;
53639 if(stripe && ((rowIndex+1) % 2 == 0)){
53640 alt.push( "x-grid-row-alt");
53643 alt.push(" x-grid-dirty-row");
53646 if(this.getRowClass){
53647 alt.push( this.getRowClass(r, rowIndex));
53653 rowIndex : rowIndex,
53656 this.grid.fireEvent('rowclass', this, rowcfg);
53657 alt.push(rowcfg.rowClass);
53659 rp.alt = alt.join(" ");
53660 rp.cells = lcb.join("");
53661 lbuf[lbuf.length] = rt.apply(rp);
53662 rp.cells = cb.join("");
53663 buf[buf.length] = rt.apply(rp);
53665 return [lbuf.join(""), buf.join("")];
53668 renderBody : function(){
53669 var markup = this.renderRows();
53670 var bt = this.templates.body;
53671 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53675 * Refreshes the grid
53676 * @param {Boolean} headersToo
53678 refresh : function(headersToo){
53679 this.fireEvent("beforerefresh", this);
53680 this.grid.stopEditing();
53681 var result = this.renderBody();
53682 this.lockedBody.update(result[0]);
53683 this.mainBody.update(result[1]);
53684 if(headersToo === true){
53685 this.updateHeaders();
53686 this.updateColumns();
53687 this.updateSplitters();
53688 this.updateHeaderSortState();
53690 this.syncRowHeights();
53692 this.fireEvent("refresh", this);
53695 handleColumnMove : function(cm, oldIndex, newIndex){
53696 this.indexMap = null;
53697 var s = this.getScrollState();
53698 this.refresh(true);
53699 this.restoreScroll(s);
53700 this.afterMove(newIndex);
53703 afterMove : function(colIndex){
53704 if(this.enableMoveAnim && Roo.enableFx){
53705 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53707 // if multisort - fix sortOrder, and reload..
53708 if (this.grid.dataSource.multiSort) {
53709 // the we can call sort again..
53710 var dm = this.grid.dataSource;
53711 var cm = this.grid.colModel;
53713 for(var i = 0; i < cm.config.length; i++ ) {
53715 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53716 continue; // dont' bother, it's not in sort list or being set.
53719 so.push(cm.config[i].dataIndex);
53722 dm.load(dm.lastOptions);
53729 updateCell : function(dm, rowIndex, dataIndex){
53730 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53731 if(typeof colIndex == "undefined"){ // not present in grid
53734 var cm = this.grid.colModel;
53735 var cell = this.getCell(rowIndex, colIndex);
53736 var cellText = this.getCellText(rowIndex, colIndex);
53739 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53740 id : cm.getColumnId(colIndex),
53741 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53743 var renderer = cm.getRenderer(colIndex);
53744 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53745 if(typeof val == "undefined" || val === "") val = " ";
53746 cellText.innerHTML = val;
53747 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53748 this.syncRowHeights(rowIndex, rowIndex);
53751 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53753 if(this.grid.autoSizeHeaders){
53754 var h = this.getHeaderCellMeasure(colIndex);
53755 maxWidth = Math.max(maxWidth, h.scrollWidth);
53758 if(this.cm.isLocked(colIndex)){
53759 tb = this.getLockedTable();
53762 tb = this.getBodyTable();
53763 index = colIndex - this.cm.getLockedCount();
53766 var rows = tb.rows;
53767 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53768 for(var i = 0; i < stopIndex; i++){
53769 var cell = rows[i].childNodes[index].firstChild;
53770 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53773 return maxWidth + /*margin for error in IE*/ 5;
53776 * Autofit a column to its content.
53777 * @param {Number} colIndex
53778 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53780 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53781 if(this.cm.isHidden(colIndex)){
53782 return; // can't calc a hidden column
53785 var cid = this.cm.getColumnId(colIndex);
53786 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53787 if(this.grid.autoSizeHeaders){
53788 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53791 var newWidth = this.calcColumnWidth(colIndex);
53792 this.cm.setColumnWidth(colIndex,
53793 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53794 if(!suppressEvent){
53795 this.grid.fireEvent("columnresize", colIndex, newWidth);
53800 * Autofits all columns to their content and then expands to fit any extra space in the grid
53802 autoSizeColumns : function(){
53803 var cm = this.grid.colModel;
53804 var colCount = cm.getColumnCount();
53805 for(var i = 0; i < colCount; i++){
53806 this.autoSizeColumn(i, true, true);
53808 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53811 this.updateColumns();
53817 * Autofits all columns to the grid's width proportionate with their current size
53818 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53820 fitColumns : function(reserveScrollSpace){
53821 var cm = this.grid.colModel;
53822 var colCount = cm.getColumnCount();
53826 for (i = 0; i < colCount; i++){
53827 if(!cm.isHidden(i) && !cm.isFixed(i)){
53828 w = cm.getColumnWidth(i);
53834 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53835 if(reserveScrollSpace){
53838 var frac = (avail - cm.getTotalWidth())/width;
53839 while (cols.length){
53842 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53844 this.updateColumns();
53848 onRowSelect : function(rowIndex){
53849 var row = this.getRowComposite(rowIndex);
53850 row.addClass("x-grid-row-selected");
53853 onRowDeselect : function(rowIndex){
53854 var row = this.getRowComposite(rowIndex);
53855 row.removeClass("x-grid-row-selected");
53858 onCellSelect : function(row, col){
53859 var cell = this.getCell(row, col);
53861 Roo.fly(cell).addClass("x-grid-cell-selected");
53865 onCellDeselect : function(row, col){
53866 var cell = this.getCell(row, col);
53868 Roo.fly(cell).removeClass("x-grid-cell-selected");
53872 updateHeaderSortState : function(){
53874 // sort state can be single { field: xxx, direction : yyy}
53875 // or { xxx=>ASC , yyy : DESC ..... }
53878 if (!this.ds.multiSort) {
53879 var state = this.ds.getSortState();
53883 mstate[state.field] = state.direction;
53884 // FIXME... - this is not used here.. but might be elsewhere..
53885 this.sortState = state;
53888 mstate = this.ds.sortToggle;
53890 //remove existing sort classes..
53892 var sc = this.sortClasses;
53893 var hds = this.el.select(this.headerSelector).removeClass(sc);
53895 for(var f in mstate) {
53897 var sortColumn = this.cm.findColumnIndex(f);
53899 if(sortColumn != -1){
53900 var sortDir = mstate[f];
53901 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53910 handleHeaderClick : function(g, index,e){
53912 Roo.log("header click");
53915 // touch events on header are handled by context
53916 this.handleHdCtx(g,index,e);
53921 if(this.headersDisabled){
53924 var dm = g.dataSource, cm = g.colModel;
53925 if(!cm.isSortable(index)){
53930 if (dm.multiSort) {
53931 // update the sortOrder
53933 for(var i = 0; i < cm.config.length; i++ ) {
53935 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53936 continue; // dont' bother, it's not in sort list or being set.
53939 so.push(cm.config[i].dataIndex);
53945 dm.sort(cm.getDataIndex(index));
53949 destroy : function(){
53951 this.colMenu.removeAll();
53952 Roo.menu.MenuMgr.unregister(this.colMenu);
53953 this.colMenu.getEl().remove();
53954 delete this.colMenu;
53957 this.hmenu.removeAll();
53958 Roo.menu.MenuMgr.unregister(this.hmenu);
53959 this.hmenu.getEl().remove();
53962 if(this.grid.enableColumnMove){
53963 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53965 for(var dd in dds){
53966 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53967 var elid = dds[dd].dragElId;
53969 Roo.get(elid).remove();
53970 } else if(dds[dd].config.isTarget){
53971 dds[dd].proxyTop.remove();
53972 dds[dd].proxyBottom.remove();
53975 if(Roo.dd.DDM.locationCache[dd]){
53976 delete Roo.dd.DDM.locationCache[dd];
53979 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53982 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53983 this.bind(null, null);
53984 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53987 handleLockChange : function(){
53988 this.refresh(true);
53991 onDenyColumnLock : function(){
53995 onDenyColumnHide : function(){
53999 handleHdMenuClick : function(item){
54000 var index = this.hdCtxIndex;
54001 var cm = this.cm, ds = this.ds;
54004 ds.sort(cm.getDataIndex(index), "ASC");
54007 ds.sort(cm.getDataIndex(index), "DESC");
54010 var lc = cm.getLockedCount();
54011 if(cm.getColumnCount(true) <= lc+1){
54012 this.onDenyColumnLock();
54016 cm.setLocked(index, true, true);
54017 cm.moveColumn(index, lc);
54018 this.grid.fireEvent("columnmove", index, lc);
54020 cm.setLocked(index, true);
54024 var lc = cm.getLockedCount();
54025 if((lc-1) != index){
54026 cm.setLocked(index, false, true);
54027 cm.moveColumn(index, lc-1);
54028 this.grid.fireEvent("columnmove", index, lc-1);
54030 cm.setLocked(index, false);
54033 case 'wider': // used to expand cols on touch..
54035 var cw = cm.getColumnWidth(index);
54036 cw += (item.id == 'wider' ? 1 : -1) * 50;
54037 cw = Math.max(0, cw);
54038 cw = Math.min(cw,4000);
54039 cm.setColumnWidth(index, cw);
54043 index = cm.getIndexById(item.id.substr(4));
54045 if(item.checked && cm.getColumnCount(true) <= 1){
54046 this.onDenyColumnHide();
54049 cm.setHidden(index, item.checked);
54055 beforeColMenuShow : function(){
54056 var cm = this.cm, colCount = cm.getColumnCount();
54057 this.colMenu.removeAll();
54058 for(var i = 0; i < colCount; i++){
54059 this.colMenu.add(new Roo.menu.CheckItem({
54060 id: "col-"+cm.getColumnId(i),
54061 text: cm.getColumnHeader(i),
54062 checked: !cm.isHidden(i),
54068 handleHdCtx : function(g, index, e){
54070 var hd = this.getHeaderCell(index);
54071 this.hdCtxIndex = index;
54072 var ms = this.hmenu.items, cm = this.cm;
54073 ms.get("asc").setDisabled(!cm.isSortable(index));
54074 ms.get("desc").setDisabled(!cm.isSortable(index));
54075 if(this.grid.enableColLock !== false){
54076 ms.get("lock").setDisabled(cm.isLocked(index));
54077 ms.get("unlock").setDisabled(!cm.isLocked(index));
54079 this.hmenu.show(hd, "tl-bl");
54082 handleHdOver : function(e){
54083 var hd = this.findHeaderCell(e.getTarget());
54084 if(hd && !this.headersDisabled){
54085 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54086 this.fly(hd).addClass("x-grid-hd-over");
54091 handleHdOut : function(e){
54092 var hd = this.findHeaderCell(e.getTarget());
54094 this.fly(hd).removeClass("x-grid-hd-over");
54098 handleSplitDblClick : function(e, t){
54099 var i = this.getCellIndex(t);
54100 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54101 this.autoSizeColumn(i, true);
54106 render : function(){
54109 var colCount = cm.getColumnCount();
54111 if(this.grid.monitorWindowResize === true){
54112 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54114 var header = this.renderHeaders();
54115 var body = this.templates.body.apply({rows:""});
54116 var html = this.templates.master.apply({
54119 lockedHeader: header[0],
54123 //this.updateColumns();
54125 this.grid.getGridEl().dom.innerHTML = html;
54127 this.initElements();
54129 // a kludge to fix the random scolling effect in webkit
54130 this.el.on("scroll", function() {
54131 this.el.dom.scrollTop=0; // hopefully not recursive..
54134 this.scroller.on("scroll", this.handleScroll, this);
54135 this.lockedBody.on("mousewheel", this.handleWheel, this);
54136 this.mainBody.on("mousewheel", this.handleWheel, this);
54138 this.mainHd.on("mouseover", this.handleHdOver, this);
54139 this.mainHd.on("mouseout", this.handleHdOut, this);
54140 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54141 {delegate: "."+this.splitClass});
54143 this.lockedHd.on("mouseover", this.handleHdOver, this);
54144 this.lockedHd.on("mouseout", this.handleHdOut, this);
54145 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54146 {delegate: "."+this.splitClass});
54148 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54149 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54152 this.updateSplitters();
54154 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54155 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54156 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54159 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54160 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54162 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54163 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54165 if(this.grid.enableColLock !== false){
54166 this.hmenu.add('-',
54167 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54168 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54172 this.hmenu.add('-',
54173 {id:"wider", text: this.columnsWiderText},
54174 {id:"narrow", text: this.columnsNarrowText }
54180 if(this.grid.enableColumnHide !== false){
54182 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54183 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54184 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54186 this.hmenu.add('-',
54187 {id:"columns", text: this.columnsText, menu: this.colMenu}
54190 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54192 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54195 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54196 this.dd = new Roo.grid.GridDragZone(this.grid, {
54197 ddGroup : this.grid.ddGroup || 'GridDD'
54203 for(var i = 0; i < colCount; i++){
54204 if(cm.isHidden(i)){
54205 this.hideColumn(i);
54207 if(cm.config[i].align){
54208 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54209 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54213 this.updateHeaderSortState();
54215 this.beforeInitialResize();
54218 // two part rendering gives faster view to the user
54219 this.renderPhase2.defer(1, this);
54222 renderPhase2 : function(){
54223 // render the rows now
54225 if(this.grid.autoSizeColumns){
54226 this.autoSizeColumns();
54230 beforeInitialResize : function(){
54234 onColumnSplitterMoved : function(i, w){
54235 this.userResized = true;
54236 var cm = this.grid.colModel;
54237 cm.setColumnWidth(i, w, true);
54238 var cid = cm.getColumnId(i);
54239 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54240 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54241 this.updateSplitters();
54243 this.grid.fireEvent("columnresize", i, w);
54246 syncRowHeights : function(startIndex, endIndex){
54247 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54248 startIndex = startIndex || 0;
54249 var mrows = this.getBodyTable().rows;
54250 var lrows = this.getLockedTable().rows;
54251 var len = mrows.length-1;
54252 endIndex = Math.min(endIndex || len, len);
54253 for(var i = startIndex; i <= endIndex; i++){
54254 var m = mrows[i], l = lrows[i];
54255 var h = Math.max(m.offsetHeight, l.offsetHeight);
54256 m.style.height = l.style.height = h + "px";
54261 layout : function(initialRender, is2ndPass){
54263 var auto = g.autoHeight;
54264 var scrollOffset = 16;
54265 var c = g.getGridEl(), cm = this.cm,
54266 expandCol = g.autoExpandColumn,
54268 //c.beginMeasure();
54270 if(!c.dom.offsetWidth){ // display:none?
54272 this.lockedWrap.show();
54273 this.mainWrap.show();
54278 var hasLock = this.cm.isLocked(0);
54280 var tbh = this.headerPanel.getHeight();
54281 var bbh = this.footerPanel.getHeight();
54284 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54285 var newHeight = ch + c.getBorderWidth("tb");
54287 newHeight = Math.min(g.maxHeight, newHeight);
54289 c.setHeight(newHeight);
54293 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54296 var s = this.scroller;
54298 var csize = c.getSize(true);
54300 this.el.setSize(csize.width, csize.height);
54302 this.headerPanel.setWidth(csize.width);
54303 this.footerPanel.setWidth(csize.width);
54305 var hdHeight = this.mainHd.getHeight();
54306 var vw = csize.width;
54307 var vh = csize.height - (tbh + bbh);
54311 var bt = this.getBodyTable();
54312 var ltWidth = hasLock ?
54313 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54315 var scrollHeight = bt.offsetHeight;
54316 var scrollWidth = ltWidth + bt.offsetWidth;
54317 var vscroll = false, hscroll = false;
54319 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54321 var lw = this.lockedWrap, mw = this.mainWrap;
54322 var lb = this.lockedBody, mb = this.mainBody;
54324 setTimeout(function(){
54325 var t = s.dom.offsetTop;
54326 var w = s.dom.clientWidth,
54327 h = s.dom.clientHeight;
54330 lw.setSize(ltWidth, h);
54332 mw.setLeftTop(ltWidth, t);
54333 mw.setSize(w-ltWidth, h);
54335 lb.setHeight(h-hdHeight);
54336 mb.setHeight(h-hdHeight);
54338 if(is2ndPass !== true && !gv.userResized && expandCol){
54339 // high speed resize without full column calculation
54341 var ci = cm.getIndexById(expandCol);
54343 ci = cm.findColumnIndex(expandCol);
54345 ci = Math.max(0, ci); // make sure it's got at least the first col.
54346 var expandId = cm.getColumnId(ci);
54347 var tw = cm.getTotalWidth(false);
54348 var currentWidth = cm.getColumnWidth(ci);
54349 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54350 if(currentWidth != cw){
54351 cm.setColumnWidth(ci, cw, true);
54352 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54353 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54354 gv.updateSplitters();
54355 gv.layout(false, true);
54367 onWindowResize : function(){
54368 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54374 appendFooter : function(parentEl){
54378 sortAscText : "Sort Ascending",
54379 sortDescText : "Sort Descending",
54380 lockText : "Lock Column",
54381 unlockText : "Unlock Column",
54382 columnsText : "Columns",
54384 columnsWiderText : "Wider",
54385 columnsNarrowText : "Thinner"
54389 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54390 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54391 this.proxy.el.addClass('x-grid3-col-dd');
54394 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54395 handleMouseDown : function(e){
54399 callHandleMouseDown : function(e){
54400 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54405 * Ext JS Library 1.1.1
54406 * Copyright(c) 2006-2007, Ext JS, LLC.
54408 * Originally Released Under LGPL - original licence link has changed is not relivant.
54411 * <script type="text/javascript">
54415 // This is a support class used internally by the Grid components
54416 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54418 this.view = grid.getView();
54419 this.proxy = this.view.resizeProxy;
54420 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54421 "gridSplitters" + this.grid.getGridEl().id, {
54422 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54424 this.setHandleElId(Roo.id(hd));
54425 this.setOuterHandleElId(Roo.id(hd2));
54426 this.scroll = false;
54428 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54429 fly: Roo.Element.fly,
54431 b4StartDrag : function(x, y){
54432 this.view.headersDisabled = true;
54433 this.proxy.setHeight(this.view.mainWrap.getHeight());
54434 var w = this.cm.getColumnWidth(this.cellIndex);
54435 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54436 this.resetConstraints();
54437 this.setXConstraint(minw, 1000);
54438 this.setYConstraint(0, 0);
54439 this.minX = x - minw;
54440 this.maxX = x + 1000;
54442 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54446 handleMouseDown : function(e){
54447 ev = Roo.EventObject.setEvent(e);
54448 var t = this.fly(ev.getTarget());
54449 if(t.hasClass("x-grid-split")){
54450 this.cellIndex = this.view.getCellIndex(t.dom);
54451 this.split = t.dom;
54452 this.cm = this.grid.colModel;
54453 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54454 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54459 endDrag : function(e){
54460 this.view.headersDisabled = false;
54461 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54462 var diff = endX - this.startPos;
54463 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54466 autoOffset : function(){
54467 this.setDelta(0,0);
54471 * Ext JS Library 1.1.1
54472 * Copyright(c) 2006-2007, Ext JS, LLC.
54474 * Originally Released Under LGPL - original licence link has changed is not relivant.
54477 * <script type="text/javascript">
54481 // This is a support class used internally by the Grid components
54482 Roo.grid.GridDragZone = function(grid, config){
54483 this.view = grid.getView();
54484 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54485 if(this.view.lockedBody){
54486 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54487 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54489 this.scroll = false;
54491 this.ddel = document.createElement('div');
54492 this.ddel.className = 'x-grid-dd-wrap';
54495 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54496 ddGroup : "GridDD",
54498 getDragData : function(e){
54499 var t = Roo.lib.Event.getTarget(e);
54500 var rowIndex = this.view.findRowIndex(t);
54501 var sm = this.grid.selModel;
54503 //Roo.log(rowIndex);
54505 if (sm.getSelectedCell) {
54506 // cell selection..
54507 if (!sm.getSelectedCell()) {
54510 if (rowIndex != sm.getSelectedCell()[0]) {
54516 if(rowIndex !== false){
54521 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54523 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54526 if (e.hasModifier()){
54527 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54530 Roo.log("getDragData");
54535 rowIndex: rowIndex,
54536 selections:sm.getSelections ? sm.getSelections() : (
54537 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54544 onInitDrag : function(e){
54545 var data = this.dragData;
54546 this.ddel.innerHTML = this.grid.getDragDropText();
54547 this.proxy.update(this.ddel);
54548 // fire start drag?
54551 afterRepair : function(){
54552 this.dragging = false;
54555 getRepairXY : function(e, data){
54559 onEndDrag : function(data, e){
54563 onValidDrop : function(dd, e, id){
54568 beforeInvalidDrop : function(e, id){
54573 * Ext JS Library 1.1.1
54574 * Copyright(c) 2006-2007, Ext JS, LLC.
54576 * Originally Released Under LGPL - original licence link has changed is not relivant.
54579 * <script type="text/javascript">
54584 * @class Roo.grid.ColumnModel
54585 * @extends Roo.util.Observable
54586 * This is the default implementation of a ColumnModel used by the Grid. It defines
54587 * the columns in the grid.
54590 var colModel = new Roo.grid.ColumnModel([
54591 {header: "Ticker", width: 60, sortable: true, locked: true},
54592 {header: "Company Name", width: 150, sortable: true},
54593 {header: "Market Cap.", width: 100, sortable: true},
54594 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54595 {header: "Employees", width: 100, sortable: true, resizable: false}
54600 * The config options listed for this class are options which may appear in each
54601 * individual column definition.
54602 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54604 * @param {Object} config An Array of column config objects. See this class's
54605 * config objects for details.
54607 Roo.grid.ColumnModel = function(config){
54609 * The config passed into the constructor
54611 this.config = config;
54614 // if no id, create one
54615 // if the column does not have a dataIndex mapping,
54616 // map it to the order it is in the config
54617 for(var i = 0, len = config.length; i < len; i++){
54619 if(typeof c.dataIndex == "undefined"){
54622 if(typeof c.renderer == "string"){
54623 c.renderer = Roo.util.Format[c.renderer];
54625 if(typeof c.id == "undefined"){
54628 if(c.editor && c.editor.xtype){
54629 c.editor = Roo.factory(c.editor, Roo.grid);
54631 if(c.editor && c.editor.isFormField){
54632 c.editor = new Roo.grid.GridEditor(c.editor);
54634 this.lookup[c.id] = c;
54638 * The width of columns which have no width specified (defaults to 100)
54641 this.defaultWidth = 100;
54644 * Default sortable of columns which have no sortable specified (defaults to false)
54647 this.defaultSortable = false;
54651 * @event widthchange
54652 * Fires when the width of a column changes.
54653 * @param {ColumnModel} this
54654 * @param {Number} columnIndex The column index
54655 * @param {Number} newWidth The new width
54657 "widthchange": true,
54659 * @event headerchange
54660 * Fires when the text of a header changes.
54661 * @param {ColumnModel} this
54662 * @param {Number} columnIndex The column index
54663 * @param {Number} newText The new header text
54665 "headerchange": true,
54667 * @event hiddenchange
54668 * Fires when a column is hidden or "unhidden".
54669 * @param {ColumnModel} this
54670 * @param {Number} columnIndex The column index
54671 * @param {Boolean} hidden true if hidden, false otherwise
54673 "hiddenchange": true,
54675 * @event columnmoved
54676 * Fires when a column is moved.
54677 * @param {ColumnModel} this
54678 * @param {Number} oldIndex
54679 * @param {Number} newIndex
54681 "columnmoved" : true,
54683 * @event columlockchange
54684 * Fires when a column's locked state is changed
54685 * @param {ColumnModel} this
54686 * @param {Number} colIndex
54687 * @param {Boolean} locked true if locked
54689 "columnlockchange" : true
54691 Roo.grid.ColumnModel.superclass.constructor.call(this);
54693 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54695 * @cfg {String} header The header text to display in the Grid view.
54698 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54699 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54700 * specified, the column's index is used as an index into the Record's data Array.
54703 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54704 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54707 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54708 * Defaults to the value of the {@link #defaultSortable} property.
54709 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54712 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54715 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54718 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54721 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54724 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54725 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54726 * default renderer uses the raw data value.
54729 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54732 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54736 * Returns the id of the column at the specified index.
54737 * @param {Number} index The column index
54738 * @return {String} the id
54740 getColumnId : function(index){
54741 return this.config[index].id;
54745 * Returns the column for a specified id.
54746 * @param {String} id The column id
54747 * @return {Object} the column
54749 getColumnById : function(id){
54750 return this.lookup[id];
54755 * Returns the column for a specified dataIndex.
54756 * @param {String} dataIndex The column dataIndex
54757 * @return {Object|Boolean} the column or false if not found
54759 getColumnByDataIndex: function(dataIndex){
54760 var index = this.findColumnIndex(dataIndex);
54761 return index > -1 ? this.config[index] : false;
54765 * Returns the index for a specified column id.
54766 * @param {String} id The column id
54767 * @return {Number} the index, or -1 if not found
54769 getIndexById : function(id){
54770 for(var i = 0, len = this.config.length; i < len; i++){
54771 if(this.config[i].id == id){
54779 * Returns the index for a specified column dataIndex.
54780 * @param {String} dataIndex The column dataIndex
54781 * @return {Number} the index, or -1 if not found
54784 findColumnIndex : function(dataIndex){
54785 for(var i = 0, len = this.config.length; i < len; i++){
54786 if(this.config[i].dataIndex == dataIndex){
54794 moveColumn : function(oldIndex, newIndex){
54795 var c = this.config[oldIndex];
54796 this.config.splice(oldIndex, 1);
54797 this.config.splice(newIndex, 0, c);
54798 this.dataMap = null;
54799 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54802 isLocked : function(colIndex){
54803 return this.config[colIndex].locked === true;
54806 setLocked : function(colIndex, value, suppressEvent){
54807 if(this.isLocked(colIndex) == value){
54810 this.config[colIndex].locked = value;
54811 if(!suppressEvent){
54812 this.fireEvent("columnlockchange", this, colIndex, value);
54816 getTotalLockedWidth : function(){
54817 var totalWidth = 0;
54818 for(var i = 0; i < this.config.length; i++){
54819 if(this.isLocked(i) && !this.isHidden(i)){
54820 this.totalWidth += this.getColumnWidth(i);
54826 getLockedCount : function(){
54827 for(var i = 0, len = this.config.length; i < len; i++){
54828 if(!this.isLocked(i)){
54835 * Returns the number of columns.
54838 getColumnCount : function(visibleOnly){
54839 if(visibleOnly === true){
54841 for(var i = 0, len = this.config.length; i < len; i++){
54842 if(!this.isHidden(i)){
54848 return this.config.length;
54852 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54853 * @param {Function} fn
54854 * @param {Object} scope (optional)
54855 * @return {Array} result
54857 getColumnsBy : function(fn, scope){
54859 for(var i = 0, len = this.config.length; i < len; i++){
54860 var c = this.config[i];
54861 if(fn.call(scope||this, c, i) === true){
54869 * Returns true if the specified column is sortable.
54870 * @param {Number} col The column index
54871 * @return {Boolean}
54873 isSortable : function(col){
54874 if(typeof this.config[col].sortable == "undefined"){
54875 return this.defaultSortable;
54877 return this.config[col].sortable;
54881 * Returns the rendering (formatting) function defined for the column.
54882 * @param {Number} col The column index.
54883 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54885 getRenderer : function(col){
54886 if(!this.config[col].renderer){
54887 return Roo.grid.ColumnModel.defaultRenderer;
54889 return this.config[col].renderer;
54893 * Sets the rendering (formatting) function for a column.
54894 * @param {Number} col The column index
54895 * @param {Function} fn The function to use to process the cell's raw data
54896 * to return HTML markup for the grid view. The render function is called with
54897 * the following parameters:<ul>
54898 * <li>Data value.</li>
54899 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54900 * <li>css A CSS style string to apply to the table cell.</li>
54901 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54902 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54903 * <li>Row index</li>
54904 * <li>Column index</li>
54905 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54907 setRenderer : function(col, fn){
54908 this.config[col].renderer = fn;
54912 * Returns the width for the specified column.
54913 * @param {Number} col The column index
54916 getColumnWidth : function(col){
54917 return this.config[col].width * 1 || this.defaultWidth;
54921 * Sets the width for a column.
54922 * @param {Number} col The column index
54923 * @param {Number} width The new width
54925 setColumnWidth : function(col, width, suppressEvent){
54926 this.config[col].width = width;
54927 this.totalWidth = null;
54928 if(!suppressEvent){
54929 this.fireEvent("widthchange", this, col, width);
54934 * Returns the total width of all columns.
54935 * @param {Boolean} includeHidden True to include hidden column widths
54938 getTotalWidth : function(includeHidden){
54939 if(!this.totalWidth){
54940 this.totalWidth = 0;
54941 for(var i = 0, len = this.config.length; i < len; i++){
54942 if(includeHidden || !this.isHidden(i)){
54943 this.totalWidth += this.getColumnWidth(i);
54947 return this.totalWidth;
54951 * Returns the header for the specified column.
54952 * @param {Number} col The column index
54955 getColumnHeader : function(col){
54956 return this.config[col].header;
54960 * Sets the header for a column.
54961 * @param {Number} col The column index
54962 * @param {String} header The new header
54964 setColumnHeader : function(col, header){
54965 this.config[col].header = header;
54966 this.fireEvent("headerchange", this, col, header);
54970 * Returns the tooltip for the specified column.
54971 * @param {Number} col The column index
54974 getColumnTooltip : function(col){
54975 return this.config[col].tooltip;
54978 * Sets the tooltip for a column.
54979 * @param {Number} col The column index
54980 * @param {String} tooltip The new tooltip
54982 setColumnTooltip : function(col, tooltip){
54983 this.config[col].tooltip = tooltip;
54987 * Returns the dataIndex for the specified column.
54988 * @param {Number} col The column index
54991 getDataIndex : function(col){
54992 return this.config[col].dataIndex;
54996 * Sets the dataIndex for a column.
54997 * @param {Number} col The column index
54998 * @param {Number} dataIndex The new dataIndex
55000 setDataIndex : function(col, dataIndex){
55001 this.config[col].dataIndex = dataIndex;
55007 * Returns true if the cell is editable.
55008 * @param {Number} colIndex The column index
55009 * @param {Number} rowIndex The row index
55010 * @return {Boolean}
55012 isCellEditable : function(colIndex, rowIndex){
55013 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55017 * Returns the editor defined for the cell/column.
55018 * return false or null to disable editing.
55019 * @param {Number} colIndex The column index
55020 * @param {Number} rowIndex The row index
55023 getCellEditor : function(colIndex, rowIndex){
55024 return this.config[colIndex].editor;
55028 * Sets if a column is editable.
55029 * @param {Number} col The column index
55030 * @param {Boolean} editable True if the column is editable
55032 setEditable : function(col, editable){
55033 this.config[col].editable = editable;
55038 * Returns true if the column is hidden.
55039 * @param {Number} colIndex The column index
55040 * @return {Boolean}
55042 isHidden : function(colIndex){
55043 return this.config[colIndex].hidden;
55048 * Returns true if the column width cannot be changed
55050 isFixed : function(colIndex){
55051 return this.config[colIndex].fixed;
55055 * Returns true if the column can be resized
55056 * @return {Boolean}
55058 isResizable : function(colIndex){
55059 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55062 * Sets if a column is hidden.
55063 * @param {Number} colIndex The column index
55064 * @param {Boolean} hidden True if the column is hidden
55066 setHidden : function(colIndex, hidden){
55067 this.config[colIndex].hidden = hidden;
55068 this.totalWidth = null;
55069 this.fireEvent("hiddenchange", this, colIndex, hidden);
55073 * Sets the editor for a column.
55074 * @param {Number} col The column index
55075 * @param {Object} editor The editor object
55077 setEditor : function(col, editor){
55078 this.config[col].editor = editor;
55082 Roo.grid.ColumnModel.defaultRenderer = function(value){
55083 if(typeof value == "string" && value.length < 1){
55089 // Alias for backwards compatibility
55090 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55093 * Ext JS Library 1.1.1
55094 * Copyright(c) 2006-2007, Ext JS, LLC.
55096 * Originally Released Under LGPL - original licence link has changed is not relivant.
55099 * <script type="text/javascript">
55103 * @class Roo.grid.AbstractSelectionModel
55104 * @extends Roo.util.Observable
55105 * Abstract base class for grid SelectionModels. It provides the interface that should be
55106 * implemented by descendant classes. This class should not be directly instantiated.
55109 Roo.grid.AbstractSelectionModel = function(){
55110 this.locked = false;
55111 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55114 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55115 /** @ignore Called by the grid automatically. Do not call directly. */
55116 init : function(grid){
55122 * Locks the selections.
55125 this.locked = true;
55129 * Unlocks the selections.
55131 unlock : function(){
55132 this.locked = false;
55136 * Returns true if the selections are locked.
55137 * @return {Boolean}
55139 isLocked : function(){
55140 return this.locked;
55144 * Ext JS Library 1.1.1
55145 * Copyright(c) 2006-2007, Ext JS, LLC.
55147 * Originally Released Under LGPL - original licence link has changed is not relivant.
55150 * <script type="text/javascript">
55153 * @extends Roo.grid.AbstractSelectionModel
55154 * @class Roo.grid.RowSelectionModel
55155 * The default SelectionModel used by {@link Roo.grid.Grid}.
55156 * It supports multiple selections and keyboard selection/navigation.
55158 * @param {Object} config
55160 Roo.grid.RowSelectionModel = function(config){
55161 Roo.apply(this, config);
55162 this.selections = new Roo.util.MixedCollection(false, function(o){
55167 this.lastActive = false;
55171 * @event selectionchange
55172 * Fires when the selection changes
55173 * @param {SelectionModel} this
55175 "selectionchange" : true,
55177 * @event afterselectionchange
55178 * Fires after the selection changes (eg. by key press or clicking)
55179 * @param {SelectionModel} this
55181 "afterselectionchange" : true,
55183 * @event beforerowselect
55184 * Fires when a row is selected being selected, return false to cancel.
55185 * @param {SelectionModel} this
55186 * @param {Number} rowIndex The selected index
55187 * @param {Boolean} keepExisting False if other selections will be cleared
55189 "beforerowselect" : true,
55192 * Fires when a row is selected.
55193 * @param {SelectionModel} this
55194 * @param {Number} rowIndex The selected index
55195 * @param {Roo.data.Record} r The record
55197 "rowselect" : true,
55199 * @event rowdeselect
55200 * Fires when a row is deselected.
55201 * @param {SelectionModel} this
55202 * @param {Number} rowIndex The selected index
55204 "rowdeselect" : true
55206 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55207 this.locked = false;
55210 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55212 * @cfg {Boolean} singleSelect
55213 * True to allow selection of only one row at a time (defaults to false)
55215 singleSelect : false,
55218 initEvents : function(){
55220 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55221 this.grid.on("mousedown", this.handleMouseDown, this);
55222 }else{ // allow click to work like normal
55223 this.grid.on("rowclick", this.handleDragableRowClick, this);
55226 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55227 "up" : function(e){
55229 this.selectPrevious(e.shiftKey);
55230 }else if(this.last !== false && this.lastActive !== false){
55231 var last = this.last;
55232 this.selectRange(this.last, this.lastActive-1);
55233 this.grid.getView().focusRow(this.lastActive);
55234 if(last !== false){
55238 this.selectFirstRow();
55240 this.fireEvent("afterselectionchange", this);
55242 "down" : function(e){
55244 this.selectNext(e.shiftKey);
55245 }else if(this.last !== false && this.lastActive !== false){
55246 var last = this.last;
55247 this.selectRange(this.last, this.lastActive+1);
55248 this.grid.getView().focusRow(this.lastActive);
55249 if(last !== false){
55253 this.selectFirstRow();
55255 this.fireEvent("afterselectionchange", this);
55260 var view = this.grid.view;
55261 view.on("refresh", this.onRefresh, this);
55262 view.on("rowupdated", this.onRowUpdated, this);
55263 view.on("rowremoved", this.onRemove, this);
55267 onRefresh : function(){
55268 var ds = this.grid.dataSource, i, v = this.grid.view;
55269 var s = this.selections;
55270 s.each(function(r){
55271 if((i = ds.indexOfId(r.id)) != -1){
55280 onRemove : function(v, index, r){
55281 this.selections.remove(r);
55285 onRowUpdated : function(v, index, r){
55286 if(this.isSelected(r)){
55287 v.onRowSelect(index);
55293 * @param {Array} records The records to select
55294 * @param {Boolean} keepExisting (optional) True to keep existing selections
55296 selectRecords : function(records, keepExisting){
55298 this.clearSelections();
55300 var ds = this.grid.dataSource;
55301 for(var i = 0, len = records.length; i < len; i++){
55302 this.selectRow(ds.indexOf(records[i]), true);
55307 * Gets the number of selected rows.
55310 getCount : function(){
55311 return this.selections.length;
55315 * Selects the first row in the grid.
55317 selectFirstRow : function(){
55322 * Select the last row.
55323 * @param {Boolean} keepExisting (optional) True to keep existing selections
55325 selectLastRow : function(keepExisting){
55326 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55330 * Selects the row immediately following the last selected row.
55331 * @param {Boolean} keepExisting (optional) True to keep existing selections
55333 selectNext : function(keepExisting){
55334 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55335 this.selectRow(this.last+1, keepExisting);
55336 this.grid.getView().focusRow(this.last);
55341 * Selects the row that precedes the last selected row.
55342 * @param {Boolean} keepExisting (optional) True to keep existing selections
55344 selectPrevious : function(keepExisting){
55346 this.selectRow(this.last-1, keepExisting);
55347 this.grid.getView().focusRow(this.last);
55352 * Returns the selected records
55353 * @return {Array} Array of selected records
55355 getSelections : function(){
55356 return [].concat(this.selections.items);
55360 * Returns the first selected record.
55363 getSelected : function(){
55364 return this.selections.itemAt(0);
55369 * Clears all selections.
55371 clearSelections : function(fast){
55372 if(this.locked) return;
55374 var ds = this.grid.dataSource;
55375 var s = this.selections;
55376 s.each(function(r){
55377 this.deselectRow(ds.indexOfId(r.id));
55381 this.selections.clear();
55388 * Selects all rows.
55390 selectAll : function(){
55391 if(this.locked) return;
55392 this.selections.clear();
55393 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55394 this.selectRow(i, true);
55399 * Returns True if there is a selection.
55400 * @return {Boolean}
55402 hasSelection : function(){
55403 return this.selections.length > 0;
55407 * Returns True if the specified row is selected.
55408 * @param {Number/Record} record The record or index of the record to check
55409 * @return {Boolean}
55411 isSelected : function(index){
55412 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55413 return (r && this.selections.key(r.id) ? true : false);
55417 * Returns True if the specified record id is selected.
55418 * @param {String} id The id of record to check
55419 * @return {Boolean}
55421 isIdSelected : function(id){
55422 return (this.selections.key(id) ? true : false);
55426 handleMouseDown : function(e, t){
55427 var view = this.grid.getView(), rowIndex;
55428 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55431 if(e.shiftKey && this.last !== false){
55432 var last = this.last;
55433 this.selectRange(last, rowIndex, e.ctrlKey);
55434 this.last = last; // reset the last
55435 view.focusRow(rowIndex);
55437 var isSelected = this.isSelected(rowIndex);
55438 if(e.button !== 0 && isSelected){
55439 view.focusRow(rowIndex);
55440 }else if(e.ctrlKey && isSelected){
55441 this.deselectRow(rowIndex);
55442 }else if(!isSelected){
55443 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55444 view.focusRow(rowIndex);
55447 this.fireEvent("afterselectionchange", this);
55450 handleDragableRowClick : function(grid, rowIndex, e)
55452 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55453 this.selectRow(rowIndex, false);
55454 grid.view.focusRow(rowIndex);
55455 this.fireEvent("afterselectionchange", this);
55460 * Selects multiple rows.
55461 * @param {Array} rows Array of the indexes of the row to select
55462 * @param {Boolean} keepExisting (optional) True to keep existing selections
55464 selectRows : function(rows, keepExisting){
55466 this.clearSelections();
55468 for(var i = 0, len = rows.length; i < len; i++){
55469 this.selectRow(rows[i], true);
55474 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55475 * @param {Number} startRow The index of the first row in the range
55476 * @param {Number} endRow The index of the last row in the range
55477 * @param {Boolean} keepExisting (optional) True to retain existing selections
55479 selectRange : function(startRow, endRow, keepExisting){
55480 if(this.locked) return;
55482 this.clearSelections();
55484 if(startRow <= endRow){
55485 for(var i = startRow; i <= endRow; i++){
55486 this.selectRow(i, true);
55489 for(var i = startRow; i >= endRow; i--){
55490 this.selectRow(i, true);
55496 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55497 * @param {Number} startRow The index of the first row in the range
55498 * @param {Number} endRow The index of the last row in the range
55500 deselectRange : function(startRow, endRow, preventViewNotify){
55501 if(this.locked) return;
55502 for(var i = startRow; i <= endRow; i++){
55503 this.deselectRow(i, preventViewNotify);
55509 * @param {Number} row The index of the row to select
55510 * @param {Boolean} keepExisting (optional) True to keep existing selections
55512 selectRow : function(index, keepExisting, preventViewNotify){
55513 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55514 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55515 if(!keepExisting || this.singleSelect){
55516 this.clearSelections();
55518 var r = this.grid.dataSource.getAt(index);
55519 this.selections.add(r);
55520 this.last = this.lastActive = index;
55521 if(!preventViewNotify){
55522 this.grid.getView().onRowSelect(index);
55524 this.fireEvent("rowselect", this, index, r);
55525 this.fireEvent("selectionchange", this);
55531 * @param {Number} row The index of the row to deselect
55533 deselectRow : function(index, preventViewNotify){
55534 if(this.locked) return;
55535 if(this.last == index){
55538 if(this.lastActive == index){
55539 this.lastActive = false;
55541 var r = this.grid.dataSource.getAt(index);
55542 this.selections.remove(r);
55543 if(!preventViewNotify){
55544 this.grid.getView().onRowDeselect(index);
55546 this.fireEvent("rowdeselect", this, index);
55547 this.fireEvent("selectionchange", this);
55551 restoreLast : function(){
55553 this.last = this._last;
55558 acceptsNav : function(row, col, cm){
55559 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55563 onEditorKey : function(field, e){
55564 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55569 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55571 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55573 }else if(k == e.ENTER && !e.ctrlKey){
55577 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55579 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55581 }else if(k == e.ESC){
55585 g.startEditing(newCell[0], newCell[1]);
55590 * Ext JS Library 1.1.1
55591 * Copyright(c) 2006-2007, Ext JS, LLC.
55593 * Originally Released Under LGPL - original licence link has changed is not relivant.
55596 * <script type="text/javascript">
55599 * @class Roo.grid.CellSelectionModel
55600 * @extends Roo.grid.AbstractSelectionModel
55601 * This class provides the basic implementation for cell selection in a grid.
55603 * @param {Object} config The object containing the configuration of this model.
55604 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55606 Roo.grid.CellSelectionModel = function(config){
55607 Roo.apply(this, config);
55609 this.selection = null;
55613 * @event beforerowselect
55614 * Fires before a cell is selected.
55615 * @param {SelectionModel} this
55616 * @param {Number} rowIndex The selected row index
55617 * @param {Number} colIndex The selected cell index
55619 "beforecellselect" : true,
55621 * @event cellselect
55622 * Fires when a cell is selected.
55623 * @param {SelectionModel} this
55624 * @param {Number} rowIndex The selected row index
55625 * @param {Number} colIndex The selected cell index
55627 "cellselect" : true,
55629 * @event selectionchange
55630 * Fires when the active selection changes.
55631 * @param {SelectionModel} this
55632 * @param {Object} selection null for no selection or an object (o) with two properties
55634 <li>o.record: the record object for the row the selection is in</li>
55635 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55638 "selectionchange" : true,
55641 * Fires when the tab (or enter) was pressed on the last editable cell
55642 * You can use this to trigger add new row.
55643 * @param {SelectionModel} this
55647 * @event beforeeditnext
55648 * Fires before the next editable sell is made active
55649 * You can use this to skip to another cell or fire the tabend
55650 * if you set cell to false
55651 * @param {Object} eventdata object : { cell : [ row, col ] }
55653 "beforeeditnext" : true
55655 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55658 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55660 enter_is_tab: false,
55663 initEvents : function(){
55664 this.grid.on("mousedown", this.handleMouseDown, this);
55665 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55666 var view = this.grid.view;
55667 view.on("refresh", this.onViewChange, this);
55668 view.on("rowupdated", this.onRowUpdated, this);
55669 view.on("beforerowremoved", this.clearSelections, this);
55670 view.on("beforerowsinserted", this.clearSelections, this);
55671 if(this.grid.isEditor){
55672 this.grid.on("beforeedit", this.beforeEdit, this);
55677 beforeEdit : function(e){
55678 this.select(e.row, e.column, false, true, e.record);
55682 onRowUpdated : function(v, index, r){
55683 if(this.selection && this.selection.record == r){
55684 v.onCellSelect(index, this.selection.cell[1]);
55689 onViewChange : function(){
55690 this.clearSelections(true);
55694 * Returns the currently selected cell,.
55695 * @return {Array} The selected cell (row, column) or null if none selected.
55697 getSelectedCell : function(){
55698 return this.selection ? this.selection.cell : null;
55702 * Clears all selections.
55703 * @param {Boolean} true to prevent the gridview from being notified about the change.
55705 clearSelections : function(preventNotify){
55706 var s = this.selection;
55708 if(preventNotify !== true){
55709 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55711 this.selection = null;
55712 this.fireEvent("selectionchange", this, null);
55717 * Returns true if there is a selection.
55718 * @return {Boolean}
55720 hasSelection : function(){
55721 return this.selection ? true : false;
55725 handleMouseDown : function(e, t){
55726 var v = this.grid.getView();
55727 if(this.isLocked()){
55730 var row = v.findRowIndex(t);
55731 var cell = v.findCellIndex(t);
55732 if(row !== false && cell !== false){
55733 this.select(row, cell);
55739 * @param {Number} rowIndex
55740 * @param {Number} collIndex
55742 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55743 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55744 this.clearSelections();
55745 r = r || this.grid.dataSource.getAt(rowIndex);
55748 cell : [rowIndex, colIndex]
55750 if(!preventViewNotify){
55751 var v = this.grid.getView();
55752 v.onCellSelect(rowIndex, colIndex);
55753 if(preventFocus !== true){
55754 v.focusCell(rowIndex, colIndex);
55757 this.fireEvent("cellselect", this, rowIndex, colIndex);
55758 this.fireEvent("selectionchange", this, this.selection);
55763 isSelectable : function(rowIndex, colIndex, cm){
55764 return !cm.isHidden(colIndex);
55768 handleKeyDown : function(e){
55769 //Roo.log('Cell Sel Model handleKeyDown');
55770 if(!e.isNavKeyPress()){
55773 var g = this.grid, s = this.selection;
55776 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55778 this.select(cell[0], cell[1]);
55783 var walk = function(row, col, step){
55784 return g.walkCells(row, col, step, sm.isSelectable, sm);
55786 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55793 // handled by onEditorKey
55794 if (g.isEditor && g.editing) {
55798 newCell = walk(r, c-1, -1);
55800 newCell = walk(r, c+1, 1);
55805 newCell = walk(r+1, c, 1);
55809 newCell = walk(r-1, c, -1);
55813 newCell = walk(r, c+1, 1);
55817 newCell = walk(r, c-1, -1);
55822 if(g.isEditor && !g.editing){
55823 g.startEditing(r, c);
55832 this.select(newCell[0], newCell[1]);
55838 acceptsNav : function(row, col, cm){
55839 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55843 * @param {Number} field (not used) - as it's normally used as a listener
55844 * @param {Number} e - event - fake it by using
55846 * var e = Roo.EventObjectImpl.prototype;
55847 * e.keyCode = e.TAB
55851 onEditorKey : function(field, e){
55853 var k = e.getKey(),
55856 ed = g.activeEditor,
55858 ///Roo.log('onEditorKey' + k);
55861 if (this.enter_is_tab && k == e.ENTER) {
55867 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55869 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55875 } else if(k == e.ENTER && !e.ctrlKey){
55878 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55880 } else if(k == e.ESC){
55885 var ecall = { cell : newCell, forward : forward };
55886 this.fireEvent('beforeeditnext', ecall );
55887 newCell = ecall.cell;
55888 forward = ecall.forward;
55892 //Roo.log('next cell after edit');
55893 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55894 } else if (forward) {
55895 // tabbed past last
55896 this.fireEvent.defer(100, this, ['tabend',this]);
55901 * Ext JS Library 1.1.1
55902 * Copyright(c) 2006-2007, Ext JS, LLC.
55904 * Originally Released Under LGPL - original licence link has changed is not relivant.
55907 * <script type="text/javascript">
55911 * @class Roo.grid.EditorGrid
55912 * @extends Roo.grid.Grid
55913 * Class for creating and editable grid.
55914 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55915 * The container MUST have some type of size defined for the grid to fill. The container will be
55916 * automatically set to position relative if it isn't already.
55917 * @param {Object} dataSource The data model to bind to
55918 * @param {Object} colModel The column model with info about this grid's columns
55920 Roo.grid.EditorGrid = function(container, config){
55921 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55922 this.getGridEl().addClass("xedit-grid");
55924 if(!this.selModel){
55925 this.selModel = new Roo.grid.CellSelectionModel();
55928 this.activeEditor = null;
55932 * @event beforeedit
55933 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55934 * <ul style="padding:5px;padding-left:16px;">
55935 * <li>grid - This grid</li>
55936 * <li>record - The record being edited</li>
55937 * <li>field - The field name being edited</li>
55938 * <li>value - The value for the field being edited.</li>
55939 * <li>row - The grid row index</li>
55940 * <li>column - The grid column index</li>
55941 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55943 * @param {Object} e An edit event (see above for description)
55945 "beforeedit" : true,
55948 * Fires after a cell is edited. <br />
55949 * <ul style="padding:5px;padding-left:16px;">
55950 * <li>grid - This grid</li>
55951 * <li>record - The record being edited</li>
55952 * <li>field - The field name being edited</li>
55953 * <li>value - The value being set</li>
55954 * <li>originalValue - The original value for the field, before the edit.</li>
55955 * <li>row - The grid row index</li>
55956 * <li>column - The grid column index</li>
55958 * @param {Object} e An edit event (see above for description)
55960 "afteredit" : true,
55962 * @event validateedit
55963 * Fires after a cell is edited, but before the value is set in the record.
55964 * You can use this to modify the value being set in the field, Return false
55965 * to cancel the change. The edit event object has the following properties <br />
55966 * <ul style="padding:5px;padding-left:16px;">
55967 * <li>editor - This editor</li>
55968 * <li>grid - This grid</li>
55969 * <li>record - The record being edited</li>
55970 * <li>field - The field name being edited</li>
55971 * <li>value - The value being set</li>
55972 * <li>originalValue - The original value for the field, before the edit.</li>
55973 * <li>row - The grid row index</li>
55974 * <li>column - The grid column index</li>
55975 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55977 * @param {Object} e An edit event (see above for description)
55979 "validateedit" : true
55981 this.on("bodyscroll", this.stopEditing, this);
55982 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55985 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55987 * @cfg {Number} clicksToEdit
55988 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55995 trackMouseOver: false, // causes very odd FF errors
55997 onCellDblClick : function(g, row, col){
55998 this.startEditing(row, col);
56001 onEditComplete : function(ed, value, startValue){
56002 this.editing = false;
56003 this.activeEditor = null;
56004 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56006 var field = this.colModel.getDataIndex(ed.col);
56011 originalValue: startValue,
56018 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56021 if(String(value) !== String(startValue)){
56023 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56024 r.set(field, e.value);
56025 // if we are dealing with a combo box..
56026 // then we also set the 'name' colum to be the displayField
56027 if (ed.field.displayField && ed.field.name) {
56028 r.set(ed.field.name, ed.field.el.dom.value);
56031 delete e.cancel; //?? why!!!
56032 this.fireEvent("afteredit", e);
56035 this.fireEvent("afteredit", e); // always fire it!
56037 this.view.focusCell(ed.row, ed.col);
56041 * Starts editing the specified for the specified row/column
56042 * @param {Number} rowIndex
56043 * @param {Number} colIndex
56045 startEditing : function(row, col){
56046 this.stopEditing();
56047 if(this.colModel.isCellEditable(col, row)){
56048 this.view.ensureVisible(row, col, true);
56050 var r = this.dataSource.getAt(row);
56051 var field = this.colModel.getDataIndex(col);
56052 var cell = Roo.get(this.view.getCell(row,col));
56057 value: r.data[field],
56062 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56063 this.editing = true;
56064 var ed = this.colModel.getCellEditor(col, row);
56070 ed.render(ed.parentEl || document.body);
56076 (function(){ // complex but required for focus issues in safari, ie and opera
56080 ed.on("complete", this.onEditComplete, this, {single: true});
56081 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56082 this.activeEditor = ed;
56083 var v = r.data[field];
56084 ed.startEdit(this.view.getCell(row, col), v);
56085 // combo's with 'displayField and name set
56086 if (ed.field.displayField && ed.field.name) {
56087 ed.field.el.dom.value = r.data[ed.field.name];
56091 }).defer(50, this);
56097 * Stops any active editing
56099 stopEditing : function(){
56100 if(this.activeEditor){
56101 this.activeEditor.completeEdit();
56103 this.activeEditor = null;
56107 * Called to get grid's drag proxy text, by default returns this.ddText.
56110 getDragDropText : function(){
56111 var count = this.selModel.getSelectedCell() ? 1 : 0;
56112 return String.format(this.ddText, count, count == 1 ? '' : 's');
56117 * Ext JS Library 1.1.1
56118 * Copyright(c) 2006-2007, Ext JS, LLC.
56120 * Originally Released Under LGPL - original licence link has changed is not relivant.
56123 * <script type="text/javascript">
56126 // private - not really -- you end up using it !
56127 // This is a support class used internally by the Grid components
56130 * @class Roo.grid.GridEditor
56131 * @extends Roo.Editor
56132 * Class for creating and editable grid elements.
56133 * @param {Object} config any settings (must include field)
56135 Roo.grid.GridEditor = function(field, config){
56136 if (!config && field.field) {
56138 field = Roo.factory(config.field, Roo.form);
56140 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56141 field.monitorTab = false;
56144 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56147 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56150 alignment: "tl-tl",
56153 cls: "x-small-editor x-grid-editor",
56158 * Ext JS Library 1.1.1
56159 * Copyright(c) 2006-2007, Ext JS, LLC.
56161 * Originally Released Under LGPL - original licence link has changed is not relivant.
56164 * <script type="text/javascript">
56169 Roo.grid.PropertyRecord = Roo.data.Record.create([
56170 {name:'name',type:'string'}, 'value'
56174 Roo.grid.PropertyStore = function(grid, source){
56176 this.store = new Roo.data.Store({
56177 recordType : Roo.grid.PropertyRecord
56179 this.store.on('update', this.onUpdate, this);
56181 this.setSource(source);
56183 Roo.grid.PropertyStore.superclass.constructor.call(this);
56188 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56189 setSource : function(o){
56191 this.store.removeAll();
56194 if(this.isEditableValue(o[k])){
56195 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56198 this.store.loadRecords({records: data}, {}, true);
56201 onUpdate : function(ds, record, type){
56202 if(type == Roo.data.Record.EDIT){
56203 var v = record.data['value'];
56204 var oldValue = record.modified['value'];
56205 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56206 this.source[record.id] = v;
56208 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56215 getProperty : function(row){
56216 return this.store.getAt(row);
56219 isEditableValue: function(val){
56220 if(val && val instanceof Date){
56222 }else if(typeof val == 'object' || typeof val == 'function'){
56228 setValue : function(prop, value){
56229 this.source[prop] = value;
56230 this.store.getById(prop).set('value', value);
56233 getSource : function(){
56234 return this.source;
56238 Roo.grid.PropertyColumnModel = function(grid, store){
56241 g.PropertyColumnModel.superclass.constructor.call(this, [
56242 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56243 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56245 this.store = store;
56246 this.bselect = Roo.DomHelper.append(document.body, {
56247 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56248 {tag: 'option', value: 'true', html: 'true'},
56249 {tag: 'option', value: 'false', html: 'false'}
56252 Roo.id(this.bselect);
56255 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56256 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56257 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56258 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56259 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56261 this.renderCellDelegate = this.renderCell.createDelegate(this);
56262 this.renderPropDelegate = this.renderProp.createDelegate(this);
56265 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56269 valueText : 'Value',
56271 dateFormat : 'm/j/Y',
56274 renderDate : function(dateVal){
56275 return dateVal.dateFormat(this.dateFormat);
56278 renderBool : function(bVal){
56279 return bVal ? 'true' : 'false';
56282 isCellEditable : function(colIndex, rowIndex){
56283 return colIndex == 1;
56286 getRenderer : function(col){
56288 this.renderCellDelegate : this.renderPropDelegate;
56291 renderProp : function(v){
56292 return this.getPropertyName(v);
56295 renderCell : function(val){
56297 if(val instanceof Date){
56298 rv = this.renderDate(val);
56299 }else if(typeof val == 'boolean'){
56300 rv = this.renderBool(val);
56302 return Roo.util.Format.htmlEncode(rv);
56305 getPropertyName : function(name){
56306 var pn = this.grid.propertyNames;
56307 return pn && pn[name] ? pn[name] : name;
56310 getCellEditor : function(colIndex, rowIndex){
56311 var p = this.store.getProperty(rowIndex);
56312 var n = p.data['name'], val = p.data['value'];
56314 if(typeof(this.grid.customEditors[n]) == 'string'){
56315 return this.editors[this.grid.customEditors[n]];
56317 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56318 return this.grid.customEditors[n];
56320 if(val instanceof Date){
56321 return this.editors['date'];
56322 }else if(typeof val == 'number'){
56323 return this.editors['number'];
56324 }else if(typeof val == 'boolean'){
56325 return this.editors['boolean'];
56327 return this.editors['string'];
56333 * @class Roo.grid.PropertyGrid
56334 * @extends Roo.grid.EditorGrid
56335 * This class represents the interface of a component based property grid control.
56336 * <br><br>Usage:<pre><code>
56337 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56345 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56346 * The container MUST have some type of size defined for the grid to fill. The container will be
56347 * automatically set to position relative if it isn't already.
56348 * @param {Object} config A config object that sets properties on this grid.
56350 Roo.grid.PropertyGrid = function(container, config){
56351 config = config || {};
56352 var store = new Roo.grid.PropertyStore(this);
56353 this.store = store;
56354 var cm = new Roo.grid.PropertyColumnModel(this, store);
56355 store.store.sort('name', 'ASC');
56356 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56359 enableColLock:false,
56360 enableColumnMove:false,
56362 trackMouseOver: false,
56365 this.getGridEl().addClass('x-props-grid');
56366 this.lastEditRow = null;
56367 this.on('columnresize', this.onColumnResize, this);
56370 * @event beforepropertychange
56371 * Fires before a property changes (return false to stop?)
56372 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56373 * @param {String} id Record Id
56374 * @param {String} newval New Value
56375 * @param {String} oldval Old Value
56377 "beforepropertychange": true,
56379 * @event propertychange
56380 * Fires after a property changes
56381 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56382 * @param {String} id Record Id
56383 * @param {String} newval New Value
56384 * @param {String} oldval Old Value
56386 "propertychange": true
56388 this.customEditors = this.customEditors || {};
56390 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56393 * @cfg {Object} customEditors map of colnames=> custom editors.
56394 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56395 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56396 * false disables editing of the field.
56400 * @cfg {Object} propertyNames map of property Names to their displayed value
56403 render : function(){
56404 Roo.grid.PropertyGrid.superclass.render.call(this);
56405 this.autoSize.defer(100, this);
56408 autoSize : function(){
56409 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56411 this.view.fitColumns();
56415 onColumnResize : function(){
56416 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56420 * Sets the data for the Grid
56421 * accepts a Key => Value object of all the elements avaiable.
56422 * @param {Object} data to appear in grid.
56424 setSource : function(source){
56425 this.store.setSource(source);
56429 * Gets all the data from the grid.
56430 * @return {Object} data data stored in grid
56432 getSource : function(){
56433 return this.store.getSource();
56442 * @class Roo.grid.Calendar
56443 * @extends Roo.util.Grid
56444 * This class extends the Grid to provide a calendar widget
56445 * <br><br>Usage:<pre><code>
56446 var grid = new Roo.grid.Calendar("my-container-id", {
56449 selModel: mySelectionModel,
56450 autoSizeColumns: true,
56451 monitorWindowResize: false,
56452 trackMouseOver: true
56453 eventstore : real data store..
56459 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56460 * The container MUST have some type of size defined for the grid to fill. The container will be
56461 * automatically set to position relative if it isn't already.
56462 * @param {Object} config A config object that sets properties on this grid.
56464 Roo.grid.Calendar = function(container, config){
56465 // initialize the container
56466 this.container = Roo.get(container);
56467 this.container.update("");
56468 this.container.setStyle("overflow", "hidden");
56469 this.container.addClass('x-grid-container');
56471 this.id = this.container.id;
56473 Roo.apply(this, config);
56474 // check and correct shorthanded configs
56478 for (var r = 0;r < 6;r++) {
56481 for (var c =0;c < 7;c++) {
56485 if (this.eventStore) {
56486 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56487 this.eventStore.on('load',this.onLoad, this);
56488 this.eventStore.on('beforeload',this.clearEvents, this);
56492 this.dataSource = new Roo.data.Store({
56493 proxy: new Roo.data.MemoryProxy(rows),
56494 reader: new Roo.data.ArrayReader({}, [
56495 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56498 this.dataSource.load();
56499 this.ds = this.dataSource;
56500 this.ds.xmodule = this.xmodule || false;
56503 var cellRender = function(v,x,r)
56505 return String.format(
56506 '<div class="fc-day fc-widget-content"><div>' +
56507 '<div class="fc-event-container"></div>' +
56508 '<div class="fc-day-number">{0}</div>'+
56510 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56511 '</div></div>', v);
56516 this.colModel = new Roo.grid.ColumnModel( [
56518 xtype: 'ColumnModel',
56520 dataIndex : 'weekday0',
56522 renderer : cellRender
56525 xtype: 'ColumnModel',
56527 dataIndex : 'weekday1',
56529 renderer : cellRender
56532 xtype: 'ColumnModel',
56534 dataIndex : 'weekday2',
56535 header : 'Tuesday',
56536 renderer : cellRender
56539 xtype: 'ColumnModel',
56541 dataIndex : 'weekday3',
56542 header : 'Wednesday',
56543 renderer : cellRender
56546 xtype: 'ColumnModel',
56548 dataIndex : 'weekday4',
56549 header : 'Thursday',
56550 renderer : cellRender
56553 xtype: 'ColumnModel',
56555 dataIndex : 'weekday5',
56557 renderer : cellRender
56560 xtype: 'ColumnModel',
56562 dataIndex : 'weekday6',
56563 header : 'Saturday',
56564 renderer : cellRender
56567 this.cm = this.colModel;
56568 this.cm.xmodule = this.xmodule || false;
56572 //this.selModel = new Roo.grid.CellSelectionModel();
56573 //this.sm = this.selModel;
56574 //this.selModel.init(this);
56578 this.container.setWidth(this.width);
56582 this.container.setHeight(this.height);
56589 * The raw click event for the entire grid.
56590 * @param {Roo.EventObject} e
56595 * The raw dblclick event for the entire grid.
56596 * @param {Roo.EventObject} e
56600 * @event contextmenu
56601 * The raw contextmenu event for the entire grid.
56602 * @param {Roo.EventObject} e
56604 "contextmenu" : true,
56607 * The raw mousedown event for the entire grid.
56608 * @param {Roo.EventObject} e
56610 "mousedown" : true,
56613 * The raw mouseup event for the entire grid.
56614 * @param {Roo.EventObject} e
56619 * The raw mouseover event for the entire grid.
56620 * @param {Roo.EventObject} e
56622 "mouseover" : true,
56625 * The raw mouseout event for the entire grid.
56626 * @param {Roo.EventObject} e
56631 * The raw keypress event for the entire grid.
56632 * @param {Roo.EventObject} e
56637 * The raw keydown event for the entire grid.
56638 * @param {Roo.EventObject} e
56646 * Fires when a cell is clicked
56647 * @param {Grid} this
56648 * @param {Number} rowIndex
56649 * @param {Number} columnIndex
56650 * @param {Roo.EventObject} e
56652 "cellclick" : true,
56654 * @event celldblclick
56655 * Fires when a cell is double clicked
56656 * @param {Grid} this
56657 * @param {Number} rowIndex
56658 * @param {Number} columnIndex
56659 * @param {Roo.EventObject} e
56661 "celldblclick" : true,
56664 * Fires when a row is clicked
56665 * @param {Grid} this
56666 * @param {Number} rowIndex
56667 * @param {Roo.EventObject} e
56671 * @event rowdblclick
56672 * Fires when a row is double clicked
56673 * @param {Grid} this
56674 * @param {Number} rowIndex
56675 * @param {Roo.EventObject} e
56677 "rowdblclick" : true,
56679 * @event headerclick
56680 * Fires when a header is clicked
56681 * @param {Grid} this
56682 * @param {Number} columnIndex
56683 * @param {Roo.EventObject} e
56685 "headerclick" : true,
56687 * @event headerdblclick
56688 * Fires when a header cell is double clicked
56689 * @param {Grid} this
56690 * @param {Number} columnIndex
56691 * @param {Roo.EventObject} e
56693 "headerdblclick" : true,
56695 * @event rowcontextmenu
56696 * Fires when a row is right clicked
56697 * @param {Grid} this
56698 * @param {Number} rowIndex
56699 * @param {Roo.EventObject} e
56701 "rowcontextmenu" : true,
56703 * @event cellcontextmenu
56704 * Fires when a cell is right clicked
56705 * @param {Grid} this
56706 * @param {Number} rowIndex
56707 * @param {Number} cellIndex
56708 * @param {Roo.EventObject} e
56710 "cellcontextmenu" : true,
56712 * @event headercontextmenu
56713 * Fires when a header is right clicked
56714 * @param {Grid} this
56715 * @param {Number} columnIndex
56716 * @param {Roo.EventObject} e
56718 "headercontextmenu" : true,
56720 * @event bodyscroll
56721 * Fires when the body element is scrolled
56722 * @param {Number} scrollLeft
56723 * @param {Number} scrollTop
56725 "bodyscroll" : true,
56727 * @event columnresize
56728 * Fires when the user resizes a column
56729 * @param {Number} columnIndex
56730 * @param {Number} newSize
56732 "columnresize" : true,
56734 * @event columnmove
56735 * Fires when the user moves a column
56736 * @param {Number} oldIndex
56737 * @param {Number} newIndex
56739 "columnmove" : true,
56742 * Fires when row(s) start being dragged
56743 * @param {Grid} this
56744 * @param {Roo.GridDD} dd The drag drop object
56745 * @param {event} e The raw browser event
56747 "startdrag" : true,
56750 * Fires when a drag operation is complete
56751 * @param {Grid} this
56752 * @param {Roo.GridDD} dd The drag drop object
56753 * @param {event} e The raw browser event
56758 * Fires when dragged row(s) are dropped on a valid DD target
56759 * @param {Grid} this
56760 * @param {Roo.GridDD} dd The drag drop object
56761 * @param {String} targetId The target drag drop object
56762 * @param {event} e The raw browser event
56767 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56768 * @param {Grid} this
56769 * @param {Roo.GridDD} dd The drag drop object
56770 * @param {String} targetId The target drag drop object
56771 * @param {event} e The raw browser event
56776 * Fires when the dragged row(s) first cross another DD target while being dragged
56777 * @param {Grid} this
56778 * @param {Roo.GridDD} dd The drag drop object
56779 * @param {String} targetId The target drag drop object
56780 * @param {event} e The raw browser event
56782 "dragenter" : true,
56785 * Fires when the dragged row(s) leave another DD target while being dragged
56786 * @param {Grid} this
56787 * @param {Roo.GridDD} dd The drag drop object
56788 * @param {String} targetId The target drag drop object
56789 * @param {event} e The raw browser event
56794 * Fires when a row is rendered, so you can change add a style to it.
56795 * @param {GridView} gridview The grid view
56796 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56802 * Fires when the grid is rendered
56803 * @param {Grid} grid
56808 * Fires when a date is selected
56809 * @param {DatePicker} this
56810 * @param {Date} date The selected date
56814 * @event monthchange
56815 * Fires when the displayed month changes
56816 * @param {DatePicker} this
56817 * @param {Date} date The selected month
56819 'monthchange': true,
56821 * @event evententer
56822 * Fires when mouse over an event
56823 * @param {Calendar} this
56824 * @param {event} Event
56826 'evententer': true,
56828 * @event eventleave
56829 * Fires when the mouse leaves an
56830 * @param {Calendar} this
56833 'eventleave': true,
56835 * @event eventclick
56836 * Fires when the mouse click an
56837 * @param {Calendar} this
56840 'eventclick': true,
56842 * @event eventrender
56843 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56844 * @param {Calendar} this
56845 * @param {data} data to be modified
56847 'eventrender': true
56851 Roo.grid.Grid.superclass.constructor.call(this);
56852 this.on('render', function() {
56853 this.view.el.addClass('x-grid-cal');
56855 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56859 if (!Roo.grid.Calendar.style) {
56860 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56863 '.x-grid-cal .x-grid-col' : {
56864 height: 'auto !important',
56865 'vertical-align': 'top'
56867 '.x-grid-cal .fc-event-hori' : {
56878 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56880 * @cfg {Store} eventStore The store that loads events.
56885 activeDate : false,
56888 monitorWindowResize : false,
56891 resizeColumns : function() {
56892 var col = (this.view.el.getWidth() / 7) - 3;
56893 // loop through cols, and setWidth
56894 for(var i =0 ; i < 7 ; i++){
56895 this.cm.setColumnWidth(i, col);
56898 setDate :function(date) {
56900 Roo.log('setDate?');
56902 this.resizeColumns();
56903 var vd = this.activeDate;
56904 this.activeDate = date;
56905 // if(vd && this.el){
56906 // var t = date.getTime();
56907 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56908 // Roo.log('using add remove');
56910 // this.fireEvent('monthchange', this, date);
56912 // this.cells.removeClass("fc-state-highlight");
56913 // this.cells.each(function(c){
56914 // if(c.dateValue == t){
56915 // c.addClass("fc-state-highlight");
56916 // setTimeout(function(){
56917 // try{c.dom.firstChild.focus();}catch(e){}
56927 var days = date.getDaysInMonth();
56929 var firstOfMonth = date.getFirstDateOfMonth();
56930 var startingPos = firstOfMonth.getDay()-this.startDay;
56932 if(startingPos < this.startDay){
56936 var pm = date.add(Date.MONTH, -1);
56937 var prevStart = pm.getDaysInMonth()-startingPos;
56941 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56943 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
56944 //this.cells.addClassOnOver('fc-state-hover');
56946 var cells = this.cells.elements;
56947 var textEls = this.textNodes;
56949 //Roo.each(cells, function(cell){
56950 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
56953 days += startingPos;
56955 // convert everything to numbers so it's fast
56956 var day = 86400000;
56957 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
56960 //Roo.log(prevStart);
56962 var today = new Date().clearTime().getTime();
56963 var sel = date.clearTime().getTime();
56964 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
56965 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
56966 var ddMatch = this.disabledDatesRE;
56967 var ddText = this.disabledDatesText;
56968 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
56969 var ddaysText = this.disabledDaysText;
56970 var format = this.format;
56972 var setCellClass = function(cal, cell){
56974 //Roo.log('set Cell Class');
56976 var t = d.getTime();
56981 cell.dateValue = t;
56983 cell.className += " fc-today";
56984 cell.className += " fc-state-highlight";
56985 cell.title = cal.todayText;
56988 // disable highlight in other month..
56989 cell.className += " fc-state-highlight";
56994 //cell.className = " fc-state-disabled";
56995 cell.title = cal.minText;
56999 //cell.className = " fc-state-disabled";
57000 cell.title = cal.maxText;
57004 if(ddays.indexOf(d.getDay()) != -1){
57005 // cell.title = ddaysText;
57006 // cell.className = " fc-state-disabled";
57009 if(ddMatch && format){
57010 var fvalue = d.dateFormat(format);
57011 if(ddMatch.test(fvalue)){
57012 cell.title = ddText.replace("%0", fvalue);
57013 cell.className = " fc-state-disabled";
57017 if (!cell.initialClassName) {
57018 cell.initialClassName = cell.dom.className;
57021 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57026 for(; i < startingPos; i++) {
57027 cells[i].dayName = (++prevStart);
57028 Roo.log(textEls[i]);
57029 d.setDate(d.getDate()+1);
57031 //cells[i].className = "fc-past fc-other-month";
57032 setCellClass(this, cells[i]);
57037 for(; i < days; i++){
57038 intDay = i - startingPos + 1;
57039 cells[i].dayName = (intDay);
57040 d.setDate(d.getDate()+1);
57042 cells[i].className = ''; // "x-date-active";
57043 setCellClass(this, cells[i]);
57047 for(; i < 42; i++) {
57048 //textEls[i].innerHTML = (++extraDays);
57050 d.setDate(d.getDate()+1);
57051 cells[i].dayName = (++extraDays);
57052 cells[i].className = "fc-future fc-other-month";
57053 setCellClass(this, cells[i]);
57056 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57058 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57060 // this will cause all the cells to mis
57063 for (var r = 0;r < 6;r++) {
57064 for (var c =0;c < 7;c++) {
57065 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57069 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57070 for(i=0;i<cells.length;i++) {
57072 this.cells.elements[i].dayName = cells[i].dayName ;
57073 this.cells.elements[i].className = cells[i].className;
57074 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57075 this.cells.elements[i].title = cells[i].title ;
57076 this.cells.elements[i].dateValue = cells[i].dateValue ;
57082 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57083 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57085 ////if(totalRows != 6){
57086 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57087 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57090 this.fireEvent('monthchange', this, date);
57095 * Returns the grid's SelectionModel.
57096 * @return {SelectionModel}
57098 getSelectionModel : function(){
57099 if(!this.selModel){
57100 this.selModel = new Roo.grid.CellSelectionModel();
57102 return this.selModel;
57106 this.eventStore.load()
57112 findCell : function(dt) {
57113 dt = dt.clearTime().getTime();
57115 this.cells.each(function(c){
57116 //Roo.log("check " +c.dateValue + '?=' + dt);
57117 if(c.dateValue == dt){
57127 findCells : function(rec) {
57128 var s = rec.data.start_dt.clone().clearTime().getTime();
57130 var e= rec.data.end_dt.clone().clearTime().getTime();
57133 this.cells.each(function(c){
57134 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57136 if(c.dateValue > e){
57139 if(c.dateValue < s){
57148 findBestRow: function(cells)
57152 for (var i =0 ; i < cells.length;i++) {
57153 ret = Math.max(cells[i].rows || 0,ret);
57160 addItem : function(rec)
57162 // look for vertical location slot in
57163 var cells = this.findCells(rec);
57165 rec.row = this.findBestRow(cells);
57167 // work out the location.
57171 for(var i =0; i < cells.length; i++) {
57179 if (crow.start.getY() == cells[i].getY()) {
57181 crow.end = cells[i];
57197 for (var i = 0; i < cells.length;i++) {
57198 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57205 clearEvents: function() {
57207 if (!this.eventStore.getCount()) {
57210 // reset number of rows in cells.
57211 Roo.each(this.cells.elements, function(c){
57215 this.eventStore.each(function(e) {
57216 this.clearEvent(e);
57221 clearEvent : function(ev)
57224 Roo.each(ev.els, function(el) {
57225 el.un('mouseenter' ,this.onEventEnter, this);
57226 el.un('mouseleave' ,this.onEventLeave, this);
57234 renderEvent : function(ev,ctr) {
57236 ctr = this.view.el.select('.fc-event-container',true).first();
57240 this.clearEvent(ev);
57246 var cells = ev.cells;
57247 var rows = ev.rows;
57248 this.fireEvent('eventrender', this, ev);
57250 for(var i =0; i < rows.length; i++) {
57254 cls += ' fc-event-start';
57256 if ((i+1) == rows.length) {
57257 cls += ' fc-event-end';
57260 //Roo.log(ev.data);
57261 // how many rows should it span..
57262 var cg = this.eventTmpl.append(ctr,Roo.apply({
57265 }, ev.data) , true);
57268 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57269 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57270 cg.on('click', this.onEventClick, this, ev);
57274 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57275 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57278 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57279 cg.setWidth(ebox.right - sbox.x -2);
57283 renderEvents: function()
57285 // first make sure there is enough space..
57287 if (!this.eventTmpl) {
57288 this.eventTmpl = new Roo.Template(
57289 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57290 '<div class="fc-event-inner">' +
57291 '<span class="fc-event-time">{time}</span>' +
57292 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57294 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57302 this.cells.each(function(c) {
57303 //Roo.log(c.select('.fc-day-content div',true).first());
57304 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57307 var ctr = this.view.el.select('.fc-event-container',true).first();
57310 this.eventStore.each(function(ev){
57312 this.renderEvent(ev);
57316 this.view.layout();
57320 onEventEnter: function (e, el,event,d) {
57321 this.fireEvent('evententer', this, el, event);
57324 onEventLeave: function (e, el,event,d) {
57325 this.fireEvent('eventleave', this, el, event);
57328 onEventClick: function (e, el,event,d) {
57329 this.fireEvent('eventclick', this, el, event);
57332 onMonthChange: function () {
57336 onLoad: function () {
57338 //Roo.log('calendar onload');
57340 if(this.eventStore.getCount() > 0){
57344 this.eventStore.each(function(d){
57349 if (typeof(add.end_dt) == 'undefined') {
57350 Roo.log("Missing End time in calendar data: ");
57354 if (typeof(add.start_dt) == 'undefined') {
57355 Roo.log("Missing Start time in calendar data: ");
57359 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57360 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57361 add.id = add.id || d.id;
57362 add.title = add.title || '??';
57370 this.renderEvents();
57380 render : function ()
57384 if (!this.view.el.hasClass('course-timesheet')) {
57385 this.view.el.addClass('course-timesheet');
57387 if (this.tsStyle) {
57392 Roo.log(_this.grid.view.el.getWidth());
57395 this.tsStyle = Roo.util.CSS.createStyleSheet({
57396 '.course-timesheet .x-grid-row' : {
57399 '.x-grid-row td' : {
57400 'vertical-align' : 0
57402 '.course-edit-link' : {
57404 'text-overflow' : 'ellipsis',
57405 'overflow' : 'hidden',
57406 'white-space' : 'nowrap',
57407 'cursor' : 'pointer'
57412 '.de-act-sup-link' : {
57413 'color' : 'purple',
57414 'text-decoration' : 'line-through'
57418 'text-decoration' : 'line-through'
57420 '.course-timesheet .course-highlight' : {
57421 'border-top-style': 'dashed !important',
57422 'border-bottom-bottom': 'dashed !important'
57424 '.course-timesheet .course-item' : {
57425 'font-family' : 'tahoma, arial, helvetica',
57426 'font-size' : '11px',
57427 'overflow' : 'hidden',
57428 'padding-left' : '10px',
57429 'padding-right' : '10px',
57430 'padding-top' : '10px'
57438 monitorWindowResize : false,
57439 cellrenderer : function(v,x,r)
57444 xtype: 'CellSelectionModel',
57451 beforeload : function (_self, options)
57453 options.params = options.params || {};
57454 options.params._month = _this.monthField.getValue();
57455 options.params.limit = 9999;
57456 options.params['sort'] = 'when_dt';
57457 options.params['dir'] = 'ASC';
57458 this.proxy.loadResponse = this.loadResponse;
57460 //this.addColumns();
57462 load : function (_self, records, options)
57464 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57465 // if you click on the translation.. you can edit it...
57466 var el = Roo.get(this);
57467 var id = el.dom.getAttribute('data-id');
57468 var d = el.dom.getAttribute('data-date');
57469 var t = el.dom.getAttribute('data-time');
57470 //var id = this.child('span').dom.textContent;
57473 Pman.Dialog.CourseCalendar.show({
57477 productitem_active : id ? 1 : 0
57479 _this.grid.ds.load({});
57484 _this.panel.fireEvent('resize', [ '', '' ]);
57487 loadResponse : function(o, success, response){
57488 // this is overridden on before load..
57490 Roo.log("our code?");
57491 //Roo.log(success);
57492 //Roo.log(response)
57493 delete this.activeRequest;
57495 this.fireEvent("loadexception", this, o, response);
57496 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57501 result = o.reader.read(response);
57503 Roo.log("load exception?");
57504 this.fireEvent("loadexception", this, o, response, e);
57505 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57508 Roo.log("ready...");
57509 // loop through result.records;
57510 // and set this.tdate[date] = [] << array of records..
57512 Roo.each(result.records, function(r){
57514 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57515 _this.tdata[r.data.when_dt.format('j')] = [];
57517 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57520 //Roo.log(_this.tdata);
57522 result.records = [];
57523 result.totalRecords = 6;
57525 // let's generate some duumy records for the rows.
57526 //var st = _this.dateField.getValue();
57528 // work out monday..
57529 //st = st.add(Date.DAY, -1 * st.format('w'));
57531 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57533 var firstOfMonth = date.getFirstDayOfMonth();
57534 var days = date.getDaysInMonth();
57536 var firstAdded = false;
57537 for (var i = 0; i < result.totalRecords ; i++) {
57538 //var d= st.add(Date.DAY, i);
57541 for(var w = 0 ; w < 7 ; w++){
57542 if(!firstAdded && firstOfMonth != w){
57549 var dd = (d > 0 && d < 10) ? "0"+d : d;
57550 row['weekday'+w] = String.format(
57551 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57552 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57554 date.format('Y-m-')+dd
57557 if(typeof(_this.tdata[d]) != 'undefined'){
57558 Roo.each(_this.tdata[d], function(r){
57562 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57563 if(r.parent_id*1>0){
57564 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57567 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57568 deactive = 'de-act-link';
57571 row['weekday'+w] += String.format(
57572 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57574 r.product_id_name, //1
57575 r.when_dt.format('h:ia'), //2
57585 // only do this if something added..
57587 result.records.push(_this.grid.dataSource.reader.newRow(row));
57591 // push it twice. (second one with an hour..
57595 this.fireEvent("load", this, o, o.request.arg);
57596 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57598 sortInfo : {field: 'when_dt', direction : 'ASC' },
57600 xtype: 'HttpProxy',
57603 url : baseURL + '/Roo/Shop_course.php'
57606 xtype: 'JsonReader',
57623 'name': 'parent_id',
57627 'name': 'product_id',
57631 'name': 'productitem_id',
57649 click : function (_self, e)
57651 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57652 sd.setMonth(sd.getMonth()-1);
57653 _this.monthField.setValue(sd.format('Y-m-d'));
57654 _this.grid.ds.load({});
57660 xtype: 'Separator',
57664 xtype: 'MonthField',
57667 render : function (_self)
57669 _this.monthField = _self;
57670 // _this.monthField.set today
57672 select : function (combo, date)
57674 _this.grid.ds.load({});
57677 value : (function() { return new Date(); })()
57680 xtype: 'Separator',
57686 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57696 click : function (_self, e)
57698 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57699 sd.setMonth(sd.getMonth()+1);
57700 _this.monthField.setValue(sd.format('Y-m-d'));
57701 _this.grid.ds.load({});
57714 * Ext JS Library 1.1.1
57715 * Copyright(c) 2006-2007, Ext JS, LLC.
57717 * Originally Released Under LGPL - original licence link has changed is not relivant.
57720 * <script type="text/javascript">
57724 * @class Roo.LoadMask
57725 * A simple utility class for generically masking elements while loading data. If the element being masked has
57726 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57727 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57728 * element's UpdateManager load indicator and will be destroyed after the initial load.
57730 * Create a new LoadMask
57731 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57732 * @param {Object} config The config object
57734 Roo.LoadMask = function(el, config){
57735 this.el = Roo.get(el);
57736 Roo.apply(this, config);
57738 this.store.on('beforeload', this.onBeforeLoad, this);
57739 this.store.on('load', this.onLoad, this);
57740 this.store.on('loadexception', this.onLoadException, this);
57741 this.removeMask = false;
57743 var um = this.el.getUpdateManager();
57744 um.showLoadIndicator = false; // disable the default indicator
57745 um.on('beforeupdate', this.onBeforeLoad, this);
57746 um.on('update', this.onLoad, this);
57747 um.on('failure', this.onLoad, this);
57748 this.removeMask = true;
57752 Roo.LoadMask.prototype = {
57754 * @cfg {Boolean} removeMask
57755 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57756 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57759 * @cfg {String} msg
57760 * The text to display in a centered loading message box (defaults to 'Loading...')
57762 msg : 'Loading...',
57764 * @cfg {String} msgCls
57765 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57767 msgCls : 'x-mask-loading',
57770 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57776 * Disables the mask to prevent it from being displayed
57778 disable : function(){
57779 this.disabled = true;
57783 * Enables the mask so that it can be displayed
57785 enable : function(){
57786 this.disabled = false;
57789 onLoadException : function()
57791 Roo.log(arguments);
57793 if (typeof(arguments[3]) != 'undefined') {
57794 Roo.MessageBox.alert("Error loading",arguments[3]);
57798 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57799 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57808 this.el.unmask(this.removeMask);
57811 onLoad : function()
57813 this.el.unmask(this.removeMask);
57817 onBeforeLoad : function(){
57818 if(!this.disabled){
57819 this.el.mask(this.msg, this.msgCls);
57824 destroy : function(){
57826 this.store.un('beforeload', this.onBeforeLoad, this);
57827 this.store.un('load', this.onLoad, this);
57828 this.store.un('loadexception', this.onLoadException, this);
57830 var um = this.el.getUpdateManager();
57831 um.un('beforeupdate', this.onBeforeLoad, this);
57832 um.un('update', this.onLoad, this);
57833 um.un('failure', this.onLoad, this);
57838 * Ext JS Library 1.1.1
57839 * Copyright(c) 2006-2007, Ext JS, LLC.
57841 * Originally Released Under LGPL - original licence link has changed is not relivant.
57844 * <script type="text/javascript">
57849 * @class Roo.XTemplate
57850 * @extends Roo.Template
57851 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57853 var t = new Roo.XTemplate(
57854 '<select name="{name}">',
57855 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57859 // then append, applying the master template values
57862 * Supported features:
57867 {a_variable} - output encoded.
57868 {a_variable.format:("Y-m-d")} - call a method on the variable
57869 {a_variable:raw} - unencoded output
57870 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57871 {a_variable:this.method_on_template(...)} - call a method on the template object.
57876 <tpl for="a_variable or condition.."></tpl>
57877 <tpl if="a_variable or condition"></tpl>
57878 <tpl exec="some javascript"></tpl>
57879 <tpl name="named_template"></tpl> (experimental)
57881 <tpl for="."></tpl> - just iterate the property..
57882 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57886 Roo.XTemplate = function()
57888 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57895 Roo.extend(Roo.XTemplate, Roo.Template, {
57898 * The various sub templates
57903 * basic tag replacing syntax
57906 * // you can fake an object call by doing this
57910 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57913 * compile the template
57915 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57918 compile: function()
57922 s = ['<tpl>', s, '</tpl>'].join('');
57924 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57925 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57926 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57927 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57928 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57933 while(true == !!(m = s.match(re))){
57934 var forMatch = m[0].match(nameRe),
57935 ifMatch = m[0].match(ifRe),
57936 execMatch = m[0].match(execRe),
57937 namedMatch = m[0].match(namedRe),
57942 name = forMatch && forMatch[1] ? forMatch[1] : '';
57945 // if - puts fn into test..
57946 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
57948 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
57953 // exec - calls a function... returns empty if true is returned.
57954 exp = execMatch && execMatch[1] ? execMatch[1] : null;
57956 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
57964 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
57965 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
57966 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
57969 var uid = namedMatch ? namedMatch[1] : id;
57973 id: namedMatch ? namedMatch[1] : id,
57980 s = s.replace(m[0], '');
57982 s = s.replace(m[0], '{xtpl'+ id + '}');
57987 for(var i = tpls.length-1; i >= 0; --i){
57988 this.compileTpl(tpls[i]);
57989 this.tpls[tpls[i].id] = tpls[i];
57991 this.master = tpls[tpls.length-1];
57995 * same as applyTemplate, except it's done to one of the subTemplates
57996 * when using named templates, you can do:
57998 * var str = pl.applySubTemplate('your-name', values);
58001 * @param {Number} id of the template
58002 * @param {Object} values to apply to template
58003 * @param {Object} parent (normaly the instance of this object)
58005 applySubTemplate : function(id, values, parent)
58009 var t = this.tpls[id];
58013 if(t.test && !t.test.call(this, values, parent)){
58017 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58018 Roo.log(e.toString());
58024 if(t.exec && t.exec.call(this, values, parent)){
58028 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58029 Roo.log(e.toString());
58034 var vs = t.target ? t.target.call(this, values, parent) : values;
58035 parent = t.target ? values : parent;
58036 if(t.target && vs instanceof Array){
58038 for(var i = 0, len = vs.length; i < len; i++){
58039 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58041 return buf.join('');
58043 return t.compiled.call(this, vs, parent);
58045 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58046 Roo.log(e.toString());
58047 Roo.log(t.compiled);
58052 compileTpl : function(tpl)
58054 var fm = Roo.util.Format;
58055 var useF = this.disableFormats !== true;
58056 var sep = Roo.isGecko ? "+" : ",";
58057 var undef = function(str) {
58058 Roo.log("Property not found :" + str);
58062 var fn = function(m, name, format, args)
58064 //Roo.log(arguments);
58065 args = args ? args.replace(/\\'/g,"'") : args;
58066 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58067 if (typeof(format) == 'undefined') {
58068 format= 'htmlEncode';
58070 if (format == 'raw' ) {
58074 if(name.substr(0, 4) == 'xtpl'){
58075 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58078 // build an array of options to determine if value is undefined..
58080 // basically get 'xxxx.yyyy' then do
58081 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58082 // (function () { Roo.log("Property not found"); return ''; })() :
58087 Roo.each(name.split('.'), function(st) {
58088 lookfor += (lookfor.length ? '.': '') + st;
58089 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58092 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58095 if(format && useF){
58097 args = args ? ',' + args : "";
58099 if(format.substr(0, 5) != "this."){
58100 format = "fm." + format + '(';
58102 format = 'this.call("'+ format.substr(5) + '", ';
58106 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58110 // called with xxyx.yuu:(test,test)
58112 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58114 // raw.. - :raw modifier..
58115 return "'"+ sep + udef_st + name + ")"+sep+"'";
58119 // branched to use + in gecko and [].join() in others
58121 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58122 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58125 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58126 body.push(tpl.body.replace(/(\r\n|\n)/g,
58127 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58128 body.push("'].join('');};};");
58129 body = body.join('');
58132 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58134 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58140 applyTemplate : function(values){
58141 return this.master.compiled.call(this, values, {});
58142 //var s = this.subs;
58145 apply : function(){
58146 return this.applyTemplate.apply(this, arguments);
58151 Roo.XTemplate.from = function(el){
58152 el = Roo.getDom(el);
58153 return new Roo.XTemplate(el.value || el.innerHTML);