4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isGecko = !isSafari && ua.indexOf("gecko") > -1,
60 isBorderBox = isIE && !isStrict,
61 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
62 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
63 isLinux = (ua.indexOf("linux") != -1),
64 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
65 isTouch = (function() {
67 document.createEvent("TouchEvent");
74 // remove css image flicker
77 document.execCommand("BackgroundImageCache", false, true);
83 * True if the browser is in strict mode
88 * True if the page is running over SSL
93 * True when the document is fully initialized and ready for action
98 * Turn on debugging output (currently only the factory uses this)
105 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
108 enableGarbageCollector : true,
111 * True to automatically purge event listeners after uncaching an element (defaults to false).
112 * Note: this only happens if enableGarbageCollector is true.
115 enableListenerCollection:false,
118 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
119 * the IE insecure content warning (defaults to javascript:false).
122 SSL_SECURE_URL : "javascript:false",
125 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
126 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
129 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
131 emptyFn : function(){},
134 * Copies all the properties of config to obj if they don't already exist.
135 * @param {Object} obj The receiver of the properties
136 * @param {Object} config The source of the properties
137 * @return {Object} returns obj
139 applyIf : function(o, c){
142 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
149 * Applies event listeners to elements by selectors when the document is ready.
150 * The event name is specified with an @ suffix.
153 // add a listener for click on all anchors in element with id foo
154 '#foo a@click' : function(e, t){
158 // add the same listener to multiple selectors (separated by comma BEFORE the @)
159 '#foo a, #bar span.some-class@mouseover' : function(){
164 * @param {Object} obj The list of behaviors to apply
166 addBehaviors : function(o){
168 Roo.onReady(function(){
173 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
175 var parts = b.split('@');
176 if(parts[1]){ // for Object prototype breakers
179 cache[s] = Roo.select(s);
181 cache[s].on(parts[1], o[b]);
188 * Generates unique ids. If the element already has an id, it is unchanged
189 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
190 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
191 * @return {String} The generated Id.
193 id : function(el, prefix){
194 prefix = prefix || "roo-gen";
196 var id = prefix + (++idSeed);
197 return el ? (el.id ? el.id : (el.id = id)) : id;
202 * Extends one class with another class and optionally overrides members with the passed literal. This class
203 * also adds the function "override()" to the class that can be used to override
204 * members on an instance.
205 * @param {Object} subclass The class inheriting the functionality
206 * @param {Object} superclass The class being extended
207 * @param {Object} overrides (optional) A literal with members
212 var io = function(o){
217 return function(sb, sp, overrides){
218 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
221 sb = function(){sp.apply(this, arguments);};
223 var F = function(){}, sbp, spp = sp.prototype;
225 sbp = sb.prototype = new F();
229 if(spp.constructor == Object.prototype.constructor){
234 sb.override = function(o){
238 Roo.override(sb, overrides);
244 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
246 Roo.override(MyClass, {
247 newMethod1: function(){
250 newMethod2: function(foo){
255 * @param {Object} origclass The class to override
256 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
257 * containing one or more methods.
260 override : function(origclass, overrides){
262 var p = origclass.prototype;
263 for(var method in overrides){
264 p[method] = overrides[method];
269 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
271 Roo.namespace('Company', 'Company.data');
272 Company.Widget = function() { ... }
273 Company.data.CustomStore = function(config) { ... }
275 * @param {String} namespace1
276 * @param {String} namespace2
277 * @param {String} etc
280 namespace : function(){
281 var a=arguments, o=null, i, j, d, rt;
282 for (i=0; i<a.length; ++i) {
286 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
287 for (j=1; j<d.length; ++j) {
288 o[d[j]]=o[d[j]] || {};
294 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
296 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
297 Roo.factory(conf, Roo.data);
299 * @param {String} classname
300 * @param {String} namespace (optional)
304 factory : function(c, ns)
306 // no xtype, no ns or c.xns - or forced off by c.xns
307 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
310 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
311 if (c.constructor == ns[c.xtype]) {// already created...
315 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
316 var ret = new ns[c.xtype](c);
320 c.xns = false; // prevent recursion..
324 * Logs to console if it can.
326 * @param {String|Object} string
331 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
338 * 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.
342 urlEncode : function(o){
348 var ov = o[key], k = Roo.encodeURIComponent(key);
349 var type = typeof ov;
350 if(type == 'undefined'){
352 }else if(type != "function" && type != "object"){
353 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
354 }else if(ov instanceof Array){
356 for(var i = 0, len = ov.length; i < len; i++) {
357 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
368 * Safe version of encodeURIComponent
369 * @param {String} data
373 encodeURIComponent : function (data)
376 return encodeURIComponent(data);
377 } catch(e) {} // should be an uri encode error.
379 if (data == '' || data == null){
382 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
383 function nibble_to_hex(nibble){
384 var chars = '0123456789ABCDEF';
385 return chars.charAt(nibble);
387 data = data.toString();
389 for(var i=0; i<data.length; i++){
390 var c = data.charCodeAt(i);
391 var bs = new Array();
394 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
395 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
396 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
397 bs[3] = 0x80 | (c & 0x3F);
398 }else if (c > 0x800){
400 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
401 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
402 bs[2] = 0x80 | (c & 0x3F);
405 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
406 bs[1] = 0x80 | (c & 0x3F);
411 for(var j=0; j<bs.length; j++){
413 var hex = nibble_to_hex((b & 0xF0) >>> 4)
414 + nibble_to_hex(b &0x0F);
423 * 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]}.
424 * @param {String} string
425 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
426 * @return {Object} A literal with members
428 urlDecode : function(string, overwrite){
429 if(!string || !string.length){
433 var pairs = string.split('&');
434 var pair, name, value;
435 for(var i = 0, len = pairs.length; i < len; i++){
436 pair = pairs[i].split('=');
437 name = decodeURIComponent(pair[0]);
438 value = decodeURIComponent(pair[1]);
439 if(overwrite !== true){
440 if(typeof obj[name] == "undefined"){
442 }else if(typeof obj[name] == "string"){
443 obj[name] = [obj[name]];
444 obj[name].push(value);
446 obj[name].push(value);
456 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
457 * passed array is not really an array, your function is called once with it.
458 * The supplied function is called with (Object item, Number index, Array allItems).
459 * @param {Array/NodeList/Mixed} array
460 * @param {Function} fn
461 * @param {Object} scope
463 each : function(array, fn, scope){
464 if(typeof array.length == "undefined" || typeof array == "string"){
467 for(var i = 0, len = array.length; i < len; i++){
468 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
473 combine : function(){
474 var as = arguments, l = as.length, r = [];
475 for(var i = 0; i < l; i++){
477 if(a instanceof Array){
479 }else if(a.length !== undefined && !a.substr){
480 r = r.concat(Array.prototype.slice.call(a, 0));
489 * Escapes the passed string for use in a regular expression
490 * @param {String} str
493 escapeRe : function(s) {
494 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
498 callback : function(cb, scope, args, delay){
499 if(typeof cb == "function"){
501 cb.defer(delay, scope, args || []);
503 cb.apply(scope, args || []);
509 * Return the dom node for the passed string (id), dom node, or Roo.Element
510 * @param {String/HTMLElement/Roo.Element} el
511 * @return HTMLElement
513 getDom : function(el){
517 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
521 * Shorthand for {@link Roo.ComponentMgr#get}
523 * @return Roo.Component
525 getCmp : function(id){
526 return Roo.ComponentMgr.get(id);
529 num : function(v, defaultValue){
530 if(typeof v != 'number'){
536 destroy : function(){
537 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
541 as.removeAllListeners();
545 if(typeof as.purgeListeners == 'function'){
548 if(typeof as.destroy == 'function'){
555 // inpired by a similar function in mootools library
557 * Returns the type of object that is passed in. If the object passed in is null or undefined it
558 * return false otherwise it returns one of the following values:<ul>
559 * <li><b>string</b>: If the object passed is a string</li>
560 * <li><b>number</b>: If the object passed is a number</li>
561 * <li><b>boolean</b>: If the object passed is a boolean value</li>
562 * <li><b>function</b>: If the object passed is a function reference</li>
563 * <li><b>object</b>: If the object passed is an object</li>
564 * <li><b>array</b>: If the object passed is an array</li>
565 * <li><b>regexp</b>: If the object passed is a regular expression</li>
566 * <li><b>element</b>: If the object passed is a DOM Element</li>
567 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
568 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
569 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
570 * @param {Mixed} object
574 if(o === undefined || o === null){
581 if(t == 'object' && o.nodeName) {
583 case 1: return 'element';
584 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
587 if(t == 'object' || t == 'function') {
588 switch(o.constructor) {
589 case Array: return 'array';
590 case RegExp: return 'regexp';
592 if(typeof o.length == 'number' && typeof o.item == 'function') {
600 * Returns true if the passed value is null, undefined or an empty string (optional).
601 * @param {Mixed} value The value to test
602 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
605 isEmpty : function(v, allowBlank){
606 return v === null || v === undefined || (!allowBlank ? v === '' : false);
614 isFirefox : isFirefox,
622 isBorderBox : isBorderBox,
624 isWindows : isWindows,
633 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
634 * you may want to set this to true.
637 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
642 * Selects a single element as a Roo Element
643 * This is about as close as you can get to jQuery's $('do crazy stuff')
644 * @param {String} selector The selector/xpath query
645 * @param {Node} root (optional) The start of the query (defaults to document).
646 * @return {Roo.Element}
648 selectNode : function(selector, root)
650 var node = Roo.DomQuery.selectNode(selector,root);
651 return node ? Roo.get(node) : new Roo.Element(false);
659 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
660 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
663 "Roo.bootstrap.dash");
666 * Ext JS Library 1.1.1
667 * Copyright(c) 2006-2007, Ext JS, LLC.
669 * Originally Released Under LGPL - original licence link has changed is not relivant.
672 * <script type="text/javascript">
676 // wrappedn so fnCleanup is not in global scope...
678 function fnCleanUp() {
679 var p = Function.prototype;
680 delete p.createSequence;
682 delete p.createDelegate;
683 delete p.createCallback;
684 delete p.createInterceptor;
686 window.detachEvent("onunload", fnCleanUp);
688 window.attachEvent("onunload", fnCleanUp);
695 * These functions are available on every Function object (any JavaScript function).
697 Roo.apply(Function.prototype, {
699 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
700 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
701 * Will create a function that is bound to those 2 args.
702 * @return {Function} The new function
704 createCallback : function(/*args...*/){
705 // make args available, in function below
706 var args = arguments;
709 return method.apply(window, args);
714 * Creates a delegate (callback) that sets the scope to obj.
715 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
716 * Will create a function that is automatically scoped to this.
717 * @param {Object} obj (optional) The object for which the scope is set
718 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
719 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
720 * if a number the args are inserted at the specified position
721 * @return {Function} The new function
723 createDelegate : function(obj, args, appendArgs){
726 var callArgs = args || arguments;
727 if(appendArgs === true){
728 callArgs = Array.prototype.slice.call(arguments, 0);
729 callArgs = callArgs.concat(args);
730 }else if(typeof appendArgs == "number"){
731 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
732 var applyArgs = [appendArgs, 0].concat(args); // create method call params
733 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
735 return method.apply(obj || window, callArgs);
740 * Calls this function after the number of millseconds specified.
741 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
742 * @param {Object} obj (optional) The object for which the scope is set
743 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
744 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
745 * if a number the args are inserted at the specified position
746 * @return {Number} The timeout id that can be used with clearTimeout
748 defer : function(millis, obj, args, appendArgs){
749 var fn = this.createDelegate(obj, args, appendArgs);
751 return setTimeout(fn, millis);
757 * Create a combined function call sequence of the original function + the passed function.
758 * The resulting function returns the results of the original function.
759 * The passed fcn is called with the parameters of the original function
760 * @param {Function} fcn The function to sequence
761 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
762 * @return {Function} The new function
764 createSequence : function(fcn, scope){
765 if(typeof fcn != "function"){
770 var retval = method.apply(this || window, arguments);
771 fcn.apply(scope || this || window, arguments);
777 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
778 * The resulting function returns the results of the original function.
779 * The passed fcn is called with the parameters of the original function.
781 * @param {Function} fcn The function to call before the original
782 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
783 * @return {Function} The new function
785 createInterceptor : function(fcn, scope){
786 if(typeof fcn != "function"){
793 if(fcn.apply(scope || this || window, arguments) === false){
796 return method.apply(this || window, arguments);
802 * Ext JS Library 1.1.1
803 * Copyright(c) 2006-2007, Ext JS, LLC.
805 * Originally Released Under LGPL - original licence link has changed is not relivant.
808 * <script type="text/javascript">
811 Roo.applyIf(String, {
816 * Escapes the passed string for ' and \
817 * @param {String} string The string to escape
818 * @return {String} The escaped string
821 escape : function(string) {
822 return string.replace(/('|\\)/g, "\\$1");
826 * Pads the left side of a string with a specified character. This is especially useful
827 * for normalizing number and date strings. Example usage:
829 var s = String.leftPad('123', 5, '0');
830 // s now contains the string: '00123'
832 * @param {String} string The original string
833 * @param {Number} size The total length of the output string
834 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
835 * @return {String} The padded string
838 leftPad : function (val, size, ch) {
839 var result = new String(val);
840 if(ch === null || ch === undefined || ch === '') {
843 while (result.length < size) {
844 result = ch + result;
850 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
851 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
853 var cls = 'my-class', text = 'Some text';
854 var s = String.format('<div class="{0}">{1}</div>', cls, text);
855 // s now contains the string: '<div class="my-class">Some text</div>'
857 * @param {String} string The tokenized string to be formatted
858 * @param {String} value1 The value to replace token {0}
859 * @param {String} value2 Etc...
860 * @return {String} The formatted string
863 format : function(format){
864 var args = Array.prototype.slice.call(arguments, 1);
865 return format.replace(/\{(\d+)\}/g, function(m, i){
866 return Roo.util.Format.htmlEncode(args[i]);
872 * Utility function that allows you to easily switch a string between two alternating values. The passed value
873 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
874 * they are already different, the first value passed in is returned. Note that this method returns the new value
875 * but does not change the current string.
877 // alternate sort directions
878 sort = sort.toggle('ASC', 'DESC');
880 // instead of conditional logic:
881 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
883 * @param {String} value The value to compare to the current string
884 * @param {String} other The new value to use if the string already equals the first value passed in
885 * @return {String} The new value
888 String.prototype.toggle = function(value, other){
889 return this == value ? other : value;
892 * Ext JS Library 1.1.1
893 * Copyright(c) 2006-2007, Ext JS, LLC.
895 * Originally Released Under LGPL - original licence link has changed is not relivant.
898 * <script type="text/javascript">
904 Roo.applyIf(Number.prototype, {
906 * Checks whether or not the current number is within a desired range. If the number is already within the
907 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
908 * exceeded. Note that this method returns the constrained value but does not change the current number.
909 * @param {Number} min The minimum number in the range
910 * @param {Number} max The maximum number in the range
911 * @return {Number} The constrained value if outside the range, otherwise the current value
913 constrain : function(min, max){
914 return Math.min(Math.max(this, min), max);
918 * Ext JS Library 1.1.1
919 * Copyright(c) 2006-2007, Ext JS, LLC.
921 * Originally Released Under LGPL - original licence link has changed is not relivant.
924 * <script type="text/javascript">
929 Roo.applyIf(Array.prototype, {
932 * Checks whether or not the specified object exists in the array.
933 * @param {Object} o The object to check for
934 * @return {Number} The index of o in the array (or -1 if it is not found)
936 indexOf : function(o){
937 for (var i = 0, len = this.length; i < len; i++){
938 if(this[i] == o) return i;
944 * Removes the specified object from the array. If the object is not found nothing happens.
945 * @param {Object} o The object to remove
947 remove : function(o){
948 var index = this.indexOf(o);
950 this.splice(index, 1);
954 * Map (JS 1.6 compatibility)
955 * @param {Function} function to call
959 var len = this.length >>> 0;
960 if (typeof fun != "function")
961 throw new TypeError();
963 var res = new Array(len);
964 var thisp = arguments[1];
965 for (var i = 0; i < len; i++)
968 res[i] = fun.call(thisp, this[i], i, this);
979 * Ext JS Library 1.1.1
980 * Copyright(c) 2006-2007, Ext JS, LLC.
982 * Originally Released Under LGPL - original licence link has changed is not relivant.
985 * <script type="text/javascript">
991 * The date parsing and format syntax is a subset of
992 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
993 * supported will provide results equivalent to their PHP versions.
995 * Following is the list of all currently supported formats:
998 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1000 Format Output Description
1001 ------ ---------- --------------------------------------------------------------
1002 d 10 Day of the month, 2 digits with leading zeros
1003 D Wed A textual representation of a day, three letters
1004 j 10 Day of the month without leading zeros
1005 l Wednesday A full textual representation of the day of the week
1006 S th English ordinal day of month suffix, 2 chars (use with j)
1007 w 3 Numeric representation of the day of the week
1008 z 9 The julian date, or day of the year (0-365)
1009 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1010 F January A full textual representation of the month
1011 m 01 Numeric representation of a month, with leading zeros
1012 M Jan Month name abbreviation, three letters
1013 n 1 Numeric representation of a month, without leading zeros
1014 t 31 Number of days in the given month
1015 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1016 Y 2007 A full numeric representation of a year, 4 digits
1017 y 07 A two digit representation of a year
1018 a pm Lowercase Ante meridiem and Post meridiem
1019 A PM Uppercase Ante meridiem and Post meridiem
1020 g 3 12-hour format of an hour without leading zeros
1021 G 15 24-hour format of an hour without leading zeros
1022 h 03 12-hour format of an hour with leading zeros
1023 H 15 24-hour format of an hour with leading zeros
1024 i 05 Minutes with leading zeros
1025 s 01 Seconds, with leading zeros
1026 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1027 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1028 T CST Timezone setting of the machine running the code
1029 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1032 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1034 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1035 document.write(dt.format('Y-m-d')); //2007-01-10
1036 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1037 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
1040 * Here are some standard date/time patterns that you might find helpful. They
1041 * are not part of the source of Date.js, but to use them you can simply copy this
1042 * block of code into any script that is included after Date.js and they will also become
1043 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1046 ISO8601Long:"Y-m-d H:i:s",
1047 ISO8601Short:"Y-m-d",
1049 LongDate: "l, F d, Y",
1050 FullDateTime: "l, F d, Y g:i:s A",
1053 LongTime: "g:i:s A",
1054 SortableDateTime: "Y-m-d\\TH:i:s",
1055 UniversalSortableDateTime: "Y-m-d H:i:sO",
1062 var dt = new Date();
1063 document.write(dt.format(Date.patterns.ShortDate));
1068 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1069 * They generate precompiled functions from date formats instead of parsing and
1070 * processing the pattern every time you format a date. These functions are available
1071 * on every Date object (any javascript function).
1073 * The original article and download are here:
1074 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1081 Returns the number of milliseconds between this date and date
1082 @param {Date} date (optional) Defaults to now
1083 @return {Number} The diff in milliseconds
1084 @member Date getElapsed
1086 Date.prototype.getElapsed = function(date) {
1087 return Math.abs((date || new Date()).getTime()-this.getTime());
1089 // was in date file..
1093 Date.parseFunctions = {count:0};
1095 Date.parseRegexes = [];
1097 Date.formatFunctions = {count:0};
1100 Date.prototype.dateFormat = function(format) {
1101 if (Date.formatFunctions[format] == null) {
1102 Date.createNewFormat(format);
1104 var func = Date.formatFunctions[format];
1105 return this[func]();
1110 * Formats a date given the supplied format string
1111 * @param {String} format The format string
1112 * @return {String} The formatted date
1115 Date.prototype.format = Date.prototype.dateFormat;
1118 Date.createNewFormat = function(format) {
1119 var funcName = "format" + Date.formatFunctions.count++;
1120 Date.formatFunctions[format] = funcName;
1121 var code = "Date.prototype." + funcName + " = function(){return ";
1122 var special = false;
1124 for (var i = 0; i < format.length; ++i) {
1125 ch = format.charAt(i);
1126 if (!special && ch == "\\") {
1131 code += "'" + String.escape(ch) + "' + ";
1134 code += Date.getFormatCode(ch);
1137 /** eval:var:zzzzzzzzzzzzz */
1138 eval(code.substring(0, code.length - 3) + ";}");
1142 Date.getFormatCode = function(character) {
1143 switch (character) {
1145 return "String.leftPad(this.getDate(), 2, '0') + ";
1147 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1149 return "this.getDate() + ";
1151 return "Date.dayNames[this.getDay()] + ";
1153 return "this.getSuffix() + ";
1155 return "this.getDay() + ";
1157 return "this.getDayOfYear() + ";
1159 return "this.getWeekOfYear() + ";
1161 return "Date.monthNames[this.getMonth()] + ";
1163 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1165 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1167 return "(this.getMonth() + 1) + ";
1169 return "this.getDaysInMonth() + ";
1171 return "(this.isLeapYear() ? 1 : 0) + ";
1173 return "this.getFullYear() + ";
1175 return "('' + this.getFullYear()).substring(2, 4) + ";
1177 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1179 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1181 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1183 return "this.getHours() + ";
1185 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1187 return "String.leftPad(this.getHours(), 2, '0') + ";
1189 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1191 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1193 return "this.getGMTOffset() + ";
1195 return "this.getGMTColonOffset() + ";
1197 return "this.getTimezone() + ";
1199 return "(this.getTimezoneOffset() * -60) + ";
1201 return "'" + String.escape(character) + "' + ";
1206 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1207 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1208 * the date format that is not specified will default to the current date value for that part. Time parts can also
1209 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1210 * string or the parse operation will fail.
1213 //dt = Fri May 25 2007 (current date)
1214 var dt = new Date();
1216 //dt = Thu May 25 2006 (today's month/day in 2006)
1217 dt = Date.parseDate("2006", "Y");
1219 //dt = Sun Jan 15 2006 (all date parts specified)
1220 dt = Date.parseDate("2006-1-15", "Y-m-d");
1222 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1223 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1225 * @param {String} input The unparsed date as a string
1226 * @param {String} format The format the date is in
1227 * @return {Date} The parsed date
1230 Date.parseDate = function(input, format) {
1231 if (Date.parseFunctions[format] == null) {
1232 Date.createParser(format);
1234 var func = Date.parseFunctions[format];
1235 return Date[func](input);
1241 Date.createParser = function(format) {
1242 var funcName = "parse" + Date.parseFunctions.count++;
1243 var regexNum = Date.parseRegexes.length;
1244 var currentGroup = 1;
1245 Date.parseFunctions[format] = funcName;
1247 var code = "Date." + funcName + " = function(input){\n"
1248 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1249 + "var d = new Date();\n"
1250 + "y = d.getFullYear();\n"
1251 + "m = d.getMonth();\n"
1252 + "d = d.getDate();\n"
1253 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1254 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1255 + "if (results && results.length > 0) {";
1258 var special = false;
1260 for (var i = 0; i < format.length; ++i) {
1261 ch = format.charAt(i);
1262 if (!special && ch == "\\") {
1267 regex += String.escape(ch);
1270 var obj = Date.formatCodeToRegex(ch, currentGroup);
1271 currentGroup += obj.g;
1273 if (obj.g && obj.c) {
1279 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1280 + "{v = new Date(y, m, d, h, i, s);}\n"
1281 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1282 + "{v = new Date(y, m, d, h, i);}\n"
1283 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1284 + "{v = new Date(y, m, d, h);}\n"
1285 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1286 + "{v = new Date(y, m, d);}\n"
1287 + "else if (y >= 0 && m >= 0)\n"
1288 + "{v = new Date(y, m);}\n"
1289 + "else if (y >= 0)\n"
1290 + "{v = new Date(y);}\n"
1291 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1292 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1293 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1296 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1297 /** eval:var:zzzzzzzzzzzzz */
1302 Date.formatCodeToRegex = function(character, currentGroup) {
1303 switch (character) {
1307 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1310 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1311 s:"(\\d{1,2})"}; // day of month without leading zeroes
1314 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1315 s:"(\\d{2})"}; // day of month with leading zeroes
1319 s:"(?:" + Date.dayNames.join("|") + ")"};
1323 s:"(?:st|nd|rd|th)"};
1338 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1339 s:"(" + Date.monthNames.join("|") + ")"};
1342 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1343 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1346 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1347 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1350 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1351 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1362 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1366 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1367 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1371 c:"if (results[" + currentGroup + "] == 'am') {\n"
1372 + "if (h == 12) { h = 0; }\n"
1373 + "} else { if (h < 12) { h += 12; }}",
1377 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1378 + "if (h == 12) { h = 0; }\n"
1379 + "} else { if (h < 12) { h += 12; }}",
1384 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1385 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1389 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1390 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1393 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1397 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1402 "o = results[", currentGroup, "];\n",
1403 "var sn = o.substring(0,1);\n", // get + / - sign
1404 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1405 "var mn = o.substring(3,5) % 60;\n", // get minutes
1406 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1407 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"([+\-]\\d{2,4})"};
1415 "o = results[", currentGroup, "];\n",
1416 "var sn = o.substring(0,1);\n",
1417 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1418 "var mn = o.substring(4,6) % 60;\n",
1419 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1420 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1426 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1429 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1430 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1431 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1435 s:String.escape(character)};
1440 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1441 * @return {String} The abbreviated timezone name (e.g. 'CST')
1443 Date.prototype.getTimezone = function() {
1444 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1448 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1449 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1451 Date.prototype.getGMTOffset = function() {
1452 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1453 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1454 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1458 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1459 * @return {String} 2-characters representing hours and 2-characters representing minutes
1460 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1462 Date.prototype.getGMTColonOffset = function() {
1463 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1464 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1466 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1470 * Get the numeric day number of the year, adjusted for leap year.
1471 * @return {Number} 0 through 364 (365 in leap years)
1473 Date.prototype.getDayOfYear = function() {
1475 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1476 for (var i = 0; i < this.getMonth(); ++i) {
1477 num += Date.daysInMonth[i];
1479 return num + this.getDate() - 1;
1483 * Get the string representation of the numeric week number of the year
1484 * (equivalent to the format specifier 'W').
1485 * @return {String} '00' through '52'
1487 Date.prototype.getWeekOfYear = function() {
1488 // Skip to Thursday of this week
1489 var now = this.getDayOfYear() + (4 - this.getDay());
1490 // Find the first Thursday of the year
1491 var jan1 = new Date(this.getFullYear(), 0, 1);
1492 var then = (7 - jan1.getDay() + 4);
1493 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1497 * Whether or not the current date is in a leap year.
1498 * @return {Boolean} True if the current date is in a leap year, else false
1500 Date.prototype.isLeapYear = function() {
1501 var year = this.getFullYear();
1502 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1506 * Get the first day of the current month, adjusted for leap year. The returned value
1507 * is the numeric day index within the week (0-6) which can be used in conjunction with
1508 * the {@link #monthNames} array to retrieve the textual day name.
1511 var dt = new Date('1/10/2007');
1512 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1514 * @return {Number} The day number (0-6)
1516 Date.prototype.getFirstDayOfMonth = function() {
1517 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1518 return (day < 0) ? (day + 7) : day;
1522 * Get the last day of the current month, adjusted for leap year. The returned value
1523 * is the numeric day index within the week (0-6) which can be used in conjunction with
1524 * the {@link #monthNames} array to retrieve the textual day name.
1527 var dt = new Date('1/10/2007');
1528 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1530 * @return {Number} The day number (0-6)
1532 Date.prototype.getLastDayOfMonth = function() {
1533 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1534 return (day < 0) ? (day + 7) : day;
1539 * Get the first date of this date's month
1542 Date.prototype.getFirstDateOfMonth = function() {
1543 return new Date(this.getFullYear(), this.getMonth(), 1);
1547 * Get the last date of this date's month
1550 Date.prototype.getLastDateOfMonth = function() {
1551 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1554 * Get the number of days in the current month, adjusted for leap year.
1555 * @return {Number} The number of days in the month
1557 Date.prototype.getDaysInMonth = function() {
1558 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1559 return Date.daysInMonth[this.getMonth()];
1563 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1564 * @return {String} 'st, 'nd', 'rd' or 'th'
1566 Date.prototype.getSuffix = function() {
1567 switch (this.getDate()) {
1584 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1587 * An array of textual month names.
1588 * Override these values for international dates, for example...
1589 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1608 * An array of textual day names.
1609 * Override these values for international dates, for example...
1610 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1626 Date.monthNumbers = {
1641 * Creates and returns a new Date instance with the exact same date value as the called instance.
1642 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1643 * variable will also be changed. When the intention is to create a new variable that will not
1644 * modify the original instance, you should create a clone.
1646 * Example of correctly cloning a date:
1649 var orig = new Date('10/1/2006');
1652 document.write(orig); //returns 'Thu Oct 05 2006'!
1655 var orig = new Date('10/1/2006');
1656 var copy = orig.clone();
1658 document.write(orig); //returns 'Thu Oct 01 2006'
1660 * @return {Date} The new Date instance
1662 Date.prototype.clone = function() {
1663 return new Date(this.getTime());
1667 * Clears any time information from this date
1668 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1669 @return {Date} this or the clone
1671 Date.prototype.clearTime = function(clone){
1673 return this.clone().clearTime();
1678 this.setMilliseconds(0);
1683 // safari setMonth is broken
1685 Date.brokenSetMonth = Date.prototype.setMonth;
1686 Date.prototype.setMonth = function(num){
1688 var n = Math.ceil(-num);
1689 var back_year = Math.ceil(n/12);
1690 var month = (n % 12) ? 12 - n % 12 : 0 ;
1691 this.setFullYear(this.getFullYear() - back_year);
1692 return Date.brokenSetMonth.call(this, month);
1694 return Date.brokenSetMonth.apply(this, arguments);
1699 /** Date interval constant
1703 /** Date interval constant
1707 /** Date interval constant
1711 /** Date interval constant
1715 /** Date interval constant
1719 /** Date interval constant
1723 /** Date interval constant
1729 * Provides a convenient method of performing basic date arithmetic. This method
1730 * does not modify the Date instance being called - it creates and returns
1731 * a new Date instance containing the resulting date value.
1736 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1737 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1739 //Negative values will subtract correctly:
1740 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1741 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1743 //You can even chain several calls together in one line!
1744 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1745 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1748 * @param {String} interval A valid date interval enum value
1749 * @param {Number} value The amount to add to the current date
1750 * @return {Date} The new Date instance
1752 Date.prototype.add = function(interval, value){
1753 var d = this.clone();
1754 if (!interval || value === 0) return d;
1755 switch(interval.toLowerCase()){
1757 d.setMilliseconds(this.getMilliseconds() + value);
1760 d.setSeconds(this.getSeconds() + value);
1763 d.setMinutes(this.getMinutes() + value);
1766 d.setHours(this.getHours() + value);
1769 d.setDate(this.getDate() + value);
1772 var day = this.getDate();
1774 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1777 d.setMonth(this.getMonth() + value);
1780 d.setFullYear(this.getFullYear() + value);
1787 * Ext JS Library 1.1.1
1788 * Copyright(c) 2006-2007, Ext JS, LLC.
1790 * Originally Released Under LGPL - original licence link has changed is not relivant.
1793 * <script type="text/javascript">
1797 * @class Roo.lib.Dom
1800 * Dom utils (from YIU afaik)
1805 * Get the view width
1806 * @param {Boolean} full True will get the full document, otherwise it's the view width
1807 * @return {Number} The width
1810 getViewWidth : function(full) {
1811 return full ? this.getDocumentWidth() : this.getViewportWidth();
1814 * Get the view height
1815 * @param {Boolean} full True will get the full document, otherwise it's the view height
1816 * @return {Number} The height
1818 getViewHeight : function(full) {
1819 return full ? this.getDocumentHeight() : this.getViewportHeight();
1822 getDocumentHeight: function() {
1823 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1824 return Math.max(scrollHeight, this.getViewportHeight());
1827 getDocumentWidth: function() {
1828 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1829 return Math.max(scrollWidth, this.getViewportWidth());
1832 getViewportHeight: function() {
1833 var height = self.innerHeight;
1834 var mode = document.compatMode;
1836 if ((mode || Roo.isIE) && !Roo.isOpera) {
1837 height = (mode == "CSS1Compat") ?
1838 document.documentElement.clientHeight :
1839 document.body.clientHeight;
1845 getViewportWidth: function() {
1846 var width = self.innerWidth;
1847 var mode = document.compatMode;
1849 if (mode || Roo.isIE) {
1850 width = (mode == "CSS1Compat") ?
1851 document.documentElement.clientWidth :
1852 document.body.clientWidth;
1857 isAncestor : function(p, c) {
1864 if (p.contains && !Roo.isSafari) {
1865 return p.contains(c);
1866 } else if (p.compareDocumentPosition) {
1867 return !!(p.compareDocumentPosition(c) & 16);
1869 var parent = c.parentNode;
1874 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1877 parent = parent.parentNode;
1883 getRegion : function(el) {
1884 return Roo.lib.Region.getRegion(el);
1887 getY : function(el) {
1888 return this.getXY(el)[1];
1891 getX : function(el) {
1892 return this.getXY(el)[0];
1895 getXY : function(el) {
1896 var p, pe, b, scroll, bd = document.body;
1897 el = Roo.getDom(el);
1898 var fly = Roo.lib.AnimBase.fly;
1899 if (el.getBoundingClientRect) {
1900 b = el.getBoundingClientRect();
1901 scroll = fly(document).getScroll();
1902 return [b.left + scroll.left, b.top + scroll.top];
1908 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1915 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1922 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1923 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1930 if (p != el && pe.getStyle('overflow') != 'visible') {
1938 if (Roo.isSafari && hasAbsolute) {
1943 if (Roo.isGecko && !hasAbsolute) {
1945 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1946 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1950 while (p && p != bd) {
1951 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1963 setXY : function(el, xy) {
1964 el = Roo.fly(el, '_setXY');
1966 var pts = el.translatePoints(xy);
1967 if (xy[0] !== false) {
1968 el.dom.style.left = pts.left + "px";
1970 if (xy[1] !== false) {
1971 el.dom.style.top = pts.top + "px";
1975 setX : function(el, x) {
1976 this.setXY(el, [x, false]);
1979 setY : function(el, y) {
1980 this.setXY(el, [false, y]);
1984 * Portions of this file are based on pieces of Yahoo User Interface Library
1985 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1986 * YUI licensed under the BSD License:
1987 * http://developer.yahoo.net/yui/license.txt
1988 * <script type="text/javascript">
1992 Roo.lib.Event = function() {
1993 var loadComplete = false;
1995 var unloadListeners = [];
1997 var onAvailStack = [];
1999 var lastError = null;
2012 startInterval: function() {
2013 if (!this._interval) {
2015 var callback = function() {
2016 self._tryPreloadAttach();
2018 this._interval = setInterval(callback, this.POLL_INTERVAL);
2023 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2024 onAvailStack.push({ id: p_id,
2027 override: p_override,
2028 checkReady: false });
2030 retryCount = this.POLL_RETRYS;
2031 this.startInterval();
2035 addListener: function(el, eventName, fn) {
2036 el = Roo.getDom(el);
2041 if ("unload" == eventName) {
2042 unloadListeners[unloadListeners.length] =
2043 [el, eventName, fn];
2047 var wrappedFn = function(e) {
2048 return fn(Roo.lib.Event.getEvent(e));
2051 var li = [el, eventName, fn, wrappedFn];
2053 var index = listeners.length;
2054 listeners[index] = li;
2056 this.doAdd(el, eventName, wrappedFn, false);
2062 removeListener: function(el, eventName, fn) {
2065 el = Roo.getDom(el);
2068 return this.purgeElement(el, false, eventName);
2072 if ("unload" == eventName) {
2074 for (i = 0,len = unloadListeners.length; i < len; i++) {
2075 var li = unloadListeners[i];
2078 li[1] == eventName &&
2080 unloadListeners.splice(i, 1);
2088 var cacheItem = null;
2091 var index = arguments[3];
2093 if ("undefined" == typeof index) {
2094 index = this._getCacheIndex(el, eventName, fn);
2098 cacheItem = listeners[index];
2101 if (!el || !cacheItem) {
2105 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2107 delete listeners[index][this.WFN];
2108 delete listeners[index][this.FN];
2109 listeners.splice(index, 1);
2116 getTarget: function(ev, resolveTextNode) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2119 var t = ev.target || ev.srcElement;
2120 return this.resolveTextNode(t);
2124 resolveTextNode: function(node) {
2125 if (Roo.isSafari && node && 3 == node.nodeType) {
2126 return node.parentNode;
2133 getPageX: function(ev) {
2134 ev = ev.browserEvent || ev;
2135 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2137 if (!x && 0 !== x) {
2138 x = ev.clientX || 0;
2141 x += this.getScroll()[1];
2149 getPageY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2153 if (!y && 0 !== y) {
2154 y = ev.clientY || 0;
2157 y += this.getScroll()[0];
2166 getXY: function(ev) {
2167 ev = ev.browserEvent || ev;
2168 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2169 return [this.getPageX(ev), this.getPageY(ev)];
2173 getRelatedTarget: function(ev) {
2174 ev = ev.browserEvent || ev;
2175 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = ev.relatedTarget;
2178 if (ev.type == "mouseout") {
2180 } else if (ev.type == "mouseover") {
2185 return this.resolveTextNode(t);
2189 getTime: function(ev) {
2190 ev = ev.browserEvent || ev;
2191 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2193 var t = new Date().getTime();
2197 this.lastError = ex;
2206 stopEvent: function(ev) {
2207 this.stopPropagation(ev);
2208 this.preventDefault(ev);
2212 stopPropagation: function(ev) {
2213 ev = ev.browserEvent || ev;
2214 if (ev.stopPropagation) {
2215 ev.stopPropagation();
2217 ev.cancelBubble = true;
2222 preventDefault: function(ev) {
2223 ev = ev.browserEvent || ev;
2224 if(ev.preventDefault) {
2225 ev.preventDefault();
2227 ev.returnValue = false;
2232 getEvent: function(e) {
2233 var ev = e || window.event;
2235 var c = this.getEvent.caller;
2237 ev = c.arguments[0];
2238 if (ev && Event == ev.constructor) {
2248 getCharCode: function(ev) {
2249 ev = ev.browserEvent || ev;
2250 return ev.charCode || ev.keyCode || 0;
2254 _getCacheIndex: function(el, eventName, fn) {
2255 for (var i = 0,len = listeners.length; i < len; ++i) {
2256 var li = listeners[i];
2258 li[this.FN] == fn &&
2259 li[this.EL] == el &&
2260 li[this.TYPE] == eventName) {
2272 getEl: function(id) {
2273 return document.getElementById(id);
2277 clearCache: function() {
2281 _load: function(e) {
2282 loadComplete = true;
2283 var EU = Roo.lib.Event;
2287 EU.doRemove(window, "load", EU._load);
2292 _tryPreloadAttach: function() {
2301 var tryAgain = !loadComplete;
2303 tryAgain = (retryCount > 0);
2308 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2309 var item = onAvailStack[i];
2311 var el = this.getEl(item.id);
2314 if (!item.checkReady ||
2317 (document && document.body)) {
2320 if (item.override) {
2321 if (item.override === true) {
2324 scope = item.override;
2327 item.fn.call(scope, item.obj);
2328 onAvailStack[i] = null;
2331 notAvail.push(item);
2336 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2340 this.startInterval();
2342 clearInterval(this._interval);
2343 this._interval = null;
2346 this.locked = false;
2353 purgeElement: function(el, recurse, eventName) {
2354 var elListeners = this.getListeners(el, eventName);
2356 for (var i = 0,len = elListeners.length; i < len; ++i) {
2357 var l = elListeners[i];
2358 this.removeListener(el, l.type, l.fn);
2362 if (recurse && el && el.childNodes) {
2363 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2364 this.purgeElement(el.childNodes[i], recurse, eventName);
2370 getListeners: function(el, eventName) {
2371 var results = [], searchLists;
2373 searchLists = [listeners, unloadListeners];
2374 } else if (eventName == "unload") {
2375 searchLists = [unloadListeners];
2377 searchLists = [listeners];
2380 for (var j = 0; j < searchLists.length; ++j) {
2381 var searchList = searchLists[j];
2382 if (searchList && searchList.length > 0) {
2383 for (var i = 0,len = searchList.length; i < len; ++i) {
2384 var l = searchList[i];
2385 if (l && l[this.EL] === el &&
2386 (!eventName || eventName === l[this.TYPE])) {
2391 adjust: l[this.ADJ_SCOPE],
2399 return (results.length) ? results : null;
2403 _unload: function(e) {
2405 var EU = Roo.lib.Event, i, j, l, len, index;
2407 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2408 l = unloadListeners[i];
2411 if (l[EU.ADJ_SCOPE]) {
2412 if (l[EU.ADJ_SCOPE] === true) {
2415 scope = l[EU.ADJ_SCOPE];
2418 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2419 unloadListeners[i] = null;
2425 unloadListeners = null;
2427 if (listeners && listeners.length > 0) {
2428 j = listeners.length;
2431 l = listeners[index];
2433 EU.removeListener(l[EU.EL], l[EU.TYPE],
2443 EU.doRemove(window, "unload", EU._unload);
2448 getScroll: function() {
2449 var dd = document.documentElement, db = document.body;
2450 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2451 return [dd.scrollTop, dd.scrollLeft];
2453 return [db.scrollTop, db.scrollLeft];
2460 doAdd: function () {
2461 if (window.addEventListener) {
2462 return function(el, eventName, fn, capture) {
2463 el.addEventListener(eventName, fn, (capture));
2465 } else if (window.attachEvent) {
2466 return function(el, eventName, fn, capture) {
2467 el.attachEvent("on" + eventName, fn);
2476 doRemove: function() {
2477 if (window.removeEventListener) {
2478 return function (el, eventName, fn, capture) {
2479 el.removeEventListener(eventName, fn, (capture));
2481 } else if (window.detachEvent) {
2482 return function (el, eventName, fn) {
2483 el.detachEvent("on" + eventName, fn);
2495 var E = Roo.lib.Event;
2496 E.on = E.addListener;
2497 E.un = E.removeListener;
2499 if (document && document.body) {
2502 E.doAdd(window, "load", E._load);
2504 E.doAdd(window, "unload", E._unload);
2505 E._tryPreloadAttach();
2509 * Portions of this file are based on pieces of Yahoo User Interface Library
2510 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2511 * YUI licensed under the BSD License:
2512 * http://developer.yahoo.net/yui/license.txt
2513 * <script type="text/javascript">
2519 * @class Roo.lib.Ajax
2526 request : function(method, uri, cb, data, options) {
2528 var hs = options.headers;
2531 if(hs.hasOwnProperty(h)){
2532 this.initHeader(h, hs[h], false);
2536 if(options.xmlData){
2537 this.initHeader('Content-Type', 'text/xml', false);
2539 data = options.xmlData;
2543 return this.asyncRequest(method, uri, cb, data);
2546 serializeForm : function(form) {
2547 if(typeof form == 'string') {
2548 form = (document.getElementById(form) || document.forms[form]);
2551 var el, name, val, disabled, data = '', hasSubmit = false;
2552 for (var i = 0; i < form.elements.length; i++) {
2553 el = form.elements[i];
2554 disabled = form.elements[i].disabled;
2555 name = form.elements[i].name;
2556 val = form.elements[i].value;
2558 if (!disabled && name){
2562 case 'select-multiple':
2563 for (var j = 0; j < el.options.length; j++) {
2564 if (el.options[j].selected) {
2566 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2569 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2577 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2590 if(hasSubmit == false) {
2591 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2601 data = data.substr(0, data.length - 1);
2609 useDefaultHeader:true,
2611 defaultPostHeader:'application/x-www-form-urlencoded',
2613 useDefaultXhrHeader:true,
2615 defaultXhrHeader:'XMLHttpRequest',
2617 hasDefaultHeaders:true,
2629 setProgId:function(id)
2631 this.activeX.unshift(id);
2634 setDefaultPostHeader:function(b)
2636 this.useDefaultHeader = b;
2639 setDefaultXhrHeader:function(b)
2641 this.useDefaultXhrHeader = b;
2644 setPollingInterval:function(i)
2646 if (typeof i == 'number' && isFinite(i)) {
2647 this.pollInterval = i;
2651 createXhrObject:function(transactionId)
2657 http = new XMLHttpRequest();
2659 obj = { conn:http, tId:transactionId };
2663 for (var i = 0; i < this.activeX.length; ++i) {
2667 http = new ActiveXObject(this.activeX[i]);
2669 obj = { conn:http, tId:transactionId };
2682 getConnectionObject:function()
2685 var tId = this.transactionId;
2689 o = this.createXhrObject(tId);
2691 this.transactionId++;
2702 asyncRequest:function(method, uri, callback, postData)
2704 var o = this.getConnectionObject();
2710 o.conn.open(method, uri, true);
2712 if (this.useDefaultXhrHeader) {
2713 if (!this.defaultHeaders['X-Requested-With']) {
2714 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2718 if(postData && this.useDefaultHeader){
2719 this.initHeader('Content-Type', this.defaultPostHeader);
2722 if (this.hasDefaultHeaders || this.hasHeaders) {
2726 this.handleReadyState(o, callback);
2727 o.conn.send(postData || null);
2733 handleReadyState:function(o, callback)
2737 if (callback && callback.timeout) {
2739 this.timeout[o.tId] = window.setTimeout(function() {
2740 oConn.abort(o, callback, true);
2741 }, callback.timeout);
2744 this.poll[o.tId] = window.setInterval(
2746 if (o.conn && o.conn.readyState == 4) {
2747 window.clearInterval(oConn.poll[o.tId]);
2748 delete oConn.poll[o.tId];
2750 if(callback && callback.timeout) {
2751 window.clearTimeout(oConn.timeout[o.tId]);
2752 delete oConn.timeout[o.tId];
2755 oConn.handleTransactionResponse(o, callback);
2758 , this.pollInterval);
2761 handleTransactionResponse:function(o, callback, isAbort)
2765 this.releaseObject(o);
2769 var httpStatus, responseObject;
2773 if (o.conn.status !== undefined && o.conn.status != 0) {
2774 httpStatus = o.conn.status;
2786 if (httpStatus >= 200 && httpStatus < 300) {
2787 responseObject = this.createResponseObject(o, callback.argument);
2788 if (callback.success) {
2789 if (!callback.scope) {
2790 callback.success(responseObject);
2795 callback.success.apply(callback.scope, [responseObject]);
2800 switch (httpStatus) {
2808 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2809 if (callback.failure) {
2810 if (!callback.scope) {
2811 callback.failure(responseObject);
2814 callback.failure.apply(callback.scope, [responseObject]);
2819 responseObject = this.createResponseObject(o, callback.argument);
2820 if (callback.failure) {
2821 if (!callback.scope) {
2822 callback.failure(responseObject);
2825 callback.failure.apply(callback.scope, [responseObject]);
2831 this.releaseObject(o);
2832 responseObject = null;
2835 createResponseObject:function(o, callbackArg)
2842 var headerStr = o.conn.getAllResponseHeaders();
2843 var header = headerStr.split('\n');
2844 for (var i = 0; i < header.length; i++) {
2845 var delimitPos = header[i].indexOf(':');
2846 if (delimitPos != -1) {
2847 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2855 obj.status = o.conn.status;
2856 obj.statusText = o.conn.statusText;
2857 obj.getResponseHeader = headerObj;
2858 obj.getAllResponseHeaders = headerStr;
2859 obj.responseText = o.conn.responseText;
2860 obj.responseXML = o.conn.responseXML;
2862 if (typeof callbackArg !== undefined) {
2863 obj.argument = callbackArg;
2869 createExceptionObject:function(tId, callbackArg, isAbort)
2872 var COMM_ERROR = 'communication failure';
2873 var ABORT_CODE = -1;
2874 var ABORT_ERROR = 'transaction aborted';
2880 obj.status = ABORT_CODE;
2881 obj.statusText = ABORT_ERROR;
2884 obj.status = COMM_CODE;
2885 obj.statusText = COMM_ERROR;
2889 obj.argument = callbackArg;
2895 initHeader:function(label, value, isDefault)
2897 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2899 if (headerObj[label] === undefined) {
2900 headerObj[label] = value;
2905 headerObj[label] = value + "," + headerObj[label];
2909 this.hasDefaultHeaders = true;
2912 this.hasHeaders = true;
2917 setHeader:function(o)
2919 if (this.hasDefaultHeaders) {
2920 for (var prop in this.defaultHeaders) {
2921 if (this.defaultHeaders.hasOwnProperty(prop)) {
2922 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2927 if (this.hasHeaders) {
2928 for (var prop in this.headers) {
2929 if (this.headers.hasOwnProperty(prop)) {
2930 o.conn.setRequestHeader(prop, this.headers[prop]);
2934 this.hasHeaders = false;
2938 resetDefaultHeaders:function() {
2939 delete this.defaultHeaders;
2940 this.defaultHeaders = {};
2941 this.hasDefaultHeaders = false;
2944 abort:function(o, callback, isTimeout)
2946 if(this.isCallInProgress(o)) {
2948 window.clearInterval(this.poll[o.tId]);
2949 delete this.poll[o.tId];
2951 delete this.timeout[o.tId];
2954 this.handleTransactionResponse(o, callback, true);
2964 isCallInProgress:function(o)
2967 return o.conn.readyState != 4 && o.conn.readyState != 0;
2976 releaseObject:function(o)
2985 'MSXML2.XMLHTTP.3.0',
2993 * Portions of this file are based on pieces of Yahoo User Interface Library
2994 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2995 * YUI licensed under the BSD License:
2996 * http://developer.yahoo.net/yui/license.txt
2997 * <script type="text/javascript">
3001 Roo.lib.Region = function(t, r, b, l) {
3011 Roo.lib.Region.prototype = {
3012 contains : function(region) {
3013 return ( region.left >= this.left &&
3014 region.right <= this.right &&
3015 region.top >= this.top &&
3016 region.bottom <= this.bottom );
3020 getArea : function() {
3021 return ( (this.bottom - this.top) * (this.right - this.left) );
3024 intersect : function(region) {
3025 var t = Math.max(this.top, region.top);
3026 var r = Math.min(this.right, region.right);
3027 var b = Math.min(this.bottom, region.bottom);
3028 var l = Math.max(this.left, region.left);
3030 if (b >= t && r >= l) {
3031 return new Roo.lib.Region(t, r, b, l);
3036 union : function(region) {
3037 var t = Math.min(this.top, region.top);
3038 var r = Math.max(this.right, region.right);
3039 var b = Math.max(this.bottom, region.bottom);
3040 var l = Math.min(this.left, region.left);
3042 return new Roo.lib.Region(t, r, b, l);
3045 adjust : function(t, l, b, r) {
3054 Roo.lib.Region.getRegion = function(el) {
3055 var p = Roo.lib.Dom.getXY(el);
3058 var r = p[0] + el.offsetWidth;
3059 var b = p[1] + el.offsetHeight;
3062 return new Roo.lib.Region(t, r, b, l);
3065 * Portions of this file are based on pieces of Yahoo User Interface Library
3066 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3067 * YUI licensed under the BSD License:
3068 * http://developer.yahoo.net/yui/license.txt
3069 * <script type="text/javascript">
3072 //@@dep Roo.lib.Region
3075 Roo.lib.Point = function(x, y) {
3076 if (x instanceof Array) {
3080 this.x = this.right = this.left = this[0] = x;
3081 this.y = this.top = this.bottom = this[1] = y;
3084 Roo.lib.Point.prototype = new Roo.lib.Region();
3086 * Portions of this file are based on pieces of Yahoo User Interface Library
3087 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3088 * YUI licensed under the BSD License:
3089 * http://developer.yahoo.net/yui/license.txt
3090 * <script type="text/javascript">
3097 scroll : function(el, args, duration, easing, cb, scope) {
3098 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3101 motion : function(el, args, duration, easing, cb, scope) {
3102 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3105 color : function(el, args, duration, easing, cb, scope) {
3106 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3109 run : function(el, args, duration, easing, cb, scope, type) {
3110 type = type || Roo.lib.AnimBase;
3111 if (typeof easing == "string") {
3112 easing = Roo.lib.Easing[easing];
3114 var anim = new type(el, args, duration, easing);
3115 anim.animateX(function() {
3116 Roo.callback(cb, scope);
3122 * Portions of this file are based on pieces of Yahoo User Interface Library
3123 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3124 * YUI licensed under the BSD License:
3125 * http://developer.yahoo.net/yui/license.txt
3126 * <script type="text/javascript">
3134 if (!libFlyweight) {
3135 libFlyweight = new Roo.Element.Flyweight();
3137 libFlyweight.dom = el;
3138 return libFlyweight;
3141 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3145 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3147 this.init(el, attributes, duration, method);
3151 Roo.lib.AnimBase.fly = fly;
3155 Roo.lib.AnimBase.prototype = {
3157 toString: function() {
3158 var el = this.getEl();
3159 var id = el.id || el.tagName;
3160 return ("Anim " + id);
3164 noNegatives: /width|height|opacity|padding/i,
3165 offsetAttribute: /^((width|height)|(top|left))$/,
3166 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3167 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3171 doMethod: function(attr, start, end) {
3172 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3176 setAttribute: function(attr, val, unit) {
3177 if (this.patterns.noNegatives.test(attr)) {
3178 val = (val > 0) ? val : 0;
3181 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3185 getAttribute: function(attr) {
3186 var el = this.getEl();
3187 var val = fly(el).getStyle(attr);
3189 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3190 return parseFloat(val);
3193 var a = this.patterns.offsetAttribute.exec(attr) || [];
3194 var pos = !!( a[3] );
3195 var box = !!( a[2] );
3198 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3199 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3208 getDefaultUnit: function(attr) {
3209 if (this.patterns.defaultUnit.test(attr)) {
3216 animateX : function(callback, scope) {
3217 var f = function() {
3218 this.onComplete.removeListener(f);
3219 if (typeof callback == "function") {
3220 callback.call(scope || this, this);
3223 this.onComplete.addListener(f, this);
3228 setRuntimeAttribute: function(attr) {
3231 var attributes = this.attributes;
3233 this.runtimeAttributes[attr] = {};
3235 var isset = function(prop) {
3236 return (typeof prop !== 'undefined');
3239 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3243 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3246 if (isset(attributes[attr]['to'])) {
3247 end = attributes[attr]['to'];
3248 } else if (isset(attributes[attr]['by'])) {
3249 if (start.constructor == Array) {
3251 for (var i = 0, len = start.length; i < len; ++i) {
3252 end[i] = start[i] + attributes[attr]['by'][i];
3255 end = start + attributes[attr]['by'];
3259 this.runtimeAttributes[attr].start = start;
3260 this.runtimeAttributes[attr].end = end;
3263 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3267 init: function(el, attributes, duration, method) {
3269 var isAnimated = false;
3272 var startTime = null;
3275 var actualFrames = 0;
3278 el = Roo.getDom(el);
3281 this.attributes = attributes || {};
3284 this.duration = duration || 1;
3287 this.method = method || Roo.lib.Easing.easeNone;
3290 this.useSeconds = true;
3293 this.currentFrame = 0;
3296 this.totalFrames = Roo.lib.AnimMgr.fps;
3299 this.getEl = function() {
3304 this.isAnimated = function() {
3309 this.getStartTime = function() {
3313 this.runtimeAttributes = {};
3316 this.animate = function() {
3317 if (this.isAnimated()) {
3321 this.currentFrame = 0;
3323 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3325 Roo.lib.AnimMgr.registerElement(this);
3329 this.stop = function(finish) {
3331 this.currentFrame = this.totalFrames;
3332 this._onTween.fire();
3334 Roo.lib.AnimMgr.stop(this);
3337 var onStart = function() {
3338 this.onStart.fire();
3340 this.runtimeAttributes = {};
3341 for (var attr in this.attributes) {
3342 this.setRuntimeAttribute(attr);
3347 startTime = new Date();
3351 var onTween = function() {
3353 duration: new Date() - this.getStartTime(),
3354 currentFrame: this.currentFrame
3357 data.toString = function() {
3359 'duration: ' + data.duration +
3360 ', currentFrame: ' + data.currentFrame
3364 this.onTween.fire(data);
3366 var runtimeAttributes = this.runtimeAttributes;
3368 for (var attr in runtimeAttributes) {
3369 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3375 var onComplete = function() {
3376 var actual_duration = (new Date() - startTime) / 1000 ;
3379 duration: actual_duration,
3380 frames: actualFrames,
3381 fps: actualFrames / actual_duration
3384 data.toString = function() {
3386 'duration: ' + data.duration +
3387 ', frames: ' + data.frames +
3388 ', fps: ' + data.fps
3394 this.onComplete.fire(data);
3398 this._onStart = new Roo.util.Event(this);
3399 this.onStart = new Roo.util.Event(this);
3400 this.onTween = new Roo.util.Event(this);
3401 this._onTween = new Roo.util.Event(this);
3402 this.onComplete = new Roo.util.Event(this);
3403 this._onComplete = new Roo.util.Event(this);
3404 this._onStart.addListener(onStart);
3405 this._onTween.addListener(onTween);
3406 this._onComplete.addListener(onComplete);
3411 * Portions of this file are based on pieces of Yahoo User Interface Library
3412 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3413 * YUI licensed under the BSD License:
3414 * http://developer.yahoo.net/yui/license.txt
3415 * <script type="text/javascript">
3419 Roo.lib.AnimMgr = new function() {
3436 this.registerElement = function(tween) {
3437 queue[queue.length] = tween;
3439 tween._onStart.fire();
3444 this.unRegister = function(tween, index) {
3445 tween._onComplete.fire();
3446 index = index || getIndex(tween);
3448 queue.splice(index, 1);
3452 if (tweenCount <= 0) {
3458 this.start = function() {
3459 if (thread === null) {
3460 thread = setInterval(this.run, this.delay);
3465 this.stop = function(tween) {
3467 clearInterval(thread);
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 if (queue[0].isAnimated()) {
3471 this.unRegister(queue[0], 0);
3480 this.unRegister(tween);
3485 this.run = function() {
3486 for (var i = 0, len = queue.length; i < len; ++i) {
3487 var tween = queue[i];
3488 if (!tween || !tween.isAnimated()) {
3492 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3494 tween.currentFrame += 1;
3496 if (tween.useSeconds) {
3497 correctFrame(tween);
3499 tween._onTween.fire();
3502 Roo.lib.AnimMgr.stop(tween, i);
3507 var getIndex = function(anim) {
3508 for (var i = 0, len = queue.length; i < len; ++i) {
3509 if (queue[i] == anim) {
3517 var correctFrame = function(tween) {
3518 var frames = tween.totalFrames;
3519 var frame = tween.currentFrame;
3520 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3521 var elapsed = (new Date() - tween.getStartTime());
3524 if (elapsed < tween.duration * 1000) {
3525 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3527 tweak = frames - (frame + 1);
3529 if (tweak > 0 && isFinite(tweak)) {
3530 if (tween.currentFrame + tweak >= frames) {
3531 tweak = frames - (frame + 1);
3534 tween.currentFrame += tweak;
3540 * Portions of this file are based on pieces of Yahoo User Interface Library
3541 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3542 * YUI licensed under the BSD License:
3543 * http://developer.yahoo.net/yui/license.txt
3544 * <script type="text/javascript">
3547 Roo.lib.Bezier = new function() {
3549 this.getPosition = function(points, t) {
3550 var n = points.length;
3553 for (var i = 0; i < n; ++i) {
3554 tmp[i] = [points[i][0], points[i][1]];
3557 for (var j = 1; j < n; ++j) {
3558 for (i = 0; i < n - j; ++i) {
3559 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3560 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3564 return [ tmp[0][0], tmp[0][1] ];
3568 * Portions of this file are based on pieces of Yahoo User Interface Library
3569 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3570 * YUI licensed under the BSD License:
3571 * http://developer.yahoo.net/yui/license.txt
3572 * <script type="text/javascript">
3577 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3578 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3581 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3583 var fly = Roo.lib.AnimBase.fly;
3585 var superclass = Y.ColorAnim.superclass;
3586 var proto = Y.ColorAnim.prototype;
3588 proto.toString = function() {
3589 var el = this.getEl();
3590 var id = el.id || el.tagName;
3591 return ("ColorAnim " + id);
3594 proto.patterns.color = /color$/i;
3595 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3596 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3597 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3598 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3601 proto.parseColor = function(s) {
3602 if (s.length == 3) {
3606 var c = this.patterns.hex.exec(s);
3607 if (c && c.length == 4) {
3608 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3611 c = this.patterns.rgb.exec(s);
3612 if (c && c.length == 4) {
3613 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3616 c = this.patterns.hex3.exec(s);
3617 if (c && c.length == 4) {
3618 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3623 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3624 proto.getAttribute = function(attr) {
3625 var el = this.getEl();
3626 if (this.patterns.color.test(attr)) {
3627 var val = fly(el).getStyle(attr);
3629 if (this.patterns.transparent.test(val)) {
3630 var parent = el.parentNode;
3631 val = fly(parent).getStyle(attr);
3633 while (parent && this.patterns.transparent.test(val)) {
3634 parent = parent.parentNode;
3635 val = fly(parent).getStyle(attr);
3636 if (parent.tagName.toUpperCase() == 'HTML') {
3642 val = superclass.getAttribute.call(this, attr);
3647 proto.getAttribute = function(attr) {
3648 var el = this.getEl();
3649 if (this.patterns.color.test(attr)) {
3650 var val = fly(el).getStyle(attr);
3652 if (this.patterns.transparent.test(val)) {
3653 var parent = el.parentNode;
3654 val = fly(parent).getStyle(attr);
3656 while (parent && this.patterns.transparent.test(val)) {
3657 parent = parent.parentNode;
3658 val = fly(parent).getStyle(attr);
3659 if (parent.tagName.toUpperCase() == 'HTML') {
3665 val = superclass.getAttribute.call(this, attr);
3671 proto.doMethod = function(attr, start, end) {
3674 if (this.patterns.color.test(attr)) {
3676 for (var i = 0, len = start.length; i < len; ++i) {
3677 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3680 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3683 val = superclass.doMethod.call(this, attr, start, end);
3689 proto.setRuntimeAttribute = function(attr) {
3690 superclass.setRuntimeAttribute.call(this, attr);
3692 if (this.patterns.color.test(attr)) {
3693 var attributes = this.attributes;
3694 var start = this.parseColor(this.runtimeAttributes[attr].start);
3695 var end = this.parseColor(this.runtimeAttributes[attr].end);
3697 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3698 end = this.parseColor(attributes[attr].by);
3700 for (var i = 0, len = start.length; i < len; ++i) {
3701 end[i] = start[i] + end[i];
3705 this.runtimeAttributes[attr].start = start;
3706 this.runtimeAttributes[attr].end = end;
3712 * Portions of this file are based on pieces of Yahoo User Interface Library
3713 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3714 * YUI licensed under the BSD License:
3715 * http://developer.yahoo.net/yui/license.txt
3716 * <script type="text/javascript">
3722 easeNone: function (t, b, c, d) {
3723 return c * t / d + b;
3727 easeIn: function (t, b, c, d) {
3728 return c * (t /= d) * t + b;
3732 easeOut: function (t, b, c, d) {
3733 return -c * (t /= d) * (t - 2) + b;
3737 easeBoth: function (t, b, c, d) {
3738 if ((t /= d / 2) < 1) {
3739 return c / 2 * t * t + b;
3742 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3746 easeInStrong: function (t, b, c, d) {
3747 return c * (t /= d) * t * t * t + b;
3751 easeOutStrong: function (t, b, c, d) {
3752 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3756 easeBothStrong: function (t, b, c, d) {
3757 if ((t /= d / 2) < 1) {
3758 return c / 2 * t * t * t * t + b;
3761 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3766 elasticIn: function (t, b, c, d, a, p) {
3770 if ((t /= d) == 1) {
3777 if (!a || a < Math.abs(c)) {
3782 var s = p / (2 * Math.PI) * Math.asin(c / a);
3785 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3789 elasticOut: function (t, b, c, d, a, p) {
3793 if ((t /= d) == 1) {
3800 if (!a || a < Math.abs(c)) {
3805 var s = p / (2 * Math.PI) * Math.asin(c / a);
3808 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3812 elasticBoth: function (t, b, c, d, a, p) {
3817 if ((t /= d / 2) == 2) {
3825 if (!a || a < Math.abs(c)) {
3830 var s = p / (2 * Math.PI) * Math.asin(c / a);
3834 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3835 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3837 return a * Math.pow(2, -10 * (t -= 1)) *
3838 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3843 backIn: function (t, b, c, d, s) {
3844 if (typeof s == 'undefined') {
3847 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3851 backOut: function (t, b, c, d, s) {
3852 if (typeof s == 'undefined') {
3855 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3859 backBoth: function (t, b, c, d, s) {
3860 if (typeof s == 'undefined') {
3864 if ((t /= d / 2 ) < 1) {
3865 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3867 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3871 bounceIn: function (t, b, c, d) {
3872 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3876 bounceOut: function (t, b, c, d) {
3877 if ((t /= d) < (1 / 2.75)) {
3878 return c * (7.5625 * t * t) + b;
3879 } else if (t < (2 / 2.75)) {
3880 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3881 } else if (t < (2.5 / 2.75)) {
3882 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3884 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3888 bounceBoth: function (t, b, c, d) {
3890 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3892 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3895 * Portions of this file are based on pieces of Yahoo User Interface Library
3896 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3897 * YUI licensed under the BSD License:
3898 * http://developer.yahoo.net/yui/license.txt
3899 * <script type="text/javascript">
3903 Roo.lib.Motion = function(el, attributes, duration, method) {
3905 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3909 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3913 var superclass = Y.Motion.superclass;
3914 var proto = Y.Motion.prototype;
3916 proto.toString = function() {
3917 var el = this.getEl();
3918 var id = el.id || el.tagName;
3919 return ("Motion " + id);
3922 proto.patterns.points = /^points$/i;
3924 proto.setAttribute = function(attr, val, unit) {
3925 if (this.patterns.points.test(attr)) {
3926 unit = unit || 'px';
3927 superclass.setAttribute.call(this, 'left', val[0], unit);
3928 superclass.setAttribute.call(this, 'top', val[1], unit);
3930 superclass.setAttribute.call(this, attr, val, unit);
3934 proto.getAttribute = function(attr) {
3935 if (this.patterns.points.test(attr)) {
3937 superclass.getAttribute.call(this, 'left'),
3938 superclass.getAttribute.call(this, 'top')
3941 val = superclass.getAttribute.call(this, attr);
3947 proto.doMethod = function(attr, start, end) {
3950 if (this.patterns.points.test(attr)) {
3951 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3952 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3954 val = superclass.doMethod.call(this, attr, start, end);
3959 proto.setRuntimeAttribute = function(attr) {
3960 if (this.patterns.points.test(attr)) {
3961 var el = this.getEl();
3962 var attributes = this.attributes;
3964 var control = attributes['points']['control'] || [];
3968 if (control.length > 0 && !(control[0] instanceof Array)) {
3969 control = [control];
3972 for (i = 0,len = control.length; i < len; ++i) {
3973 tmp[i] = control[i];
3978 Roo.fly(el).position();
3980 if (isset(attributes['points']['from'])) {
3981 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3984 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3987 start = this.getAttribute('points');
3990 if (isset(attributes['points']['to'])) {
3991 end = translateValues.call(this, attributes['points']['to'], start);
3993 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3994 for (i = 0,len = control.length; i < len; ++i) {
3995 control[i] = translateValues.call(this, control[i], start);
3999 } else if (isset(attributes['points']['by'])) {
4000 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4002 for (i = 0,len = control.length; i < len; ++i) {
4003 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4007 this.runtimeAttributes[attr] = [start];
4009 if (control.length > 0) {
4010 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4013 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4016 superclass.setRuntimeAttribute.call(this, attr);
4020 var translateValues = function(val, start) {
4021 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4022 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4027 var isset = function(prop) {
4028 return (typeof prop !== 'undefined');
4032 * Portions of this file are based on pieces of Yahoo User Interface Library
4033 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4034 * YUI licensed under the BSD License:
4035 * http://developer.yahoo.net/yui/license.txt
4036 * <script type="text/javascript">
4040 Roo.lib.Scroll = function(el, attributes, duration, method) {
4042 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4046 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4050 var superclass = Y.Scroll.superclass;
4051 var proto = Y.Scroll.prototype;
4053 proto.toString = function() {
4054 var el = this.getEl();
4055 var id = el.id || el.tagName;
4056 return ("Scroll " + id);
4059 proto.doMethod = function(attr, start, end) {
4062 if (attr == 'scroll') {
4064 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4065 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4069 val = superclass.doMethod.call(this, attr, start, end);
4074 proto.getAttribute = function(attr) {
4076 var el = this.getEl();
4078 if (attr == 'scroll') {
4079 val = [ el.scrollLeft, el.scrollTop ];
4081 val = superclass.getAttribute.call(this, attr);
4087 proto.setAttribute = function(attr, val, unit) {
4088 var el = this.getEl();
4090 if (attr == 'scroll') {
4091 el.scrollLeft = val[0];
4092 el.scrollTop = val[1];
4094 superclass.setAttribute.call(this, attr, val, unit);
4100 * Ext JS Library 1.1.1
4101 * Copyright(c) 2006-2007, Ext JS, LLC.
4103 * Originally Released Under LGPL - original licence link has changed is not relivant.
4106 * <script type="text/javascript">
4110 // nasty IE9 hack - what a pile of crap that is..
4112 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4113 Range.prototype.createContextualFragment = function (html) {
4114 var doc = window.document;
4115 var container = doc.createElement("div");
4116 container.innerHTML = html;
4117 var frag = doc.createDocumentFragment(), n;
4118 while ((n = container.firstChild)) {
4119 frag.appendChild(n);
4126 * @class Roo.DomHelper
4127 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4128 * 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>.
4131 Roo.DomHelper = function(){
4132 var tempTableEl = null;
4133 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4134 var tableRe = /^table|tbody|tr|td$/i;
4136 // build as innerHTML where available
4138 var createHtml = function(o){
4139 if(typeof o == 'string'){
4148 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4149 if(attr == "style"){
4151 if(typeof s == "function"){
4154 if(typeof s == "string"){
4155 b += ' style="' + s + '"';
4156 }else if(typeof s == "object"){
4159 if(typeof s[key] != "function"){
4160 b += key + ":" + s[key] + ";";
4167 b += ' class="' + o["cls"] + '"';
4168 }else if(attr == "htmlFor"){
4169 b += ' for="' + o["htmlFor"] + '"';
4171 b += " " + attr + '="' + o[attr] + '"';
4175 if(emptyTags.test(o.tag)){
4179 var cn = o.children || o.cn;
4181 //http://bugs.kde.org/show_bug.cgi?id=71506
4182 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4183 for(var i = 0, len = cn.length; i < len; i++) {
4184 b += createHtml(cn[i], b);
4187 b += createHtml(cn, b);
4193 b += "</" + o.tag + ">";
4200 var createDom = function(o, parentNode){
4202 // defininition craeted..
4204 if (o.ns && o.ns != 'html') {
4206 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4207 xmlns[o.ns] = o.xmlns;
4210 if (typeof(xmlns[o.ns]) == 'undefined') {
4211 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4217 if (typeof(o) == 'string') {
4218 return parentNode.appendChild(document.createTextNode(o));
4220 o.tag = o.tag || div;
4221 if (o.ns && Roo.isIE) {
4223 o.tag = o.ns + ':' + o.tag;
4226 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4227 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4230 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4231 attr == "style" || typeof o[attr] == "function") continue;
4233 if(attr=="cls" && Roo.isIE){
4234 el.className = o["cls"];
4236 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4237 else el[attr] = o[attr];
4240 Roo.DomHelper.applyStyles(el, o.style);
4241 var cn = o.children || o.cn;
4243 //http://bugs.kde.org/show_bug.cgi?id=71506
4244 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4245 for(var i = 0, len = cn.length; i < len; i++) {
4246 createDom(cn[i], el);
4253 el.innerHTML = o.html;
4256 parentNode.appendChild(el);
4261 var ieTable = function(depth, s, h, e){
4262 tempTableEl.innerHTML = [s, h, e].join('');
4263 var i = -1, el = tempTableEl;
4270 // kill repeat to save bytes
4274 tbe = '</tbody>'+te,
4280 * Nasty code for IE's broken table implementation
4282 var insertIntoTable = function(tag, where, el, html){
4284 tempTableEl = document.createElement('div');
4289 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4292 if(where == 'beforebegin'){
4296 before = el.nextSibling;
4299 node = ieTable(4, trs, html, tre);
4301 else if(tag == 'tr'){
4302 if(where == 'beforebegin'){
4305 node = ieTable(3, tbs, html, tbe);
4306 } else if(where == 'afterend'){
4307 before = el.nextSibling;
4309 node = ieTable(3, tbs, html, tbe);
4310 } else{ // INTO a TR
4311 if(where == 'afterbegin'){
4312 before = el.firstChild;
4314 node = ieTable(4, trs, html, tre);
4316 } else if(tag == 'tbody'){
4317 if(where == 'beforebegin'){
4320 node = ieTable(2, ts, html, te);
4321 } else if(where == 'afterend'){
4322 before = el.nextSibling;
4324 node = ieTable(2, ts, html, te);
4326 if(where == 'afterbegin'){
4327 before = el.firstChild;
4329 node = ieTable(3, tbs, html, tbe);
4332 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4335 if(where == 'afterbegin'){
4336 before = el.firstChild;
4338 node = ieTable(2, ts, html, te);
4340 el.insertBefore(node, before);
4345 /** True to force the use of DOM instead of html fragments @type Boolean */
4349 * Returns the markup for the passed Element(s) config
4350 * @param {Object} o The Dom object spec (and children)
4353 markup : function(o){
4354 return createHtml(o);
4358 * Applies a style specification to an element
4359 * @param {String/HTMLElement} el The element to apply styles to
4360 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4361 * a function which returns such a specification.
4363 applyStyles : function(el, styles){
4366 if(typeof styles == "string"){
4367 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4369 while ((matches = re.exec(styles)) != null){
4370 el.setStyle(matches[1], matches[2]);
4372 }else if (typeof styles == "object"){
4373 for (var style in styles){
4374 el.setStyle(style, styles[style]);
4376 }else if (typeof styles == "function"){
4377 Roo.DomHelper.applyStyles(el, styles.call());
4383 * Inserts an HTML fragment into the Dom
4384 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4385 * @param {HTMLElement} el The context element
4386 * @param {String} html The HTML fragmenet
4387 * @return {HTMLElement} The new node
4389 insertHtml : function(where, el, html){
4390 where = where.toLowerCase();
4391 if(el.insertAdjacentHTML){
4392 if(tableRe.test(el.tagName)){
4394 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4400 el.insertAdjacentHTML('BeforeBegin', html);
4401 return el.previousSibling;
4403 el.insertAdjacentHTML('AfterBegin', html);
4404 return el.firstChild;
4406 el.insertAdjacentHTML('BeforeEnd', html);
4407 return el.lastChild;
4409 el.insertAdjacentHTML('AfterEnd', html);
4410 return el.nextSibling;
4412 throw 'Illegal insertion point -> "' + where + '"';
4414 var range = el.ownerDocument.createRange();
4418 range.setStartBefore(el);
4419 frag = range.createContextualFragment(html);
4420 el.parentNode.insertBefore(frag, el);
4421 return el.previousSibling;
4424 range.setStartBefore(el.firstChild);
4425 frag = range.createContextualFragment(html);
4426 el.insertBefore(frag, el.firstChild);
4427 return el.firstChild;
4429 el.innerHTML = html;
4430 return el.firstChild;
4434 range.setStartAfter(el.lastChild);
4435 frag = range.createContextualFragment(html);
4436 el.appendChild(frag);
4437 return el.lastChild;
4439 el.innerHTML = html;
4440 return el.lastChild;
4443 range.setStartAfter(el);
4444 frag = range.createContextualFragment(html);
4445 el.parentNode.insertBefore(frag, el.nextSibling);
4446 return el.nextSibling;
4448 throw 'Illegal insertion point -> "' + where + '"';
4452 * Creates new Dom element(s) and inserts them before el
4453 * @param {String/HTMLElement/Element} el The context element
4454 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4455 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4456 * @return {HTMLElement/Roo.Element} The new node
4458 insertBefore : function(el, o, returnElement){
4459 return this.doInsert(el, o, returnElement, "beforeBegin");
4463 * Creates new Dom element(s) and inserts them after el
4464 * @param {String/HTMLElement/Element} el The context element
4465 * @param {Object} o The Dom object spec (and children)
4466 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4467 * @return {HTMLElement/Roo.Element} The new node
4469 insertAfter : function(el, o, returnElement){
4470 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4474 * Creates new Dom element(s) and inserts them as the first child of el
4475 * @param {String/HTMLElement/Element} el The context element
4476 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4477 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4478 * @return {HTMLElement/Roo.Element} The new node
4480 insertFirst : function(el, o, returnElement){
4481 return this.doInsert(el, o, returnElement, "afterBegin");
4485 doInsert : function(el, o, returnElement, pos, sibling){
4486 el = Roo.getDom(el);
4488 if(this.useDom || o.ns){
4489 newNode = createDom(o, null);
4490 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4492 var html = createHtml(o);
4493 newNode = this.insertHtml(pos, el, html);
4495 return returnElement ? Roo.get(newNode, true) : newNode;
4499 * Creates new Dom element(s) and appends them to el
4500 * @param {String/HTMLElement/Element} el The context element
4501 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4502 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4503 * @return {HTMLElement/Roo.Element} The new node
4505 append : function(el, o, returnElement){
4506 el = Roo.getDom(el);
4508 if(this.useDom || o.ns){
4509 newNode = createDom(o, null);
4510 el.appendChild(newNode);
4512 var html = createHtml(o);
4513 newNode = this.insertHtml("beforeEnd", el, html);
4515 return returnElement ? Roo.get(newNode, true) : newNode;
4519 * Creates new Dom element(s) and overwrites the contents of el with them
4520 * @param {String/HTMLElement/Element} el The context element
4521 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4522 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4523 * @return {HTMLElement/Roo.Element} The new node
4525 overwrite : function(el, o, returnElement){
4526 el = Roo.getDom(el);
4529 while (el.childNodes.length) {
4530 el.removeChild(el.firstChild);
4534 el.innerHTML = createHtml(o);
4537 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4541 * Creates a new Roo.DomHelper.Template from the Dom object spec
4542 * @param {Object} o The Dom object spec (and children)
4543 * @return {Roo.DomHelper.Template} The new template
4545 createTemplate : function(o){
4546 var html = createHtml(o);
4547 return new Roo.Template(html);
4553 * Ext JS Library 1.1.1
4554 * Copyright(c) 2006-2007, Ext JS, LLC.
4556 * Originally Released Under LGPL - original licence link has changed is not relivant.
4559 * <script type="text/javascript">
4563 * @class Roo.Template
4564 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4565 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4568 var t = new Roo.Template({
4569 html : '<div name="{id}">' +
4570 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4572 myformat: function (value, allValues) {
4573 return 'XX' + value;
4576 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4578 * For more information see this blog post with examples:
4579 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4580 - Create Elements using DOM, HTML fragments and Templates</a>.
4582 * @param {Object} cfg - Configuration object.
4584 Roo.Template = function(cfg){
4586 if(cfg instanceof Array){
4588 }else if(arguments.length > 1){
4589 cfg = Array.prototype.join.call(arguments, "");
4593 if (typeof(cfg) == 'object') {
4604 Roo.Template.prototype = {
4607 * @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..
4608 * it should be fixed so that template is observable...
4612 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4616 * Returns an HTML fragment of this template with the specified values applied.
4617 * @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'})
4618 * @return {String} The HTML fragment
4620 applyTemplate : function(values){
4624 return this.compiled(values);
4626 var useF = this.disableFormats !== true;
4627 var fm = Roo.util.Format, tpl = this;
4628 var fn = function(m, name, format, args){
4630 if(format.substr(0, 5) == "this."){
4631 return tpl.call(format.substr(5), values[name], values);
4634 // quoted values are required for strings in compiled templates,
4635 // but for non compiled we need to strip them
4636 // quoted reversed for jsmin
4637 var re = /^\s*['"](.*)["']\s*$/;
4638 args = args.split(',');
4639 for(var i = 0, len = args.length; i < len; i++){
4640 args[i] = args[i].replace(re, "$1");
4642 args = [values[name]].concat(args);
4644 args = [values[name]];
4646 return fm[format].apply(fm, args);
4649 return values[name] !== undefined ? values[name] : "";
4652 return this.html.replace(this.re, fn);
4670 this.loading = true;
4671 this.compiled = false;
4673 var cx = new Roo.data.Connection();
4677 success : function (response) {
4679 _t.html = response.responseText;
4683 failure : function(response) {
4684 Roo.log("Template failed to load from " + _t.url);
4691 * Sets the HTML used as the template and optionally compiles it.
4692 * @param {String} html
4693 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4694 * @return {Roo.Template} this
4696 set : function(html, compile){
4698 this.compiled = null;
4706 * True to disable format functions (defaults to false)
4709 disableFormats : false,
4712 * The regular expression used to match template variables
4716 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4719 * Compiles the template into an internal function, eliminating the RegEx overhead.
4720 * @return {Roo.Template} this
4722 compile : function(){
4723 var fm = Roo.util.Format;
4724 var useF = this.disableFormats !== true;
4725 var sep = Roo.isGecko ? "+" : ",";
4726 var fn = function(m, name, format, args){
4728 args = args ? ',' + args : "";
4729 if(format.substr(0, 5) != "this."){
4730 format = "fm." + format + '(';
4732 format = 'this.call("'+ format.substr(5) + '", ';
4736 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4738 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4741 // branched to use + in gecko and [].join() in others
4743 body = "this.compiled = function(values){ return '" +
4744 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4747 body = ["this.compiled = function(values){ return ['"];
4748 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4749 body.push("'].join('');};");
4750 body = body.join('');
4760 // private function used to call members
4761 call : function(fnName, value, allValues){
4762 return this[fnName](value, allValues);
4766 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4767 * @param {String/HTMLElement/Roo.Element} el The context element
4768 * @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'})
4769 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4770 * @return {HTMLElement/Roo.Element} The new node or Element
4772 insertFirst: function(el, values, returnElement){
4773 return this.doInsert('afterBegin', el, values, returnElement);
4777 * Applies the supplied values to the template and inserts the new node(s) before el.
4778 * @param {String/HTMLElement/Roo.Element} el The context element
4779 * @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'})
4780 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4781 * @return {HTMLElement/Roo.Element} The new node or Element
4783 insertBefore: function(el, values, returnElement){
4784 return this.doInsert('beforeBegin', el, values, returnElement);
4788 * Applies the supplied values to the template and inserts the new node(s) after el.
4789 * @param {String/HTMLElement/Roo.Element} el The context element
4790 * @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'})
4791 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4792 * @return {HTMLElement/Roo.Element} The new node or Element
4794 insertAfter : function(el, values, returnElement){
4795 return this.doInsert('afterEnd', el, values, returnElement);
4799 * Applies the supplied values to the template and appends the new node(s) to el.
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 append : function(el, values, returnElement){
4806 return this.doInsert('beforeEnd', el, values, returnElement);
4809 doInsert : function(where, el, values, returnEl){
4810 el = Roo.getDom(el);
4811 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4812 return returnEl ? Roo.get(newNode, true) : newNode;
4816 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4817 * @param {String/HTMLElement/Roo.Element} el The context element
4818 * @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'})
4819 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4820 * @return {HTMLElement/Roo.Element} The new node or Element
4822 overwrite : function(el, values, returnElement){
4823 el = Roo.getDom(el);
4824 el.innerHTML = this.applyTemplate(values);
4825 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4829 * Alias for {@link #applyTemplate}
4832 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4835 Roo.DomHelper.Template = Roo.Template;
4838 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4839 * @param {String/HTMLElement} el A DOM element or its id
4840 * @returns {Roo.Template} The created template
4843 Roo.Template.from = function(el){
4844 el = Roo.getDom(el);
4845 return new Roo.Template(el.value || el.innerHTML);
4848 * Ext JS Library 1.1.1
4849 * Copyright(c) 2006-2007, Ext JS, LLC.
4851 * Originally Released Under LGPL - original licence link has changed is not relivant.
4854 * <script type="text/javascript">
4859 * This is code is also distributed under MIT license for use
4860 * with jQuery and prototype JavaScript libraries.
4863 * @class Roo.DomQuery
4864 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).
4866 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>
4869 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.
4871 <h4>Element Selectors:</h4>
4873 <li> <b>*</b> any element</li>
4874 <li> <b>E</b> an element with the tag E</li>
4875 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4876 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4877 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4878 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4880 <h4>Attribute Selectors:</h4>
4881 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4883 <li> <b>E[foo]</b> has an attribute "foo"</li>
4884 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4885 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4886 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4887 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4888 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4889 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4891 <h4>Pseudo Classes:</h4>
4893 <li> <b>E:first-child</b> E is the first child of its parent</li>
4894 <li> <b>E:last-child</b> E is the last child of its parent</li>
4895 <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>
4896 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4897 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4898 <li> <b>E:only-child</b> E is the only child of its parent</li>
4899 <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>
4900 <li> <b>E:first</b> the first E in the resultset</li>
4901 <li> <b>E:last</b> the last E in the resultset</li>
4902 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4903 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4904 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4905 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4906 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4907 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4908 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4909 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4910 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4912 <h4>CSS Value Selectors:</h4>
4914 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4915 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4916 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4917 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4918 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4919 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4923 Roo.DomQuery = function(){
4924 var cache = {}, simpleCache = {}, valueCache = {};
4925 var nonSpace = /\S/;
4926 var trimRe = /^\s+|\s+$/g;
4927 var tplRe = /\{(\d+)\}/g;
4928 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4929 var tagTokenRe = /^(#)?([\w-\*]+)/;
4930 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4932 function child(p, index){
4934 var n = p.firstChild;
4936 if(n.nodeType == 1){
4947 while((n = n.nextSibling) && n.nodeType != 1);
4952 while((n = n.previousSibling) && n.nodeType != 1);
4956 function children(d){
4957 var n = d.firstChild, ni = -1;
4959 var nx = n.nextSibling;
4960 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4970 function byClassName(c, a, v){
4974 var r = [], ri = -1, cn;
4975 for(var i = 0, ci; ci = c[i]; i++){
4976 if((' '+ci.className+' ').indexOf(v) != -1){
4983 function attrValue(n, attr){
4984 if(!n.tagName && typeof n.length != "undefined"){
4993 if(attr == "class" || attr == "className"){
4996 return n.getAttribute(attr) || n[attr];
5000 function getNodes(ns, mode, tagName){
5001 var result = [], ri = -1, cs;
5005 tagName = tagName || "*";
5006 if(typeof ns.getElementsByTagName != "undefined"){
5010 for(var i = 0, ni; ni = ns[i]; i++){
5011 cs = ni.getElementsByTagName(tagName);
5012 for(var j = 0, ci; ci = cs[j]; j++){
5016 }else if(mode == "/" || mode == ">"){
5017 var utag = tagName.toUpperCase();
5018 for(var i = 0, ni, cn; ni = ns[i]; i++){
5019 cn = ni.children || ni.childNodes;
5020 for(var j = 0, cj; cj = cn[j]; j++){
5021 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5026 }else if(mode == "+"){
5027 var utag = tagName.toUpperCase();
5028 for(var i = 0, n; n = ns[i]; i++){
5029 while((n = n.nextSibling) && n.nodeType != 1);
5030 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5034 }else if(mode == "~"){
5035 for(var i = 0, n; n = ns[i]; i++){
5036 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5045 function concat(a, b){
5049 for(var i = 0, l = b.length; i < l; i++){
5055 function byTag(cs, tagName){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 tagName = tagName.toLowerCase();
5064 for(var i = 0, ci; ci = cs[i]; i++){
5065 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5072 function byId(cs, attr, id){
5073 if(cs.tagName || cs == document){
5079 var r = [], ri = -1;
5080 for(var i = 0,ci; ci = cs[i]; i++){
5081 if(ci && ci.id == id){
5089 function byAttribute(cs, attr, value, op, custom){
5090 var r = [], ri = -1, st = custom=="{";
5091 var f = Roo.DomQuery.operators[op];
5092 for(var i = 0, ci; ci = cs[i]; i++){
5095 a = Roo.DomQuery.getStyle(ci, attr);
5097 else if(attr == "class" || attr == "className"){
5099 }else if(attr == "for"){
5101 }else if(attr == "href"){
5102 a = ci.getAttribute("href", 2);
5104 a = ci.getAttribute(attr);
5106 if((f && f(a, value)) || (!f && a)){
5113 function byPseudo(cs, name, value){
5114 return Roo.DomQuery.pseudos[name](cs, value);
5117 // This is for IE MSXML which does not support expandos.
5118 // IE runs the same speed using setAttribute, however FF slows way down
5119 // and Safari completely fails so they need to continue to use expandos.
5120 var isIE = window.ActiveXObject ? true : false;
5122 // this eval is stop the compressor from
5123 // renaming the variable to something shorter
5125 /** eval:var:batch */
5130 function nodupIEXml(cs){
5132 cs[0].setAttribute("_nodup", d);
5134 for(var i = 1, len = cs.length; i < len; i++){
5136 if(!c.getAttribute("_nodup") != d){
5137 c.setAttribute("_nodup", d);
5141 for(var i = 0, len = cs.length; i < len; i++){
5142 cs[i].removeAttribute("_nodup");
5151 var len = cs.length, c, i, r = cs, cj, ri = -1;
5152 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5155 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5156 return nodupIEXml(cs);
5160 for(i = 1; c = cs[i]; i++){
5165 for(var j = 0; j < i; j++){
5168 for(j = i+1; cj = cs[j]; j++){
5180 function quickDiffIEXml(c1, c2){
5182 for(var i = 0, len = c1.length; i < len; i++){
5183 c1[i].setAttribute("_qdiff", d);
5186 for(var i = 0, len = c2.length; i < len; i++){
5187 if(c2[i].getAttribute("_qdiff") != d){
5188 r[r.length] = c2[i];
5191 for(var i = 0, len = c1.length; i < len; i++){
5192 c1[i].removeAttribute("_qdiff");
5197 function quickDiff(c1, c2){
5198 var len1 = c1.length;
5202 if(isIE && c1[0].selectSingleNode){
5203 return quickDiffIEXml(c1, c2);
5206 for(var i = 0; i < len1; i++){
5210 for(var i = 0, len = c2.length; i < len; i++){
5211 if(c2[i]._qdiff != d){
5212 r[r.length] = c2[i];
5218 function quickId(ns, mode, root, id){
5220 var d = root.ownerDocument || root;
5221 return d.getElementById(id);
5223 ns = getNodes(ns, mode, "*");
5224 return byId(ns, null, id);
5228 getStyle : function(el, name){
5229 return Roo.fly(el).getStyle(name);
5232 * Compiles a selector/xpath query into a reusable function. The returned function
5233 * takes one parameter "root" (optional), which is the context node from where the query should start.
5234 * @param {String} selector The selector/xpath query
5235 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5236 * @return {Function}
5238 compile : function(path, type){
5239 type = type || "select";
5241 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5242 var q = path, mode, lq;
5243 var tk = Roo.DomQuery.matchers;
5244 var tklen = tk.length;
5247 // accept leading mode switch
5248 var lmode = q.match(modeRe);
5249 if(lmode && lmode[1]){
5250 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5251 q = q.replace(lmode[1], "");
5253 // strip leading slashes
5254 while(path.substr(0, 1)=="/"){
5255 path = path.substr(1);
5258 while(q && lq != q){
5260 var tm = q.match(tagTokenRe);
5261 if(type == "select"){
5264 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5266 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5268 q = q.replace(tm[0], "");
5269 }else if(q.substr(0, 1) != '@'){
5270 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5275 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5277 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5279 q = q.replace(tm[0], "");
5282 while(!(mm = q.match(modeRe))){
5283 var matched = false;
5284 for(var j = 0; j < tklen; j++){
5286 var m = q.match(t.re);
5288 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5291 q = q.replace(m[0], "");
5296 // prevent infinite loop on bad selector
5298 throw 'Error parsing selector, parsing failed at "' + q + '"';
5302 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5303 q = q.replace(mm[1], "");
5306 fn[fn.length] = "return nodup(n);\n}";
5309 * list of variables that need from compression as they are used by eval.
5319 * eval:var:byClassName
5321 * eval:var:byAttribute
5322 * eval:var:attrValue
5330 * Selects a group of elements.
5331 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5332 * @param {Node} root (optional) The start of the query (defaults to document).
5335 select : function(path, root, type){
5336 if(!root || root == document){
5339 if(typeof root == "string"){
5340 root = document.getElementById(root);
5342 var paths = path.split(",");
5344 for(var i = 0, len = paths.length; i < len; i++){
5345 var p = paths[i].replace(trimRe, "");
5347 cache[p] = Roo.DomQuery.compile(p);
5349 throw p + " is not a valid selector";
5352 var result = cache[p](root);
5353 if(result && result != document){
5354 results = results.concat(result);
5357 if(paths.length > 1){
5358 return nodup(results);
5364 * Selects a single element.
5365 * @param {String} selector The selector/xpath query
5366 * @param {Node} root (optional) The start of the query (defaults to document).
5369 selectNode : function(path, root){
5370 return Roo.DomQuery.select(path, root)[0];
5374 * Selects the value of a node, optionally replacing null with the defaultValue.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {String} defaultValue
5379 selectValue : function(path, root, defaultValue){
5380 path = path.replace(trimRe, "");
5381 if(!valueCache[path]){
5382 valueCache[path] = Roo.DomQuery.compile(path, "select");
5384 var n = valueCache[path](root);
5385 n = n[0] ? n[0] : n;
5386 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5387 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5391 * Selects the value of a node, parsing integers and floats.
5392 * @param {String} selector The selector/xpath query
5393 * @param {Node} root (optional) The start of the query (defaults to document).
5394 * @param {Number} defaultValue
5397 selectNumber : function(path, root, defaultValue){
5398 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5399 return parseFloat(v);
5403 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5404 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5405 * @param {String} selector The simple selector to test
5408 is : function(el, ss){
5409 if(typeof el == "string"){
5410 el = document.getElementById(el);
5412 var isArray = (el instanceof Array);
5413 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5414 return isArray ? (result.length == el.length) : (result.length > 0);
5418 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5419 * @param {Array} el An array of elements to filter
5420 * @param {String} selector The simple selector to test
5421 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5422 * the selector instead of the ones that match
5425 filter : function(els, ss, nonMatches){
5426 ss = ss.replace(trimRe, "");
5427 if(!simpleCache[ss]){
5428 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5430 var result = simpleCache[ss](els);
5431 return nonMatches ? quickDiff(result, els) : result;
5435 * Collection of matching regular expressions and code snippets.
5439 select: 'n = byClassName(n, null, " {1} ");'
5441 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5442 select: 'n = byPseudo(n, "{1}", "{2}");'
5444 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5445 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5448 select: 'n = byId(n, null, "{1}");'
5451 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5456 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5457 * 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, > <.
5460 "=" : function(a, v){
5463 "!=" : function(a, v){
5466 "^=" : function(a, v){
5467 return a && a.substr(0, v.length) == v;
5469 "$=" : function(a, v){
5470 return a && a.substr(a.length-v.length) == v;
5472 "*=" : function(a, v){
5473 return a && a.indexOf(v) !== -1;
5475 "%=" : function(a, v){
5476 return (a % v) == 0;
5478 "|=" : function(a, v){
5479 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5481 "~=" : function(a, v){
5482 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5487 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5488 * and the argument (if any) supplied in the selector.
5491 "first-child" : function(c){
5492 var r = [], ri = -1, n;
5493 for(var i = 0, ci; ci = n = c[i]; i++){
5494 while((n = n.previousSibling) && n.nodeType != 1);
5502 "last-child" : function(c){
5503 var r = [], ri = -1, n;
5504 for(var i = 0, ci; ci = n = c[i]; i++){
5505 while((n = n.nextSibling) && n.nodeType != 1);
5513 "nth-child" : function(c, a) {
5514 var r = [], ri = -1;
5515 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5516 var f = (m[1] || 1) - 0, l = m[2] - 0;
5517 for(var i = 0, n; n = c[i]; i++){
5518 var pn = n.parentNode;
5519 if (batch != pn._batch) {
5521 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5522 if(cn.nodeType == 1){
5529 if (l == 0 || n.nodeIndex == l){
5532 } else if ((n.nodeIndex + l) % f == 0){
5540 "only-child" : function(c){
5541 var r = [], ri = -1;;
5542 for(var i = 0, ci; ci = c[i]; i++){
5543 if(!prev(ci) && !next(ci)){
5550 "empty" : function(c){
5551 var r = [], ri = -1;
5552 for(var i = 0, ci; ci = c[i]; i++){
5553 var cns = ci.childNodes, j = 0, cn, empty = true;
5556 if(cn.nodeType == 1 || cn.nodeType == 3){
5568 "contains" : function(c, v){
5569 var r = [], ri = -1;
5570 for(var i = 0, ci; ci = c[i]; i++){
5571 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5578 "nodeValue" : function(c, v){
5579 var r = [], ri = -1;
5580 for(var i = 0, ci; ci = c[i]; i++){
5581 if(ci.firstChild && ci.firstChild.nodeValue == v){
5588 "checked" : function(c){
5589 var r = [], ri = -1;
5590 for(var i = 0, ci; ci = c[i]; i++){
5591 if(ci.checked == true){
5598 "not" : function(c, ss){
5599 return Roo.DomQuery.filter(c, ss, true);
5602 "odd" : function(c){
5603 return this["nth-child"](c, "odd");
5606 "even" : function(c){
5607 return this["nth-child"](c, "even");
5610 "nth" : function(c, a){
5611 return c[a-1] || [];
5614 "first" : function(c){
5618 "last" : function(c){
5619 return c[c.length-1] || [];
5622 "has" : function(c, ss){
5623 var s = Roo.DomQuery.select;
5624 var r = [], ri = -1;
5625 for(var i = 0, ci; ci = c[i]; i++){
5626 if(s(ss, ci).length > 0){
5633 "next" : function(c, ss){
5634 var is = Roo.DomQuery.is;
5635 var r = [], ri = -1;
5636 for(var i = 0, ci; ci = c[i]; i++){
5645 "prev" : function(c, ss){
5646 var is = Roo.DomQuery.is;
5647 var r = [], ri = -1;
5648 for(var i = 0, ci; ci = c[i]; i++){
5661 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5662 * @param {String} path The selector/xpath query
5663 * @param {Node} root (optional) The start of the query (defaults to document).
5668 Roo.query = Roo.DomQuery.select;
5671 * Ext JS Library 1.1.1
5672 * Copyright(c) 2006-2007, Ext JS, LLC.
5674 * Originally Released Under LGPL - original licence link has changed is not relivant.
5677 * <script type="text/javascript">
5681 * @class Roo.util.Observable
5682 * Base class that provides a common interface for publishing events. Subclasses are expected to
5683 * to have a property "events" with all the events defined.<br>
5686 Employee = function(name){
5693 Roo.extend(Employee, Roo.util.Observable);
5695 * @param {Object} config properties to use (incuding events / listeners)
5698 Roo.util.Observable = function(cfg){
5701 this.addEvents(cfg.events || {});
5703 delete cfg.events; // make sure
5706 Roo.apply(this, cfg);
5709 this.on(this.listeners);
5710 delete this.listeners;
5713 Roo.util.Observable.prototype = {
5715 * @cfg {Object} listeners list of events and functions to call for this object,
5719 'click' : function(e) {
5729 * Fires the specified event with the passed parameters (minus the event name).
5730 * @param {String} eventName
5731 * @param {Object...} args Variable number of parameters are passed to handlers
5732 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5734 fireEvent : function(){
5735 var ce = this.events[arguments[0].toLowerCase()];
5736 if(typeof ce == "object"){
5737 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5744 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5747 * Appends an event handler to this component
5748 * @param {String} eventName The type of event to listen for
5749 * @param {Function} handler The method the event invokes
5750 * @param {Object} scope (optional) The scope in which to execute the handler
5751 * function. The handler function's "this" context.
5752 * @param {Object} options (optional) An object containing handler configuration
5753 * properties. This may contain any of the following properties:<ul>
5754 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5755 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5756 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5757 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5758 * by the specified number of milliseconds. If the event fires again within that time, the original
5759 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5762 * <b>Combining Options</b><br>
5763 * Using the options argument, it is possible to combine different types of listeners:<br>
5765 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5767 el.on('click', this.onClick, this, {
5774 * <b>Attaching multiple handlers in 1 call</b><br>
5775 * The method also allows for a single argument to be passed which is a config object containing properties
5776 * which specify multiple handlers.
5785 fn: this.onMouseOver,
5789 fn: this.onMouseOut,
5795 * Or a shorthand syntax which passes the same scope object to all handlers:
5798 'click': this.onClick,
5799 'mouseover': this.onMouseOver,
5800 'mouseout': this.onMouseOut,
5805 addListener : function(eventName, fn, scope, o){
5806 if(typeof eventName == "object"){
5809 if(this.filterOptRe.test(e)){
5812 if(typeof o[e] == "function"){
5814 this.addListener(e, o[e], o.scope, o);
5816 // individual options
5817 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5822 o = (!o || typeof o == "boolean") ? {} : o;
5823 eventName = eventName.toLowerCase();
5824 var ce = this.events[eventName] || true;
5825 if(typeof ce == "boolean"){
5826 ce = new Roo.util.Event(this, eventName);
5827 this.events[eventName] = ce;
5829 ce.addListener(fn, scope, o);
5833 * Removes a listener
5834 * @param {String} eventName The type of event to listen for
5835 * @param {Function} handler The handler to remove
5836 * @param {Object} scope (optional) The scope (this object) for the handler
5838 removeListener : function(eventName, fn, scope){
5839 var ce = this.events[eventName.toLowerCase()];
5840 if(typeof ce == "object"){
5841 ce.removeListener(fn, scope);
5846 * Removes all listeners for this object
5848 purgeListeners : function(){
5849 for(var evt in this.events){
5850 if(typeof this.events[evt] == "object"){
5851 this.events[evt].clearListeners();
5856 relayEvents : function(o, events){
5857 var createHandler = function(ename){
5859 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5862 for(var i = 0, len = events.length; i < len; i++){
5863 var ename = events[i];
5864 if(!this.events[ename]){ this.events[ename] = true; };
5865 o.on(ename, createHandler(ename), this);
5870 * Used to define events on this Observable
5871 * @param {Object} object The object with the events defined
5873 addEvents : function(o){
5877 Roo.applyIf(this.events, o);
5881 * Checks to see if this object has any listeners for a specified event
5882 * @param {String} eventName The name of the event to check for
5883 * @return {Boolean} True if the event is being listened for, else false
5885 hasListener : function(eventName){
5886 var e = this.events[eventName];
5887 return typeof e == "object" && e.listeners.length > 0;
5891 * Appends an event handler to this element (shorthand for addListener)
5892 * @param {String} eventName The type of event to listen for
5893 * @param {Function} handler The method the event invokes
5894 * @param {Object} scope (optional) The scope in which to execute the handler
5895 * function. The handler function's "this" context.
5896 * @param {Object} options (optional)
5899 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5901 * Removes a listener (shorthand for removeListener)
5902 * @param {String} eventName The type of event to listen for
5903 * @param {Function} handler The handler to remove
5904 * @param {Object} scope (optional) The scope (this object) for the handler
5907 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5910 * Starts capture on the specified Observable. All events will be passed
5911 * to the supplied function with the event name + standard signature of the event
5912 * <b>before</b> the event is fired. If the supplied function returns false,
5913 * the event will not fire.
5914 * @param {Observable} o The Observable to capture
5915 * @param {Function} fn The function to call
5916 * @param {Object} scope (optional) The scope (this object) for the fn
5919 Roo.util.Observable.capture = function(o, fn, scope){
5920 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5924 * Removes <b>all</b> added captures from the Observable.
5925 * @param {Observable} o The Observable to release
5928 Roo.util.Observable.releaseCapture = function(o){
5929 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5934 var createBuffered = function(h, o, scope){
5935 var task = new Roo.util.DelayedTask();
5937 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5941 var createSingle = function(h, e, fn, scope){
5943 e.removeListener(fn, scope);
5944 return h.apply(scope, arguments);
5948 var createDelayed = function(h, o, scope){
5950 var args = Array.prototype.slice.call(arguments, 0);
5951 setTimeout(function(){
5952 h.apply(scope, args);
5957 Roo.util.Event = function(obj, name){
5960 this.listeners = [];
5963 Roo.util.Event.prototype = {
5964 addListener : function(fn, scope, options){
5965 var o = options || {};
5966 scope = scope || this.obj;
5967 if(!this.isListening(fn, scope)){
5968 var l = {fn: fn, scope: scope, options: o};
5971 h = createDelayed(h, o, scope);
5974 h = createSingle(h, this, fn, scope);
5977 h = createBuffered(h, o, scope);
5980 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5981 this.listeners.push(l);
5983 this.listeners = this.listeners.slice(0);
5984 this.listeners.push(l);
5989 findListener : function(fn, scope){
5990 scope = scope || this.obj;
5991 var ls = this.listeners;
5992 for(var i = 0, len = ls.length; i < len; i++){
5994 if(l.fn == fn && l.scope == scope){
6001 isListening : function(fn, scope){
6002 return this.findListener(fn, scope) != -1;
6005 removeListener : function(fn, scope){
6007 if((index = this.findListener(fn, scope)) != -1){
6009 this.listeners.splice(index, 1);
6011 this.listeners = this.listeners.slice(0);
6012 this.listeners.splice(index, 1);
6019 clearListeners : function(){
6020 this.listeners = [];
6024 var ls = this.listeners, scope, len = ls.length;
6027 var args = Array.prototype.slice.call(arguments, 0);
6028 for(var i = 0; i < len; i++){
6030 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6031 this.firing = false;
6035 this.firing = false;
6042 * Ext JS Library 1.1.1
6043 * Copyright(c) 2006-2007, Ext JS, LLC.
6045 * Originally Released Under LGPL - original licence link has changed is not relivant.
6048 * <script type="text/javascript">
6052 * @class Roo.EventManager
6053 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6054 * several useful events directly.
6055 * See {@link Roo.EventObject} for more details on normalized event objects.
6058 Roo.EventManager = function(){
6059 var docReadyEvent, docReadyProcId, docReadyState = false;
6060 var resizeEvent, resizeTask, textEvent, textSize;
6061 var E = Roo.lib.Event;
6062 var D = Roo.lib.Dom;
6067 var fireDocReady = function(){
6069 docReadyState = true;
6072 clearInterval(docReadyProcId);
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6078 var defer = document.getElementById("ie-deferred-loader");
6080 defer.onreadystatechange = null;
6081 defer.parentNode.removeChild(defer);
6085 docReadyEvent.fire();
6086 docReadyEvent.clearListeners();
6091 var initDocReady = function(){
6092 docReadyEvent = new Roo.util.Event();
6093 if(Roo.isGecko || Roo.isOpera) {
6094 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6096 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6097 var defer = document.getElementById("ie-deferred-loader");
6098 defer.onreadystatechange = function(){
6099 if(this.readyState == "complete"){
6103 }else if(Roo.isSafari){
6104 docReadyProcId = setInterval(function(){
6105 var rs = document.readyState;
6106 if(rs == "complete") {
6111 // no matter what, make sure it fires on load
6112 E.on(window, "load", fireDocReady);
6115 var createBuffered = function(h, o){
6116 var task = new Roo.util.DelayedTask(h);
6118 // create new event object impl so new events don't wipe out properties
6119 e = new Roo.EventObjectImpl(e);
6120 task.delay(o.buffer, h, null, [e]);
6124 var createSingle = function(h, el, ename, fn){
6126 Roo.EventManager.removeListener(el, ename, fn);
6131 var createDelayed = function(h, o){
6133 // create new event object impl so new events don't wipe out properties
6134 e = new Roo.EventObjectImpl(e);
6135 setTimeout(function(){
6140 var transitionEndVal = false;
6142 var transitionEnd = function()
6144 if (transitionEndVal) {
6145 return transitionEndVal;
6147 var el = document.createElement('div');
6149 var transEndEventNames = {
6150 WebkitTransition : 'webkitTransitionEnd',
6151 MozTransition : 'transitionend',
6152 OTransition : 'oTransitionEnd otransitionend',
6153 transition : 'transitionend'
6156 for (var name in transEndEventNames) {
6157 if (el.style[name] !== undefined) {
6158 transitionEndVal = transEndEventNames[name];
6159 return transitionEndVal ;
6165 var listen = function(element, ename, opt, fn, scope){
6166 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6167 fn = fn || o.fn; scope = scope || o.scope;
6168 var el = Roo.getDom(element);
6172 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6175 if (ename == 'transitionend') {
6176 ename = transitionEnd();
6178 var h = function(e){
6179 e = Roo.EventObject.setEvent(e);
6182 t = e.getTarget(o.delegate, el);
6189 if(o.stopEvent === true){
6192 if(o.preventDefault === true){
6195 if(o.stopPropagation === true){
6196 e.stopPropagation();
6199 if(o.normalized === false){
6203 fn.call(scope || el, e, t, o);
6206 h = createDelayed(h, o);
6209 h = createSingle(h, el, ename, fn);
6212 h = createBuffered(h, o);
6214 fn._handlers = fn._handlers || [];
6217 fn._handlers.push([Roo.id(el), ename, h]);
6222 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6223 el.addEventListener("DOMMouseScroll", h, false);
6224 E.on(window, 'unload', function(){
6225 el.removeEventListener("DOMMouseScroll", h, false);
6228 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6229 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6234 var stopListening = function(el, ename, fn){
6235 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6237 for(var i = 0, len = hds.length; i < len; i++){
6239 if(h[0] == id && h[1] == ename){
6246 E.un(el, ename, hd);
6247 el = Roo.getDom(el);
6248 if(ename == "mousewheel" && el.addEventListener){
6249 el.removeEventListener("DOMMouseScroll", hd, false);
6251 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6252 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6256 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6263 * @scope Roo.EventManager
6268 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6269 * object with a Roo.EventObject
6270 * @param {Function} fn The method the event invokes
6271 * @param {Object} scope An object that becomes the scope of the handler
6272 * @param {boolean} override If true, the obj passed in becomes
6273 * the execution scope of the listener
6274 * @return {Function} The wrapped function
6277 wrap : function(fn, scope, override){
6279 Roo.EventObject.setEvent(e);
6280 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6285 * Appends an event handler to an element (shorthand for addListener)
6286 * @param {String/HTMLElement} element The html element or id to assign the
6287 * @param {String} eventName The type of event to listen for
6288 * @param {Function} handler The method the event invokes
6289 * @param {Object} scope (optional) The scope in which to execute the handler
6290 * function. The handler function's "this" context.
6291 * @param {Object} options (optional) An object containing handler configuration
6292 * properties. This may contain any of the following properties:<ul>
6293 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6294 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6295 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6296 * <li>preventDefault {Boolean} True to prevent the default action</li>
6297 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6298 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6299 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6300 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6301 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6302 * by the specified number of milliseconds. If the event fires again within that time, the original
6303 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6306 * <b>Combining Options</b><br>
6307 * Using the options argument, it is possible to combine different types of listeners:<br>
6309 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6311 el.on('click', this.onClick, this, {
6318 * <b>Attaching multiple handlers in 1 call</b><br>
6319 * The method also allows for a single argument to be passed which is a config object containing properties
6320 * which specify multiple handlers.
6330 fn: this.onMouseOver
6339 * Or a shorthand syntax:<br>
6342 'click' : this.onClick,
6343 'mouseover' : this.onMouseOver,
6344 'mouseout' : this.onMouseOut
6348 addListener : function(element, eventName, fn, scope, options){
6349 if(typeof eventName == "object"){
6355 if(typeof o[e] == "function"){
6357 listen(element, e, o, o[e], o.scope);
6359 // individual options
6360 listen(element, e, o[e]);
6365 return listen(element, eventName, options, fn, scope);
6369 * Removes an event handler
6371 * @param {String/HTMLElement} element The id or html element to remove the
6373 * @param {String} eventName The type of event
6374 * @param {Function} fn
6375 * @return {Boolean} True if a listener was actually removed
6377 removeListener : function(element, eventName, fn){
6378 return stopListening(element, eventName, fn);
6382 * Fires when the document is ready (before onload and before images are loaded). Can be
6383 * accessed shorthanded Roo.onReady().
6384 * @param {Function} fn The method the event invokes
6385 * @param {Object} scope An object that becomes the scope of the handler
6386 * @param {boolean} options
6388 onDocumentReady : function(fn, scope, options){
6389 if(docReadyState){ // if it already fired
6390 docReadyEvent.addListener(fn, scope, options);
6391 docReadyEvent.fire();
6392 docReadyEvent.clearListeners();
6398 docReadyEvent.addListener(fn, scope, options);
6402 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6403 * @param {Function} fn The method the event invokes
6404 * @param {Object} scope An object that becomes the scope of the handler
6405 * @param {boolean} options
6407 onWindowResize : function(fn, scope, options){
6409 resizeEvent = new Roo.util.Event();
6410 resizeTask = new Roo.util.DelayedTask(function(){
6411 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6413 E.on(window, "resize", function(){
6415 resizeTask.delay(50);
6417 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6421 resizeEvent.addListener(fn, scope, options);
6425 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6426 * @param {Function} fn The method the event invokes
6427 * @param {Object} scope An object that becomes the scope of the handler
6428 * @param {boolean} options
6430 onTextResize : function(fn, scope, options){
6432 textEvent = new Roo.util.Event();
6433 var textEl = new Roo.Element(document.createElement('div'));
6434 textEl.dom.className = 'x-text-resize';
6435 textEl.dom.innerHTML = 'X';
6436 textEl.appendTo(document.body);
6437 textSize = textEl.dom.offsetHeight;
6438 setInterval(function(){
6439 if(textEl.dom.offsetHeight != textSize){
6440 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6442 }, this.textResizeInterval);
6444 textEvent.addListener(fn, scope, options);
6448 * Removes the passed window resize listener.
6449 * @param {Function} fn The method the event invokes
6450 * @param {Object} scope The scope of handler
6452 removeResizeListener : function(fn, scope){
6454 resizeEvent.removeListener(fn, scope);
6459 fireResize : function(){
6461 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6465 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6469 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6471 textResizeInterval : 50
6476 * @scopeAlias pub=Roo.EventManager
6480 * Appends an event handler to an element (shorthand for addListener)
6481 * @param {String/HTMLElement} element The html element or id to assign the
6482 * @param {String} eventName The type of event to listen for
6483 * @param {Function} handler The method the event invokes
6484 * @param {Object} scope (optional) The scope in which to execute the handler
6485 * function. The handler function's "this" context.
6486 * @param {Object} options (optional) An object containing handler configuration
6487 * properties. This may contain any of the following properties:<ul>
6488 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6489 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6490 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6491 * <li>preventDefault {Boolean} True to prevent the default action</li>
6492 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6493 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6494 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6495 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6496 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6497 * by the specified number of milliseconds. If the event fires again within that time, the original
6498 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6501 * <b>Combining Options</b><br>
6502 * Using the options argument, it is possible to combine different types of listeners:<br>
6504 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6506 el.on('click', this.onClick, this, {
6513 * <b>Attaching multiple handlers in 1 call</b><br>
6514 * The method also allows for a single argument to be passed which is a config object containing properties
6515 * which specify multiple handlers.
6525 fn: this.onMouseOver
6534 * Or a shorthand syntax:<br>
6537 'click' : this.onClick,
6538 'mouseover' : this.onMouseOver,
6539 'mouseout' : this.onMouseOut
6543 pub.on = pub.addListener;
6544 pub.un = pub.removeListener;
6546 pub.stoppedMouseDownEvent = new Roo.util.Event();
6550 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6551 * @param {Function} fn The method the event invokes
6552 * @param {Object} scope An object that becomes the scope of the handler
6553 * @param {boolean} override If true, the obj passed in becomes
6554 * the execution scope of the listener
6558 Roo.onReady = Roo.EventManager.onDocumentReady;
6560 Roo.onReady(function(){
6561 var bd = Roo.get(document.body);
6566 : Roo.isGecko ? "roo-gecko"
6567 : Roo.isOpera ? "roo-opera"
6568 : Roo.isSafari ? "roo-safari" : ""];
6571 cls.push("roo-mac");
6574 cls.push("roo-linux");
6576 if(Roo.isBorderBox){
6577 cls.push('roo-border-box');
6579 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6580 var p = bd.dom.parentNode;
6582 p.className += ' roo-strict';
6585 bd.addClass(cls.join(' '));
6589 * @class Roo.EventObject
6590 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6591 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6594 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6596 var target = e.getTarget();
6599 var myDiv = Roo.get("myDiv");
6600 myDiv.on("click", handleClick);
6602 Roo.EventManager.on("myDiv", 'click', handleClick);
6603 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6607 Roo.EventObject = function(){
6609 var E = Roo.lib.Event;
6611 // safari keypress events for special keys return bad keycodes
6614 63235 : 39, // right
6617 63276 : 33, // page up
6618 63277 : 34, // page down
6619 63272 : 46, // delete
6624 // normalize button clicks
6625 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6626 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6628 Roo.EventObjectImpl = function(e){
6630 this.setEvent(e.browserEvent || e);
6633 Roo.EventObjectImpl.prototype = {
6635 * Used to fix doc tools.
6636 * @scope Roo.EventObject.prototype
6642 /** The normal browser event */
6643 browserEvent : null,
6644 /** The button pressed in a mouse event */
6646 /** True if the shift key was down during the event */
6648 /** True if the control key was down during the event */
6650 /** True if the alt key was down during the event */
6709 setEvent : function(e){
6710 if(e == this || (e && e.browserEvent)){ // already wrapped
6713 this.browserEvent = e;
6715 // normalize buttons
6716 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6717 if(e.type == 'click' && this.button == -1){
6721 this.shiftKey = e.shiftKey;
6722 // mac metaKey behaves like ctrlKey
6723 this.ctrlKey = e.ctrlKey || e.metaKey;
6724 this.altKey = e.altKey;
6725 // in getKey these will be normalized for the mac
6726 this.keyCode = e.keyCode;
6727 // keyup warnings on firefox.
6728 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6729 // cache the target for the delayed and or buffered events
6730 this.target = E.getTarget(e);
6732 this.xy = E.getXY(e);
6735 this.shiftKey = false;
6736 this.ctrlKey = false;
6737 this.altKey = false;
6747 * Stop the event (preventDefault and stopPropagation)
6749 stopEvent : function(){
6750 if(this.browserEvent){
6751 if(this.browserEvent.type == 'mousedown'){
6752 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6754 E.stopEvent(this.browserEvent);
6759 * Prevents the browsers default handling of the event.
6761 preventDefault : function(){
6762 if(this.browserEvent){
6763 E.preventDefault(this.browserEvent);
6768 isNavKeyPress : function(){
6769 var k = this.keyCode;
6770 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6771 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6774 isSpecialKey : function(){
6775 var k = this.keyCode;
6776 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6777 (k == 16) || (k == 17) ||
6778 (k >= 18 && k <= 20) ||
6779 (k >= 33 && k <= 35) ||
6780 (k >= 36 && k <= 39) ||
6781 (k >= 44 && k <= 45);
6784 * Cancels bubbling of the event.
6786 stopPropagation : function(){
6787 if(this.browserEvent){
6788 if(this.type == 'mousedown'){
6789 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6791 E.stopPropagation(this.browserEvent);
6796 * Gets the key code for the event.
6799 getCharCode : function(){
6800 return this.charCode || this.keyCode;
6804 * Returns a normalized keyCode for the event.
6805 * @return {Number} The key code
6807 getKey : function(){
6808 var k = this.keyCode || this.charCode;
6809 return Roo.isSafari ? (safariKeys[k] || k) : k;
6813 * Gets the x coordinate of the event.
6816 getPageX : function(){
6821 * Gets the y coordinate of the event.
6824 getPageY : function(){
6829 * Gets the time of the event.
6832 getTime : function(){
6833 if(this.browserEvent){
6834 return E.getTime(this.browserEvent);
6840 * Gets the page coordinates of the event.
6841 * @return {Array} The xy values like [x, y]
6848 * Gets the target for the event.
6849 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6850 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6851 search as a number or element (defaults to 10 || document.body)
6852 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6853 * @return {HTMLelement}
6855 getTarget : function(selector, maxDepth, returnEl){
6856 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6859 * Gets the related target.
6860 * @return {HTMLElement}
6862 getRelatedTarget : function(){
6863 if(this.browserEvent){
6864 return E.getRelatedTarget(this.browserEvent);
6870 * Normalizes mouse wheel delta across browsers
6871 * @return {Number} The delta
6873 getWheelDelta : function(){
6874 var e = this.browserEvent;
6876 if(e.wheelDelta){ /* IE/Opera. */
6877 delta = e.wheelDelta/120;
6878 }else if(e.detail){ /* Mozilla case. */
6879 delta = -e.detail/3;
6885 * Returns true if the control, meta, shift or alt key was pressed during this event.
6888 hasModifier : function(){
6889 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6893 * Returns true if the target of this event equals el or is a child of el
6894 * @param {String/HTMLElement/Element} el
6895 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6898 within : function(el, related){
6899 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6900 return t && Roo.fly(el).contains(t);
6903 getPoint : function(){
6904 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6908 return new Roo.EventObjectImpl();
6913 * Ext JS Library 1.1.1
6914 * Copyright(c) 2006-2007, Ext JS, LLC.
6916 * Originally Released Under LGPL - original licence link has changed is not relivant.
6919 * <script type="text/javascript">
6923 // was in Composite Element!??!?!
6926 var D = Roo.lib.Dom;
6927 var E = Roo.lib.Event;
6928 var A = Roo.lib.Anim;
6930 // local style camelizing for speed
6932 var camelRe = /(-[a-z])/gi;
6933 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6934 var view = document.defaultView;
6937 * @class Roo.Element
6938 * Represents an Element in the DOM.<br><br>
6941 var el = Roo.get("my-div");
6944 var el = getEl("my-div");
6946 // or with a DOM element
6947 var el = Roo.get(myDivElement);
6949 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6950 * each call instead of constructing a new one.<br><br>
6951 * <b>Animations</b><br />
6952 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6953 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6955 Option Default Description
6956 --------- -------- ---------------------------------------------
6957 duration .35 The duration of the animation in seconds
6958 easing easeOut The YUI easing method
6959 callback none A function to execute when the anim completes
6960 scope this The scope (this) of the callback function
6962 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6963 * manipulate the animation. Here's an example:
6965 var el = Roo.get("my-div");
6970 // default animation
6971 el.setWidth(100, true);
6973 // animation with some options set
6980 // using the "anim" property to get the Anim object
6986 el.setWidth(100, opt);
6988 if(opt.anim.isAnimated()){
6992 * <b> Composite (Collections of) Elements</b><br />
6993 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6994 * @constructor Create a new Element directly.
6995 * @param {String/HTMLElement} element
6996 * @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).
6998 Roo.Element = function(element, forceNew){
6999 var dom = typeof element == "string" ?
7000 document.getElementById(element) : element;
7001 if(!dom){ // invalid id/element
7005 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7006 return Roo.Element.cache[id];
7016 * The DOM element ID
7019 this.id = id || Roo.id(dom);
7022 var El = Roo.Element;
7026 * The element's default display mode (defaults to "")
7029 originalDisplay : "",
7033 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7038 * Sets the element's visibility mode. When setVisible() is called it
7039 * will use this to determine whether to set the visibility or the display property.
7040 * @param visMode Element.VISIBILITY or Element.DISPLAY
7041 * @return {Roo.Element} this
7043 setVisibilityMode : function(visMode){
7044 this.visibilityMode = visMode;
7048 * Convenience method for setVisibilityMode(Element.DISPLAY)
7049 * @param {String} display (optional) What to set display to when visible
7050 * @return {Roo.Element} this
7052 enableDisplayMode : function(display){
7053 this.setVisibilityMode(El.DISPLAY);
7054 if(typeof display != "undefined") this.originalDisplay = display;
7059 * 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)
7060 * @param {String} selector The simple selector to test
7061 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7062 search as a number or element (defaults to 10 || document.body)
7063 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7064 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7066 findParent : function(simpleSelector, maxDepth, returnEl){
7067 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7068 maxDepth = maxDepth || 50;
7069 if(typeof maxDepth != "number"){
7070 stopEl = Roo.getDom(maxDepth);
7073 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7074 if(dq.is(p, simpleSelector)){
7075 return returnEl ? Roo.get(p) : p;
7085 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7086 * @param {String} selector The simple selector to test
7087 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7088 search as a number or element (defaults to 10 || document.body)
7089 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7090 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7092 findParentNode : function(simpleSelector, maxDepth, returnEl){
7093 var p = Roo.fly(this.dom.parentNode, '_internal');
7094 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7098 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7099 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7100 * @param {String} selector The simple selector to test
7101 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7102 search as a number or element (defaults to 10 || document.body)
7103 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7105 up : function(simpleSelector, maxDepth){
7106 return this.findParentNode(simpleSelector, maxDepth, true);
7112 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7113 * @param {String} selector The simple selector to test
7114 * @return {Boolean} True if this element matches the selector, else false
7116 is : function(simpleSelector){
7117 return Roo.DomQuery.is(this.dom, simpleSelector);
7121 * Perform animation on this element.
7122 * @param {Object} args The YUI animation control args
7123 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7124 * @param {Function} onComplete (optional) Function to call when animation completes
7125 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7126 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7127 * @return {Roo.Element} this
7129 animate : function(args, duration, onComplete, easing, animType){
7130 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7135 * @private Internal animation call
7137 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7138 animType = animType || 'run';
7140 var anim = Roo.lib.Anim[animType](
7142 (opt.duration || defaultDur) || .35,
7143 (opt.easing || defaultEase) || 'easeOut',
7145 Roo.callback(cb, this);
7146 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7154 // private legacy anim prep
7155 preanim : function(a, i){
7156 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7160 * Removes worthless text nodes
7161 * @param {Boolean} forceReclean (optional) By default the element
7162 * keeps track if it has been cleaned already so
7163 * you can call this over and over. However, if you update the element and
7164 * need to force a reclean, you can pass true.
7166 clean : function(forceReclean){
7167 if(this.isCleaned && forceReclean !== true){
7171 var d = this.dom, n = d.firstChild, ni = -1;
7173 var nx = n.nextSibling;
7174 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7181 this.isCleaned = true;
7186 calcOffsetsTo : function(el){
7189 var restorePos = false;
7190 if(el.getStyle('position') == 'static'){
7191 el.position('relative');
7196 while(op && op != d && op.tagName != 'HTML'){
7199 op = op.offsetParent;
7202 el.position('static');
7208 * Scrolls this element into view within the passed container.
7209 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7210 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7211 * @return {Roo.Element} this
7213 scrollIntoView : function(container, hscroll){
7214 var c = Roo.getDom(container) || document.body;
7217 var o = this.calcOffsetsTo(c),
7220 b = t+el.offsetHeight,
7221 r = l+el.offsetWidth;
7223 var ch = c.clientHeight;
7224 var ct = parseInt(c.scrollTop, 10);
7225 var cl = parseInt(c.scrollLeft, 10);
7227 var cr = cl + c.clientWidth;
7235 if(hscroll !== false){
7239 c.scrollLeft = r-c.clientWidth;
7246 scrollChildIntoView : function(child, hscroll){
7247 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7251 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7252 * the new height may not be available immediately.
7253 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7254 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7255 * @param {Function} onComplete (optional) Function to call when animation completes
7256 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7257 * @return {Roo.Element} this
7259 autoHeight : function(animate, duration, onComplete, easing){
7260 var oldHeight = this.getHeight();
7262 this.setHeight(1); // force clipping
7263 setTimeout(function(){
7264 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7266 this.setHeight(height);
7268 if(typeof onComplete == "function"){
7272 this.setHeight(oldHeight); // restore original height
7273 this.setHeight(height, animate, duration, function(){
7275 if(typeof onComplete == "function") onComplete();
7276 }.createDelegate(this), easing);
7278 }.createDelegate(this), 0);
7283 * Returns true if this element is an ancestor of the passed element
7284 * @param {HTMLElement/String} el The element to check
7285 * @return {Boolean} True if this element is an ancestor of el, else false
7287 contains : function(el){
7288 if(!el){return false;}
7289 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7293 * Checks whether the element is currently visible using both visibility and display properties.
7294 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7295 * @return {Boolean} True if the element is currently visible, else false
7297 isVisible : function(deep) {
7298 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7299 if(deep !== true || !vis){
7302 var p = this.dom.parentNode;
7303 while(p && p.tagName.toLowerCase() != "body"){
7304 if(!Roo.fly(p, '_isVisible').isVisible()){
7313 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7314 * @param {String} selector The CSS selector
7315 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7316 * @return {CompositeElement/CompositeElementLite} The composite element
7318 select : function(selector, unique){
7319 return El.select(selector, unique, this.dom);
7323 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7324 * @param {String} selector The CSS selector
7325 * @return {Array} An array of the matched nodes
7327 query : function(selector, unique){
7328 return Roo.DomQuery.select(selector, this.dom);
7332 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7333 * @param {String} selector The CSS selector
7334 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7335 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7337 child : function(selector, returnDom){
7338 var n = Roo.DomQuery.selectNode(selector, this.dom);
7339 return returnDom ? n : Roo.get(n);
7343 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7344 * @param {String} selector The CSS selector
7345 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7346 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7348 down : function(selector, returnDom){
7349 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7350 return returnDom ? n : Roo.get(n);
7354 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7355 * @param {String} group The group the DD object is member of
7356 * @param {Object} config The DD config object
7357 * @param {Object} overrides An object containing methods to override/implement on the DD object
7358 * @return {Roo.dd.DD} The DD object
7360 initDD : function(group, config, overrides){
7361 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7362 return Roo.apply(dd, overrides);
7366 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7367 * @param {String} group The group the DDProxy object is member of
7368 * @param {Object} config The DDProxy config object
7369 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7370 * @return {Roo.dd.DDProxy} The DDProxy object
7372 initDDProxy : function(group, config, overrides){
7373 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7374 return Roo.apply(dd, overrides);
7378 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7379 * @param {String} group The group the DDTarget object is member of
7380 * @param {Object} config The DDTarget config object
7381 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7382 * @return {Roo.dd.DDTarget} The DDTarget object
7384 initDDTarget : function(group, config, overrides){
7385 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7386 return Roo.apply(dd, overrides);
7390 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7391 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7392 * @param {Boolean} visible Whether the element is visible
7393 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7394 * @return {Roo.Element} this
7396 setVisible : function(visible, animate){
7398 if(this.visibilityMode == El.DISPLAY){
7399 this.setDisplayed(visible);
7402 this.dom.style.visibility = visible ? "visible" : "hidden";
7405 // closure for composites
7407 var visMode = this.visibilityMode;
7409 this.setOpacity(.01);
7410 this.setVisible(true);
7412 this.anim({opacity: { to: (visible?1:0) }},
7413 this.preanim(arguments, 1),
7414 null, .35, 'easeIn', function(){
7416 if(visMode == El.DISPLAY){
7417 dom.style.display = "none";
7419 dom.style.visibility = "hidden";
7421 Roo.get(dom).setOpacity(1);
7429 * Returns true if display is not "none"
7432 isDisplayed : function() {
7433 return this.getStyle("display") != "none";
7437 * Toggles the element's visibility or display, depending on visibility mode.
7438 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7439 * @return {Roo.Element} this
7441 toggle : function(animate){
7442 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7447 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7448 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7449 * @return {Roo.Element} this
7451 setDisplayed : function(value) {
7452 if(typeof value == "boolean"){
7453 value = value ? this.originalDisplay : "none";
7455 this.setStyle("display", value);
7460 * Tries to focus the element. Any exceptions are caught and ignored.
7461 * @return {Roo.Element} this
7463 focus : function() {
7471 * Tries to blur the element. Any exceptions are caught and ignored.
7472 * @return {Roo.Element} this
7482 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7483 * @param {String/Array} className The CSS class to add, or an array of classes
7484 * @return {Roo.Element} this
7486 addClass : function(className){
7487 if(className instanceof Array){
7488 for(var i = 0, len = className.length; i < len; i++) {
7489 this.addClass(className[i]);
7492 if(className && !this.hasClass(className)){
7493 this.dom.className = this.dom.className + " " + className;
7500 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7501 * @param {String/Array} className The CSS class to add, or an array of classes
7502 * @return {Roo.Element} this
7504 radioClass : function(className){
7505 var siblings = this.dom.parentNode.childNodes;
7506 for(var i = 0; i < siblings.length; i++) {
7507 var s = siblings[i];
7508 if(s.nodeType == 1){
7509 Roo.get(s).removeClass(className);
7512 this.addClass(className);
7517 * Removes one or more CSS classes from the element.
7518 * @param {String/Array} className The CSS class to remove, or an array of classes
7519 * @return {Roo.Element} this
7521 removeClass : function(className){
7522 if(!className || !this.dom.className){
7525 if(className instanceof Array){
7526 for(var i = 0, len = className.length; i < len; i++) {
7527 this.removeClass(className[i]);
7530 if(this.hasClass(className)){
7531 var re = this.classReCache[className];
7533 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7534 this.classReCache[className] = re;
7536 this.dom.className =
7537 this.dom.className.replace(re, " ");
7547 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7548 * @param {String} className The CSS class to toggle
7549 * @return {Roo.Element} this
7551 toggleClass : function(className){
7552 if(this.hasClass(className)){
7553 this.removeClass(className);
7555 this.addClass(className);
7561 * Checks if the specified CSS class exists on this element's DOM node.
7562 * @param {String} className The CSS class to check for
7563 * @return {Boolean} True if the class exists, else false
7565 hasClass : function(className){
7566 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7570 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7571 * @param {String} oldClassName The CSS class to replace
7572 * @param {String} newClassName The replacement CSS class
7573 * @return {Roo.Element} this
7575 replaceClass : function(oldClassName, newClassName){
7576 this.removeClass(oldClassName);
7577 this.addClass(newClassName);
7582 * Returns an object with properties matching the styles requested.
7583 * For example, el.getStyles('color', 'font-size', 'width') might return
7584 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7585 * @param {String} style1 A style name
7586 * @param {String} style2 A style name
7587 * @param {String} etc.
7588 * @return {Object} The style object
7590 getStyles : function(){
7591 var a = arguments, len = a.length, r = {};
7592 for(var i = 0; i < len; i++){
7593 r[a[i]] = this.getStyle(a[i]);
7599 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7600 * @param {String} property The style property whose value is returned.
7601 * @return {String} The current value of the style property for this element.
7603 getStyle : function(){
7604 return view && view.getComputedStyle ?
7606 var el = this.dom, v, cs, camel;
7607 if(prop == 'float'){
7610 if(el.style && (v = el.style[prop])){
7613 if(cs = view.getComputedStyle(el, "")){
7614 if(!(camel = propCache[prop])){
7615 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7622 var el = this.dom, v, cs, camel;
7623 if(prop == 'opacity'){
7624 if(typeof el.style.filter == 'string'){
7625 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7627 var fv = parseFloat(m[1]);
7629 return fv ? fv / 100 : 0;
7634 }else if(prop == 'float'){
7635 prop = "styleFloat";
7637 if(!(camel = propCache[prop])){
7638 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7640 if(v = el.style[camel]){
7643 if(cs = el.currentStyle){
7651 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7652 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7653 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7654 * @return {Roo.Element} this
7656 setStyle : function(prop, value){
7657 if(typeof prop == "string"){
7659 if (prop == 'float') {
7660 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7665 if(!(camel = propCache[prop])){
7666 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7669 if(camel == 'opacity') {
7670 this.setOpacity(value);
7672 this.dom.style[camel] = value;
7675 for(var style in prop){
7676 if(typeof prop[style] != "function"){
7677 this.setStyle(style, prop[style]);
7685 * More flexible version of {@link #setStyle} for setting style properties.
7686 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7687 * a function which returns such a specification.
7688 * @return {Roo.Element} this
7690 applyStyles : function(style){
7691 Roo.DomHelper.applyStyles(this.dom, style);
7696 * 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).
7697 * @return {Number} The X position of the element
7700 return D.getX(this.dom);
7704 * 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).
7705 * @return {Number} The Y position of the element
7708 return D.getY(this.dom);
7712 * 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).
7713 * @return {Array} The XY position of the element
7716 return D.getXY(this.dom);
7720 * 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).
7721 * @param {Number} The X position of the element
7722 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7723 * @return {Roo.Element} this
7725 setX : function(x, animate){
7727 D.setX(this.dom, x);
7729 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7735 * 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).
7736 * @param {Number} The Y position of the element
7737 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7738 * @return {Roo.Element} this
7740 setY : function(y, animate){
7742 D.setY(this.dom, y);
7744 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7750 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7751 * @param {String} left The left CSS property value
7752 * @return {Roo.Element} this
7754 setLeft : function(left){
7755 this.setStyle("left", this.addUnits(left));
7760 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7761 * @param {String} top The top CSS property value
7762 * @return {Roo.Element} this
7764 setTop : function(top){
7765 this.setStyle("top", this.addUnits(top));
7770 * Sets the element's CSS right style.
7771 * @param {String} right The right CSS property value
7772 * @return {Roo.Element} this
7774 setRight : function(right){
7775 this.setStyle("right", this.addUnits(right));
7780 * Sets the element's CSS bottom style.
7781 * @param {String} bottom The bottom CSS property value
7782 * @return {Roo.Element} this
7784 setBottom : function(bottom){
7785 this.setStyle("bottom", this.addUnits(bottom));
7790 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7791 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7792 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7793 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7794 * @return {Roo.Element} this
7796 setXY : function(pos, animate){
7798 D.setXY(this.dom, pos);
7800 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7806 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7807 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7808 * @param {Number} x X value for new position (coordinates are page-based)
7809 * @param {Number} y Y value for new position (coordinates are page-based)
7810 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7811 * @return {Roo.Element} this
7813 setLocation : function(x, y, animate){
7814 this.setXY([x, y], this.preanim(arguments, 2));
7819 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7820 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7821 * @param {Number} x X value for new position (coordinates are page-based)
7822 * @param {Number} y Y value for new position (coordinates are page-based)
7823 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7824 * @return {Roo.Element} this
7826 moveTo : function(x, y, animate){
7827 this.setXY([x, y], this.preanim(arguments, 2));
7832 * Returns the region of the given element.
7833 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7834 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7836 getRegion : function(){
7837 return D.getRegion(this.dom);
7841 * Returns the offset height of the element
7842 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7843 * @return {Number} The element's height
7845 getHeight : function(contentHeight){
7846 var h = this.dom.offsetHeight || 0;
7847 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7851 * Returns the offset width of the element
7852 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7853 * @return {Number} The element's width
7855 getWidth : function(contentWidth){
7856 var w = this.dom.offsetWidth || 0;
7857 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7861 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7862 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7863 * if a height has not been set using CSS.
7866 getComputedHeight : function(){
7867 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7869 h = parseInt(this.getStyle('height'), 10) || 0;
7870 if(!this.isBorderBox()){
7871 h += this.getFrameWidth('tb');
7878 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7879 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7880 * if a width has not been set using CSS.
7883 getComputedWidth : function(){
7884 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7886 w = parseInt(this.getStyle('width'), 10) || 0;
7887 if(!this.isBorderBox()){
7888 w += this.getFrameWidth('lr');
7895 * Returns the size of the element.
7896 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7897 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7899 getSize : function(contentSize){
7900 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7904 * Returns the width and height of the viewport.
7905 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7907 getViewSize : function(){
7908 var d = this.dom, doc = document, aw = 0, ah = 0;
7909 if(d == doc || d == doc.body){
7910 return {width : D.getViewWidth(), height: D.getViewHeight()};
7913 width : d.clientWidth,
7914 height: d.clientHeight
7920 * Returns the value of the "value" attribute
7921 * @param {Boolean} asNumber true to parse the value as a number
7922 * @return {String/Number}
7924 getValue : function(asNumber){
7925 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7929 adjustWidth : function(width){
7930 if(typeof width == "number"){
7931 if(this.autoBoxAdjust && !this.isBorderBox()){
7932 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7942 adjustHeight : function(height){
7943 if(typeof height == "number"){
7944 if(this.autoBoxAdjust && !this.isBorderBox()){
7945 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7955 * Set the width of the element
7956 * @param {Number} width The new width
7957 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7958 * @return {Roo.Element} this
7960 setWidth : function(width, animate){
7961 width = this.adjustWidth(width);
7963 this.dom.style.width = this.addUnits(width);
7965 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7971 * Set the height of the element
7972 * @param {Number} height The new height
7973 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7974 * @return {Roo.Element} this
7976 setHeight : function(height, animate){
7977 height = this.adjustHeight(height);
7979 this.dom.style.height = this.addUnits(height);
7981 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7987 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7988 * @param {Number} width The new width
7989 * @param {Number} height The new height
7990 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7991 * @return {Roo.Element} this
7993 setSize : function(width, height, animate){
7994 if(typeof width == "object"){ // in case of object from getSize()
7995 height = width.height; width = width.width;
7997 width = this.adjustWidth(width); height = this.adjustHeight(height);
7999 this.dom.style.width = this.addUnits(width);
8000 this.dom.style.height = this.addUnits(height);
8002 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8008 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8009 * @param {Number} x X value for new position (coordinates are page-based)
8010 * @param {Number} y Y value for new position (coordinates are page-based)
8011 * @param {Number} width The new width
8012 * @param {Number} height The new height
8013 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8014 * @return {Roo.Element} this
8016 setBounds : function(x, y, width, height, animate){
8018 this.setSize(width, height);
8019 this.setLocation(x, y);
8021 width = this.adjustWidth(width); height = this.adjustHeight(height);
8022 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8023 this.preanim(arguments, 4), 'motion');
8029 * 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.
8030 * @param {Roo.lib.Region} region The region to fill
8031 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8032 * @return {Roo.Element} this
8034 setRegion : function(region, animate){
8035 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8040 * Appends an event handler
8042 * @param {String} eventName The type of event to append
8043 * @param {Function} fn The method the event invokes
8044 * @param {Object} scope (optional) The scope (this object) of the fn
8045 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8047 addListener : function(eventName, fn, scope, options){
8049 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8054 * Removes an event handler from this element
8055 * @param {String} eventName the type of event to remove
8056 * @param {Function} fn the method the event invokes
8057 * @return {Roo.Element} this
8059 removeListener : function(eventName, fn){
8060 Roo.EventManager.removeListener(this.dom, eventName, fn);
8065 * Removes all previous added listeners from this element
8066 * @return {Roo.Element} this
8068 removeAllListeners : function(){
8069 E.purgeElement(this.dom);
8073 relayEvent : function(eventName, observable){
8074 this.on(eventName, function(e){
8075 observable.fireEvent(eventName, e);
8080 * Set the opacity of the element
8081 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8082 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8083 * @return {Roo.Element} this
8085 setOpacity : function(opacity, animate){
8087 var s = this.dom.style;
8090 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8091 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8093 s.opacity = opacity;
8096 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8102 * Gets the left X coordinate
8103 * @param {Boolean} local True to get the local css position instead of page coordinate
8106 getLeft : function(local){
8110 return parseInt(this.getStyle("left"), 10) || 0;
8115 * Gets the right X coordinate of the element (element X position + element width)
8116 * @param {Boolean} local True to get the local css position instead of page coordinate
8119 getRight : function(local){
8121 return this.getX() + this.getWidth();
8123 return (this.getLeft(true) + this.getWidth()) || 0;
8128 * Gets the top Y coordinate
8129 * @param {Boolean} local True to get the local css position instead of page coordinate
8132 getTop : function(local) {
8136 return parseInt(this.getStyle("top"), 10) || 0;
8141 * Gets the bottom Y coordinate of the element (element Y position + element height)
8142 * @param {Boolean} local True to get the local css position instead of page coordinate
8145 getBottom : function(local){
8147 return this.getY() + this.getHeight();
8149 return (this.getTop(true) + this.getHeight()) || 0;
8154 * Initializes positioning on this element. If a desired position is not passed, it will make the
8155 * the element positioned relative IF it is not already positioned.
8156 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8157 * @param {Number} zIndex (optional) The zIndex to apply
8158 * @param {Number} x (optional) Set the page X position
8159 * @param {Number} y (optional) Set the page Y position
8161 position : function(pos, zIndex, x, y){
8163 if(this.getStyle('position') == 'static'){
8164 this.setStyle('position', 'relative');
8167 this.setStyle("position", pos);
8170 this.setStyle("z-index", zIndex);
8172 if(x !== undefined && y !== undefined){
8174 }else if(x !== undefined){
8176 }else if(y !== undefined){
8182 * Clear positioning back to the default when the document was loaded
8183 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8184 * @return {Roo.Element} this
8186 clearPositioning : function(value){
8194 "position" : "static"
8200 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8201 * snapshot before performing an update and then restoring the element.
8204 getPositioning : function(){
8205 var l = this.getStyle("left");
8206 var t = this.getStyle("top");
8208 "position" : this.getStyle("position"),
8210 "right" : l ? "" : this.getStyle("right"),
8212 "bottom" : t ? "" : this.getStyle("bottom"),
8213 "z-index" : this.getStyle("z-index")
8218 * Gets the width of the border(s) for the specified side(s)
8219 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8220 * passing lr would get the border (l)eft width + the border (r)ight width.
8221 * @return {Number} The width of the sides passed added together
8223 getBorderWidth : function(side){
8224 return this.addStyles(side, El.borders);
8228 * Gets the width of the padding(s) for the specified side(s)
8229 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8230 * passing lr would get the padding (l)eft + the padding (r)ight.
8231 * @return {Number} The padding of the sides passed added together
8233 getPadding : function(side){
8234 return this.addStyles(side, El.paddings);
8238 * Set positioning with an object returned by getPositioning().
8239 * @param {Object} posCfg
8240 * @return {Roo.Element} this
8242 setPositioning : function(pc){
8243 this.applyStyles(pc);
8244 if(pc.right == "auto"){
8245 this.dom.style.right = "";
8247 if(pc.bottom == "auto"){
8248 this.dom.style.bottom = "";
8254 fixDisplay : function(){
8255 if(this.getStyle("display") == "none"){
8256 this.setStyle("visibility", "hidden");
8257 this.setStyle("display", this.originalDisplay); // first try reverting to default
8258 if(this.getStyle("display") == "none"){ // if that fails, default to block
8259 this.setStyle("display", "block");
8265 * Quick set left and top adding default units
8266 * @param {String} left The left CSS property value
8267 * @param {String} top The top CSS property value
8268 * @return {Roo.Element} this
8270 setLeftTop : function(left, top){
8271 this.dom.style.left = this.addUnits(left);
8272 this.dom.style.top = this.addUnits(top);
8277 * Move this element relative to its current position.
8278 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8279 * @param {Number} distance How far to move the element in pixels
8280 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8281 * @return {Roo.Element} this
8283 move : function(direction, distance, animate){
8284 var xy = this.getXY();
8285 direction = direction.toLowerCase();
8289 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8293 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8298 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8303 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8310 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8311 * @return {Roo.Element} this
8314 if(!this.isClipped){
8315 this.isClipped = true;
8316 this.originalClip = {
8317 "o": this.getStyle("overflow"),
8318 "x": this.getStyle("overflow-x"),
8319 "y": this.getStyle("overflow-y")
8321 this.setStyle("overflow", "hidden");
8322 this.setStyle("overflow-x", "hidden");
8323 this.setStyle("overflow-y", "hidden");
8329 * Return clipping (overflow) to original clipping before clip() was called
8330 * @return {Roo.Element} this
8332 unclip : function(){
8334 this.isClipped = false;
8335 var o = this.originalClip;
8336 if(o.o){this.setStyle("overflow", o.o);}
8337 if(o.x){this.setStyle("overflow-x", o.x);}
8338 if(o.y){this.setStyle("overflow-y", o.y);}
8345 * Gets the x,y coordinates specified by the anchor position on the element.
8346 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8347 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8348 * {width: (target width), height: (target height)} (defaults to the element's current size)
8349 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8350 * @return {Array} [x, y] An array containing the element's x and y coordinates
8352 getAnchorXY : function(anchor, local, s){
8353 //Passing a different size is useful for pre-calculating anchors,
8354 //especially for anchored animations that change the el size.
8356 var w, h, vp = false;
8359 if(d == document.body || d == document){
8361 w = D.getViewWidth(); h = D.getViewHeight();
8363 w = this.getWidth(); h = this.getHeight();
8366 w = s.width; h = s.height;
8368 var x = 0, y = 0, r = Math.round;
8369 switch((anchor || "tl").toLowerCase()){
8411 var sc = this.getScroll();
8412 return [x + sc.left, y + sc.top];
8414 //Add the element's offset xy
8415 var o = this.getXY();
8416 return [x+o[0], y+o[1]];
8420 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8421 * supported position values.
8422 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8423 * @param {String} position The position to align to.
8424 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8425 * @return {Array} [x, y]
8427 getAlignToXY : function(el, p, o){
8431 throw "Element.alignTo with an element that doesn't exist";
8433 var c = false; //constrain to viewport
8434 var p1 = "", p2 = "";
8441 }else if(p.indexOf("-") == -1){
8444 p = p.toLowerCase();
8445 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8447 throw "Element.alignTo with an invalid alignment " + p;
8449 p1 = m[1]; p2 = m[2]; c = !!m[3];
8451 //Subtract the aligned el's internal xy from the target's offset xy
8452 //plus custom offset to get the aligned el's new offset xy
8453 var a1 = this.getAnchorXY(p1, true);
8454 var a2 = el.getAnchorXY(p2, false);
8455 var x = a2[0] - a1[0] + o[0];
8456 var y = a2[1] - a1[1] + o[1];
8458 //constrain the aligned el to viewport if necessary
8459 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8460 // 5px of margin for ie
8461 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8463 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8464 //perpendicular to the vp border, allow the aligned el to slide on that border,
8465 //otherwise swap the aligned el to the opposite border of the target.
8466 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8467 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8468 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8469 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8472 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8473 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8475 if((x+w) > dw + scrollX){
8476 x = swapX ? r.left-w : dw+scrollX-w;
8479 x = swapX ? r.right : scrollX;
8481 if((y+h) > dh + scrollY){
8482 y = swapY ? r.top-h : dh+scrollY-h;
8485 y = swapY ? r.bottom : scrollY;
8492 getConstrainToXY : function(){
8493 var os = {top:0, left:0, bottom:0, right: 0};
8495 return function(el, local, offsets, proposedXY){
8497 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8499 var vw, vh, vx = 0, vy = 0;
8500 if(el.dom == document.body || el.dom == document){
8501 vw = Roo.lib.Dom.getViewWidth();
8502 vh = Roo.lib.Dom.getViewHeight();
8504 vw = el.dom.clientWidth;
8505 vh = el.dom.clientHeight;
8507 var vxy = el.getXY();
8513 var s = el.getScroll();
8515 vx += offsets.left + s.left;
8516 vy += offsets.top + s.top;
8518 vw -= offsets.right;
8519 vh -= offsets.bottom;
8524 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8525 var x = xy[0], y = xy[1];
8526 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8528 // only move it if it needs it
8531 // first validate right/bottom
8540 // then make sure top/left isn't negative
8549 return moved ? [x, y] : false;
8554 adjustForConstraints : function(xy, parent, offsets){
8555 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8559 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8560 * document it aligns it to the viewport.
8561 * The position parameter is optional, and can be specified in any one of the following formats:
8563 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8564 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8565 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8566 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8567 * <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
8568 * element's anchor point, and the second value is used as the target's anchor point.</li>
8570 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8571 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8572 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8573 * that specified in order to enforce the viewport constraints.
8574 * Following are all of the supported anchor positions:
8577 ----- -----------------------------
8578 tl The top left corner (default)
8579 t The center of the top edge
8580 tr The top right corner
8581 l The center of the left edge
8582 c In the center of the element
8583 r The center of the right edge
8584 bl The bottom left corner
8585 b The center of the bottom edge
8586 br The bottom right corner
8590 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8591 el.alignTo("other-el");
8593 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8594 el.alignTo("other-el", "tr?");
8596 // align the bottom right corner of el with the center left edge of other-el
8597 el.alignTo("other-el", "br-l?");
8599 // align the center of el with the bottom left corner of other-el and
8600 // adjust the x position by -6 pixels (and the y position by 0)
8601 el.alignTo("other-el", "c-bl", [-6, 0]);
8603 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8604 * @param {String} position The position to align to.
8605 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 alignTo : function(element, position, offsets, animate){
8610 var xy = this.getAlignToXY(element, position, offsets);
8611 this.setXY(xy, this.preanim(arguments, 3));
8616 * Anchors an element to another element and realigns it when the window is resized.
8617 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8618 * @param {String} position The position to align to.
8619 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8620 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8621 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8622 * is a number, it is used as the buffer delay (defaults to 50ms).
8623 * @param {Function} callback The function to call after the animation finishes
8624 * @return {Roo.Element} this
8626 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8627 var action = function(){
8628 this.alignTo(el, alignment, offsets, animate);
8629 Roo.callback(callback, this);
8631 Roo.EventManager.onWindowResize(action, this);
8632 var tm = typeof monitorScroll;
8633 if(tm != 'undefined'){
8634 Roo.EventManager.on(window, 'scroll', action, this,
8635 {buffer: tm == 'number' ? monitorScroll : 50});
8637 action.call(this); // align immediately
8641 * Clears any opacity settings from this element. Required in some cases for IE.
8642 * @return {Roo.Element} this
8644 clearOpacity : function(){
8645 if (window.ActiveXObject) {
8646 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8647 this.dom.style.filter = "";
8650 this.dom.style.opacity = "";
8651 this.dom.style["-moz-opacity"] = "";
8652 this.dom.style["-khtml-opacity"] = "";
8658 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8659 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8660 * @return {Roo.Element} this
8662 hide : function(animate){
8663 this.setVisible(false, this.preanim(arguments, 0));
8668 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8669 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8670 * @return {Roo.Element} this
8672 show : function(animate){
8673 this.setVisible(true, this.preanim(arguments, 0));
8678 * @private Test if size has a unit, otherwise appends the default
8680 addUnits : function(size){
8681 return Roo.Element.addUnits(size, this.defaultUnit);
8685 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8686 * @return {Roo.Element} this
8688 beginMeasure : function(){
8690 if(el.offsetWidth || el.offsetHeight){
8691 return this; // offsets work already
8694 var p = this.dom, b = document.body; // start with this element
8695 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8696 var pe = Roo.get(p);
8697 if(pe.getStyle('display') == 'none'){
8698 changed.push({el: p, visibility: pe.getStyle("visibility")});
8699 p.style.visibility = "hidden";
8700 p.style.display = "block";
8704 this._measureChanged = changed;
8710 * Restores displays to before beginMeasure was called
8711 * @return {Roo.Element} this
8713 endMeasure : function(){
8714 var changed = this._measureChanged;
8716 for(var i = 0, len = changed.length; i < len; i++) {
8718 r.el.style.visibility = r.visibility;
8719 r.el.style.display = "none";
8721 this._measureChanged = null;
8727 * Update the innerHTML of this element, optionally searching for and processing scripts
8728 * @param {String} html The new HTML
8729 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8730 * @param {Function} callback For async script loading you can be noticed when the update completes
8731 * @return {Roo.Element} this
8733 update : function(html, loadScripts, callback){
8734 if(typeof html == "undefined"){
8737 if(loadScripts !== true){
8738 this.dom.innerHTML = html;
8739 if(typeof callback == "function"){
8747 html += '<span id="' + id + '"></span>';
8749 E.onAvailable(id, function(){
8750 var hd = document.getElementsByTagName("head")[0];
8751 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8752 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8753 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8756 while(match = re.exec(html)){
8757 var attrs = match[1];
8758 var srcMatch = attrs ? attrs.match(srcRe) : false;
8759 if(srcMatch && srcMatch[2]){
8760 var s = document.createElement("script");
8761 s.src = srcMatch[2];
8762 var typeMatch = attrs.match(typeRe);
8763 if(typeMatch && typeMatch[2]){
8764 s.type = typeMatch[2];
8767 }else if(match[2] && match[2].length > 0){
8768 if(window.execScript) {
8769 window.execScript(match[2]);
8777 window.eval(match[2]);
8781 var el = document.getElementById(id);
8782 if(el){el.parentNode.removeChild(el);}
8783 if(typeof callback == "function"){
8787 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8792 * Direct access to the UpdateManager update() method (takes the same parameters).
8793 * @param {String/Function} url The url for this request or a function to call to get the url
8794 * @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}
8795 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8796 * @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.
8797 * @return {Roo.Element} this
8800 var um = this.getUpdateManager();
8801 um.update.apply(um, arguments);
8806 * Gets this element's UpdateManager
8807 * @return {Roo.UpdateManager} The UpdateManager
8809 getUpdateManager : function(){
8810 if(!this.updateManager){
8811 this.updateManager = new Roo.UpdateManager(this);
8813 return this.updateManager;
8817 * Disables text selection for this element (normalized across browsers)
8818 * @return {Roo.Element} this
8820 unselectable : function(){
8821 this.dom.unselectable = "on";
8822 this.swallowEvent("selectstart", true);
8823 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8824 this.addClass("x-unselectable");
8829 * Calculates the x, y to center this element on the screen
8830 * @return {Array} The x, y values [x, y]
8832 getCenterXY : function(){
8833 return this.getAlignToXY(document, 'c-c');
8837 * Centers the Element in either the viewport, or another Element.
8838 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8840 center : function(centerIn){
8841 this.alignTo(centerIn || document, 'c-c');
8846 * Tests various css rules/browsers to determine if this element uses a border box
8849 isBorderBox : function(){
8850 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8854 * Return a box {x, y, width, height} that can be used to set another elements
8855 * size/location to match this element.
8856 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8857 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8858 * @return {Object} box An object in the format {x, y, width, height}
8860 getBox : function(contentBox, local){
8865 var left = parseInt(this.getStyle("left"), 10) || 0;
8866 var top = parseInt(this.getStyle("top"), 10) || 0;
8869 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8871 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8873 var l = this.getBorderWidth("l")+this.getPadding("l");
8874 var r = this.getBorderWidth("r")+this.getPadding("r");
8875 var t = this.getBorderWidth("t")+this.getPadding("t");
8876 var b = this.getBorderWidth("b")+this.getPadding("b");
8877 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)};
8879 bx.right = bx.x + bx.width;
8880 bx.bottom = bx.y + bx.height;
8885 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8886 for more information about the sides.
8887 * @param {String} sides
8890 getFrameWidth : function(sides, onlyContentBox){
8891 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8895 * 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.
8896 * @param {Object} box The box to fill {x, y, width, height}
8897 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8898 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8899 * @return {Roo.Element} this
8901 setBox : function(box, adjust, animate){
8902 var w = box.width, h = box.height;
8903 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8904 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8905 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8907 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8912 * Forces the browser to repaint this element
8913 * @return {Roo.Element} this
8915 repaint : function(){
8917 this.addClass("x-repaint");
8918 setTimeout(function(){
8919 Roo.get(dom).removeClass("x-repaint");
8925 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8926 * then it returns the calculated width of the sides (see getPadding)
8927 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8928 * @return {Object/Number}
8930 getMargins : function(side){
8933 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8934 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8935 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8936 right: parseInt(this.getStyle("margin-right"), 10) || 0
8939 return this.addStyles(side, El.margins);
8944 addStyles : function(sides, styles){
8946 for(var i = 0, len = sides.length; i < len; i++){
8947 v = this.getStyle(styles[sides.charAt(i)]);
8949 w = parseInt(v, 10);
8957 * Creates a proxy element of this element
8958 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8959 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8960 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8961 * @return {Roo.Element} The new proxy element
8963 createProxy : function(config, renderTo, matchBox){
8965 renderTo = Roo.getDom(renderTo);
8967 renderTo = document.body;
8969 config = typeof config == "object" ?
8970 config : {tag : "div", cls: config};
8971 var proxy = Roo.DomHelper.append(renderTo, config, true);
8973 proxy.setBox(this.getBox());
8979 * Puts a mask over this element to disable user interaction. Requires core.css.
8980 * This method can only be applied to elements which accept child nodes.
8981 * @param {String} msg (optional) A message to display in the mask
8982 * @param {String} msgCls (optional) A css class to apply to the msg element
8983 * @return {Element} The mask element
8985 mask : function(msg, msgCls)
8987 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8988 this.setStyle("position", "relative");
8991 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8993 this.addClass("x-masked");
8994 this._mask.setDisplayed(true);
8999 while (dom && dom.style) {
9000 if (!isNaN(parseInt(dom.style.zIndex))) {
9001 z = Math.max(z, parseInt(dom.style.zIndex));
9003 dom = dom.parentNode;
9005 // if we are masking the body - then it hides everything..
9006 if (this.dom == document.body) {
9008 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9009 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9012 if(typeof msg == 'string'){
9014 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9016 var mm = this._maskMsg;
9017 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9018 if (mm.dom.firstChild) { // weird IE issue?
9019 mm.dom.firstChild.innerHTML = msg;
9021 mm.setDisplayed(true);
9023 mm.setStyle('z-index', z + 102);
9025 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9026 this._mask.setHeight(this.getHeight());
9028 this._mask.setStyle('z-index', z + 100);
9034 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9035 * it is cached for reuse.
9037 unmask : function(removeEl){
9039 if(removeEl === true){
9040 this._mask.remove();
9043 this._maskMsg.remove();
9044 delete this._maskMsg;
9047 this._mask.setDisplayed(false);
9049 this._maskMsg.setDisplayed(false);
9053 this.removeClass("x-masked");
9057 * Returns true if this element is masked
9060 isMasked : function(){
9061 return this._mask && this._mask.isVisible();
9065 * Creates an iframe shim for this element to keep selects and other windowed objects from
9067 * @return {Roo.Element} The new shim element
9069 createShim : function(){
9070 var el = document.createElement('iframe');
9071 el.frameBorder = 'no';
9072 el.className = 'roo-shim';
9073 if(Roo.isIE && Roo.isSecure){
9074 el.src = Roo.SSL_SECURE_URL;
9076 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9077 shim.autoBoxAdjust = false;
9082 * Removes this element from the DOM and deletes it from the cache
9084 remove : function(){
9085 if(this.dom.parentNode){
9086 this.dom.parentNode.removeChild(this.dom);
9088 delete El.cache[this.dom.id];
9092 * Sets up event handlers to add and remove a css class when the mouse is over this element
9093 * @param {String} className
9094 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9095 * mouseout events for children elements
9096 * @return {Roo.Element} this
9098 addClassOnOver : function(className, preventFlicker){
9099 this.on("mouseover", function(){
9100 Roo.fly(this, '_internal').addClass(className);
9102 var removeFn = function(e){
9103 if(preventFlicker !== true || !e.within(this, true)){
9104 Roo.fly(this, '_internal').removeClass(className);
9107 this.on("mouseout", removeFn, this.dom);
9112 * Sets up event handlers to add and remove a css class when this element has the focus
9113 * @param {String} className
9114 * @return {Roo.Element} this
9116 addClassOnFocus : function(className){
9117 this.on("focus", function(){
9118 Roo.fly(this, '_internal').addClass(className);
9120 this.on("blur", function(){
9121 Roo.fly(this, '_internal').removeClass(className);
9126 * 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)
9127 * @param {String} className
9128 * @return {Roo.Element} this
9130 addClassOnClick : function(className){
9132 this.on("mousedown", function(){
9133 Roo.fly(dom, '_internal').addClass(className);
9134 var d = Roo.get(document);
9135 var fn = function(){
9136 Roo.fly(dom, '_internal').removeClass(className);
9137 d.removeListener("mouseup", fn);
9139 d.on("mouseup", fn);
9145 * Stops the specified event from bubbling and optionally prevents the default action
9146 * @param {String} eventName
9147 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9148 * @return {Roo.Element} this
9150 swallowEvent : function(eventName, preventDefault){
9151 var fn = function(e){
9152 e.stopPropagation();
9157 if(eventName instanceof Array){
9158 for(var i = 0, len = eventName.length; i < len; i++){
9159 this.on(eventName[i], fn);
9163 this.on(eventName, fn);
9170 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9173 * Sizes this element to its parent element's dimensions performing
9174 * neccessary box adjustments.
9175 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9176 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9177 * @return {Roo.Element} this
9179 fitToParent : function(monitorResize, targetParent) {
9180 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9181 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9182 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9185 var p = Roo.get(targetParent || this.dom.parentNode);
9186 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9187 if (monitorResize === true) {
9188 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9189 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9195 * Gets the next sibling, skipping text nodes
9196 * @return {HTMLElement} The next sibling or null
9198 getNextSibling : function(){
9199 var n = this.dom.nextSibling;
9200 while(n && n.nodeType != 1){
9207 * Gets the previous sibling, skipping text nodes
9208 * @return {HTMLElement} The previous sibling or null
9210 getPrevSibling : function(){
9211 var n = this.dom.previousSibling;
9212 while(n && n.nodeType != 1){
9213 n = n.previousSibling;
9220 * Appends the passed element(s) to this element
9221 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9222 * @return {Roo.Element} this
9224 appendChild: function(el){
9231 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9232 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9233 * automatically generated with the specified attributes.
9234 * @param {HTMLElement} insertBefore (optional) a child element of this element
9235 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9236 * @return {Roo.Element} The new child element
9238 createChild: function(config, insertBefore, returnDom){
9239 config = config || {tag:'div'};
9241 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9243 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9247 * Appends this element to the passed element
9248 * @param {String/HTMLElement/Element} el The new parent element
9249 * @return {Roo.Element} this
9251 appendTo: function(el){
9252 el = Roo.getDom(el);
9253 el.appendChild(this.dom);
9258 * Inserts this element before the passed element in the DOM
9259 * @param {String/HTMLElement/Element} el The element to insert before
9260 * @return {Roo.Element} this
9262 insertBefore: function(el){
9263 el = Roo.getDom(el);
9264 el.parentNode.insertBefore(this.dom, el);
9269 * Inserts this element after the passed element in the DOM
9270 * @param {String/HTMLElement/Element} el The element to insert after
9271 * @return {Roo.Element} this
9273 insertAfter: function(el){
9274 el = Roo.getDom(el);
9275 el.parentNode.insertBefore(this.dom, el.nextSibling);
9280 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9281 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9282 * @return {Roo.Element} The new child
9284 insertFirst: function(el, returnDom){
9286 if(typeof el == 'object' && !el.nodeType){ // dh config
9287 return this.createChild(el, this.dom.firstChild, returnDom);
9289 el = Roo.getDom(el);
9290 this.dom.insertBefore(el, this.dom.firstChild);
9291 return !returnDom ? Roo.get(el) : el;
9296 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9297 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9298 * @param {String} where (optional) 'before' or 'after' defaults to before
9299 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9300 * @return {Roo.Element} the inserted Element
9302 insertSibling: function(el, where, returnDom){
9303 where = where ? where.toLowerCase() : 'before';
9305 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9307 if(typeof el == 'object' && !el.nodeType){ // dh config
9308 if(where == 'after' && !this.dom.nextSibling){
9309 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9311 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9315 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9316 where == 'before' ? this.dom : this.dom.nextSibling);
9325 * Creates and wraps this element with another element
9326 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9327 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9328 * @return {HTMLElement/Element} The newly created wrapper element
9330 wrap: function(config, returnDom){
9332 config = {tag: "div"};
9334 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9335 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9340 * Replaces the passed element with this element
9341 * @param {String/HTMLElement/Element} el The element to replace
9342 * @return {Roo.Element} this
9344 replace: function(el){
9346 this.insertBefore(el);
9352 * Inserts an html fragment into this element
9353 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9354 * @param {String} html The HTML fragment
9355 * @param {Boolean} returnEl True to return an Roo.Element
9356 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9358 insertHtml : function(where, html, returnEl){
9359 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9360 return returnEl ? Roo.get(el) : el;
9364 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9365 * @param {Object} o The object with the attributes
9366 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9367 * @return {Roo.Element} this
9369 set : function(o, useSet){
9371 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9373 if(attr == "style" || typeof o[attr] == "function") continue;
9375 el.className = o["cls"];
9377 if(useSet) el.setAttribute(attr, o[attr]);
9378 else el[attr] = o[attr];
9382 Roo.DomHelper.applyStyles(el, o.style);
9388 * Convenience method for constructing a KeyMap
9389 * @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:
9390 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9391 * @param {Function} fn The function to call
9392 * @param {Object} scope (optional) The scope of the function
9393 * @return {Roo.KeyMap} The KeyMap created
9395 addKeyListener : function(key, fn, scope){
9397 if(typeof key != "object" || key instanceof Array){
9413 return new Roo.KeyMap(this, config);
9417 * Creates a KeyMap for this element
9418 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9419 * @return {Roo.KeyMap} The KeyMap created
9421 addKeyMap : function(config){
9422 return new Roo.KeyMap(this, config);
9426 * Returns true if this element is scrollable.
9429 isScrollable : function(){
9431 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9435 * 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().
9436 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9437 * @param {Number} value The new scroll value
9438 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9439 * @return {Element} this
9442 scrollTo : function(side, value, animate){
9443 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9445 this.dom[prop] = value;
9447 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9448 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9454 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9455 * within this element's scrollable range.
9456 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9457 * @param {Number} distance How far to scroll the element in pixels
9458 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9459 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9460 * was scrolled as far as it could go.
9462 scroll : function(direction, distance, animate){
9463 if(!this.isScrollable()){
9467 var l = el.scrollLeft, t = el.scrollTop;
9468 var w = el.scrollWidth, h = el.scrollHeight;
9469 var cw = el.clientWidth, ch = el.clientHeight;
9470 direction = direction.toLowerCase();
9471 var scrolled = false;
9472 var a = this.preanim(arguments, 2);
9477 var v = Math.min(l + distance, w-cw);
9478 this.scrollTo("left", v, a);
9485 var v = Math.max(l - distance, 0);
9486 this.scrollTo("left", v, a);
9494 var v = Math.max(t - distance, 0);
9495 this.scrollTo("top", v, a);
9503 var v = Math.min(t + distance, h-ch);
9504 this.scrollTo("top", v, a);
9513 * Translates the passed page coordinates into left/top css values for this element
9514 * @param {Number/Array} x The page x or an array containing [x, y]
9515 * @param {Number} y The page y
9516 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9518 translatePoints : function(x, y){
9519 if(typeof x == 'object' || x instanceof Array){
9522 var p = this.getStyle('position');
9523 var o = this.getXY();
9525 var l = parseInt(this.getStyle('left'), 10);
9526 var t = parseInt(this.getStyle('top'), 10);
9529 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9532 t = (p == "relative") ? 0 : this.dom.offsetTop;
9535 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9539 * Returns the current scroll position of the element.
9540 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9542 getScroll : function(){
9543 var d = this.dom, doc = document;
9544 if(d == doc || d == doc.body){
9545 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9546 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9547 return {left: l, top: t};
9549 return {left: d.scrollLeft, top: d.scrollTop};
9554 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9555 * are convert to standard 6 digit hex color.
9556 * @param {String} attr The css attribute
9557 * @param {String} defaultValue The default value to use when a valid color isn't found
9558 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9561 getColor : function(attr, defaultValue, prefix){
9562 var v = this.getStyle(attr);
9563 if(!v || v == "transparent" || v == "inherit") {
9564 return defaultValue;
9566 var color = typeof prefix == "undefined" ? "#" : prefix;
9567 if(v.substr(0, 4) == "rgb("){
9568 var rvs = v.slice(4, v.length -1).split(",");
9569 for(var i = 0; i < 3; i++){
9570 var h = parseInt(rvs[i]).toString(16);
9577 if(v.substr(0, 1) == "#"){
9579 for(var i = 1; i < 4; i++){
9580 var c = v.charAt(i);
9583 }else if(v.length == 7){
9584 color += v.substr(1);
9588 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9592 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9593 * gradient background, rounded corners and a 4-way shadow.
9594 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9595 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9596 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9597 * @return {Roo.Element} this
9599 boxWrap : function(cls){
9600 cls = cls || 'x-box';
9601 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9602 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9607 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9608 * @param {String} namespace The namespace in which to look for the attribute
9609 * @param {String} name The attribute name
9610 * @return {String} The attribute value
9612 getAttributeNS : Roo.isIE ? function(ns, name){
9614 var type = typeof d[ns+":"+name];
9615 if(type != 'undefined' && type != 'unknown'){
9616 return d[ns+":"+name];
9619 } : function(ns, name){
9621 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9626 * Sets or Returns the value the dom attribute value
9627 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9628 * @param {String} value (optional) The value to set the attribute to
9629 * @return {String} The attribute value
9631 attr : function(name){
9632 if (arguments.length > 1) {
9633 this.dom.setAttribute(name, arguments[1]);
9634 return arguments[1];
9636 if (typeof(name) == 'object') {
9637 for(var i in name) {
9638 this.attr(i, name[i]);
9644 if (!this.dom.hasAttribute(name)) {
9647 return this.dom.getAttribute(name);
9654 var ep = El.prototype;
9657 * Appends an event handler (Shorthand for addListener)
9658 * @param {String} eventName The type of event to append
9659 * @param {Function} fn The method the event invokes
9660 * @param {Object} scope (optional) The scope (this object) of the fn
9661 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9664 ep.on = ep.addListener;
9666 ep.mon = ep.addListener;
9669 * Removes an event handler from this element (shorthand for removeListener)
9670 * @param {String} eventName the type of event to remove
9671 * @param {Function} fn the method the event invokes
9672 * @return {Roo.Element} this
9675 ep.un = ep.removeListener;
9678 * true to automatically adjust width and height settings for box-model issues (default to true)
9680 ep.autoBoxAdjust = true;
9683 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9686 El.addUnits = function(v, defaultUnit){
9687 if(v === "" || v == "auto"){
9690 if(v === undefined){
9693 if(typeof v == "number" || !El.unitPattern.test(v)){
9694 return v + (defaultUnit || 'px');
9699 // special markup used throughout Roo when box wrapping elements
9700 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>';
9702 * Visibility mode constant - Use visibility to hide element
9708 * Visibility mode constant - Use display to hide element
9714 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9715 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9716 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9728 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9729 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9730 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9731 * @return {Element} The Element object
9734 El.get = function(el){
9736 if(!el){ return null; }
9737 if(typeof el == "string"){ // element id
9738 if(!(elm = document.getElementById(el))){
9741 if(ex = El.cache[el]){
9744 ex = El.cache[el] = new El(elm);
9747 }else if(el.tagName){ // dom element
9751 if(ex = El.cache[id]){
9754 ex = El.cache[id] = new El(el);
9757 }else if(el instanceof El){
9759 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9760 // catch case where it hasn't been appended
9761 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9764 }else if(el.isComposite){
9766 }else if(el instanceof Array){
9767 return El.select(el);
9768 }else if(el == document){
9769 // create a bogus element object representing the document object
9771 var f = function(){};
9772 f.prototype = El.prototype;
9774 docEl.dom = document;
9782 El.uncache = function(el){
9783 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9785 delete El.cache[a[i].id || a[i]];
9791 // Garbage collection - uncache elements/purge listeners on orphaned elements
9792 // so we don't hold a reference and cause the browser to retain them
9793 El.garbageCollect = function(){
9794 if(!Roo.enableGarbageCollector){
9795 clearInterval(El.collectorThread);
9798 for(var eid in El.cache){
9799 var el = El.cache[eid], d = el.dom;
9800 // -------------------------------------------------------
9801 // Determining what is garbage:
9802 // -------------------------------------------------------
9804 // dom node is null, definitely garbage
9805 // -------------------------------------------------------
9807 // no parentNode == direct orphan, definitely garbage
9808 // -------------------------------------------------------
9809 // !d.offsetParent && !document.getElementById(eid)
9810 // display none elements have no offsetParent so we will
9811 // also try to look it up by it's id. However, check
9812 // offsetParent first so we don't do unneeded lookups.
9813 // This enables collection of elements that are not orphans
9814 // directly, but somewhere up the line they have an orphan
9816 // -------------------------------------------------------
9817 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9818 delete El.cache[eid];
9819 if(d && Roo.enableListenerCollection){
9825 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9829 El.Flyweight = function(dom){
9832 El.Flyweight.prototype = El.prototype;
9834 El._flyweights = {};
9836 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9837 * the dom node can be overwritten by other code.
9838 * @param {String/HTMLElement} el The dom node or id
9839 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9840 * prevent conflicts (e.g. internally Roo uses "_internal")
9842 * @return {Element} The shared Element object
9844 El.fly = function(el, named){
9845 named = named || '_global';
9846 el = Roo.getDom(el);
9850 if(!El._flyweights[named]){
9851 El._flyweights[named] = new El.Flyweight();
9853 El._flyweights[named].dom = el;
9854 return El._flyweights[named];
9858 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9859 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9860 * Shorthand of {@link Roo.Element#get}
9861 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9862 * @return {Element} The Element object
9868 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9869 * the dom node can be overwritten by other code.
9870 * Shorthand of {@link Roo.Element#fly}
9871 * @param {String/HTMLElement} el The dom node or id
9872 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9873 * prevent conflicts (e.g. internally Roo uses "_internal")
9875 * @return {Element} The shared Element object
9881 // speedy lookup for elements never to box adjust
9882 var noBoxAdjust = Roo.isStrict ? {
9885 input:1, select:1, textarea:1
9887 if(Roo.isIE || Roo.isGecko){
9888 noBoxAdjust['button'] = 1;
9892 Roo.EventManager.on(window, 'unload', function(){
9894 delete El._flyweights;
9902 Roo.Element.selectorFunction = Roo.DomQuery.select;
9905 Roo.Element.select = function(selector, unique, root){
9907 if(typeof selector == "string"){
9908 els = Roo.Element.selectorFunction(selector, root);
9909 }else if(selector.length !== undefined){
9912 throw "Invalid selector";
9914 if(unique === true){
9915 return new Roo.CompositeElement(els);
9917 return new Roo.CompositeElementLite(els);
9921 * Selects elements based on the passed CSS selector to enable working on them as 1.
9922 * @param {String/Array} selector The CSS selector or an array of elements
9923 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9924 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9925 * @return {CompositeElementLite/CompositeElement}
9929 Roo.select = Roo.Element.select;
9946 * Ext JS Library 1.1.1
9947 * Copyright(c) 2006-2007, Ext JS, LLC.
9949 * Originally Released Under LGPL - original licence link has changed is not relivant.
9952 * <script type="text/javascript">
9957 //Notifies Element that fx methods are available
9958 Roo.enableFx = true;
9962 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9963 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9964 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9965 * Element effects to work.</p><br/>
9967 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9968 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9969 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9970 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9971 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9972 * expected results and should be done with care.</p><br/>
9974 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9975 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9978 ----- -----------------------------
9979 tl The top left corner
9980 t The center of the top edge
9981 tr The top right corner
9982 l The center of the left edge
9983 r The center of the right edge
9984 bl The bottom left corner
9985 b The center of the bottom edge
9986 br The bottom right corner
9988 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9989 * below are common options that can be passed to any Fx method.</b>
9990 * @cfg {Function} callback A function called when the effect is finished
9991 * @cfg {Object} scope The scope of the effect function
9992 * @cfg {String} easing A valid Easing value for the effect
9993 * @cfg {String} afterCls A css class to apply after the effect
9994 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9995 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9996 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9997 * effects that end with the element being visually hidden, ignored otherwise)
9998 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9999 * a function which returns such a specification that will be applied to the Element after the effect finishes
10000 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10001 * @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
10002 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10006 * Slides the element into view. An anchor point can be optionally passed to set the point of
10007 * origin for the slide effect. This function automatically handles wrapping the element with
10008 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10011 // default: slide the element in from the top
10014 // custom: slide the element in from the right with a 2-second duration
10015 el.slideIn('r', { duration: 2 });
10017 // common config options shown with default values
10023 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10024 * @param {Object} options (optional) Object literal with any of the Fx config options
10025 * @return {Roo.Element} The Element
10027 slideIn : function(anchor, o){
10028 var el = this.getFxEl();
10031 el.queueFx(o, function(){
10033 anchor = anchor || "t";
10035 // fix display to visibility
10038 // restore values after effect
10039 var r = this.getFxRestore();
10040 var b = this.getBox();
10041 // fixed size for slide
10045 var wrap = this.fxWrap(r.pos, o, "hidden");
10047 var st = this.dom.style;
10048 st.visibility = "visible";
10049 st.position = "absolute";
10051 // clear out temp styles after slide and unwrap
10052 var after = function(){
10053 el.fxUnwrap(wrap, r.pos, o);
10054 st.width = r.width;
10055 st.height = r.height;
10058 // time to calc the positions
10059 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10061 switch(anchor.toLowerCase()){
10063 wrap.setSize(b.width, 0);
10064 st.left = st.bottom = "0";
10068 wrap.setSize(0, b.height);
10069 st.right = st.top = "0";
10073 wrap.setSize(0, b.height);
10074 wrap.setX(b.right);
10075 st.left = st.top = "0";
10076 a = {width: bw, points: pt};
10079 wrap.setSize(b.width, 0);
10080 wrap.setY(b.bottom);
10081 st.left = st.top = "0";
10082 a = {height: bh, points: pt};
10085 wrap.setSize(0, 0);
10086 st.right = st.bottom = "0";
10087 a = {width: bw, height: bh};
10090 wrap.setSize(0, 0);
10091 wrap.setY(b.y+b.height);
10092 st.right = st.top = "0";
10093 a = {width: bw, height: bh, points: pt};
10096 wrap.setSize(0, 0);
10097 wrap.setXY([b.right, b.bottom]);
10098 st.left = st.top = "0";
10099 a = {width: bw, height: bh, points: pt};
10102 wrap.setSize(0, 0);
10103 wrap.setX(b.x+b.width);
10104 st.left = st.bottom = "0";
10105 a = {width: bw, height: bh, points: pt};
10108 this.dom.style.visibility = "visible";
10111 arguments.callee.anim = wrap.fxanim(a,
10121 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10122 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10123 * 'hidden') but block elements will still take up space in the document. The element must be removed
10124 * from the DOM using the 'remove' config option if desired. This function automatically handles
10125 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10128 // default: slide the element out to the top
10131 // custom: slide the element out to the right with a 2-second duration
10132 el.slideOut('r', { duration: 2 });
10134 // common config options shown with default values
10142 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10143 * @param {Object} options (optional) Object literal with any of the Fx config options
10144 * @return {Roo.Element} The Element
10146 slideOut : function(anchor, o){
10147 var el = this.getFxEl();
10150 el.queueFx(o, function(){
10152 anchor = anchor || "t";
10154 // restore values after effect
10155 var r = this.getFxRestore();
10157 var b = this.getBox();
10158 // fixed size for slide
10162 var wrap = this.fxWrap(r.pos, o, "visible");
10164 var st = this.dom.style;
10165 st.visibility = "visible";
10166 st.position = "absolute";
10170 var after = function(){
10172 el.setDisplayed(false);
10177 el.fxUnwrap(wrap, r.pos, o);
10179 st.width = r.width;
10180 st.height = r.height;
10185 var a, zero = {to: 0};
10186 switch(anchor.toLowerCase()){
10188 st.left = st.bottom = "0";
10189 a = {height: zero};
10192 st.right = st.top = "0";
10196 st.left = st.top = "0";
10197 a = {width: zero, points: {to:[b.right, b.y]}};
10200 st.left = st.top = "0";
10201 a = {height: zero, points: {to:[b.x, b.bottom]}};
10204 st.right = st.bottom = "0";
10205 a = {width: zero, height: zero};
10208 st.right = st.top = "0";
10209 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10212 st.left = st.top = "0";
10213 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10216 st.left = st.bottom = "0";
10217 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10221 arguments.callee.anim = wrap.fxanim(a,
10231 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10232 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10233 * The element must be removed from the DOM using the 'remove' config option if desired.
10239 // common config options shown with default values
10247 * @param {Object} options (optional) Object literal with any of the Fx config options
10248 * @return {Roo.Element} The Element
10250 puff : function(o){
10251 var el = this.getFxEl();
10254 el.queueFx(o, function(){
10255 this.clearOpacity();
10258 // restore values after effect
10259 var r = this.getFxRestore();
10260 var st = this.dom.style;
10262 var after = function(){
10264 el.setDisplayed(false);
10271 el.setPositioning(r.pos);
10272 st.width = r.width;
10273 st.height = r.height;
10278 var width = this.getWidth();
10279 var height = this.getHeight();
10281 arguments.callee.anim = this.fxanim({
10282 width : {to: this.adjustWidth(width * 2)},
10283 height : {to: this.adjustHeight(height * 2)},
10284 points : {by: [-(width * .5), -(height * .5)]},
10286 fontSize: {to:200, unit: "%"}
10297 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10298 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10299 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10305 // all config options shown with default values
10313 * @param {Object} options (optional) Object literal with any of the Fx config options
10314 * @return {Roo.Element} The Element
10316 switchOff : function(o){
10317 var el = this.getFxEl();
10320 el.queueFx(o, function(){
10321 this.clearOpacity();
10324 // restore values after effect
10325 var r = this.getFxRestore();
10326 var st = this.dom.style;
10328 var after = function(){
10330 el.setDisplayed(false);
10336 el.setPositioning(r.pos);
10337 st.width = r.width;
10338 st.height = r.height;
10343 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10344 this.clearOpacity();
10348 points:{by:[0, this.getHeight() * .5]}
10349 }, o, 'motion', 0.3, 'easeIn', after);
10350 }).defer(100, this);
10357 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10358 * changed using the "attr" config option) and then fading back to the original color. If no original
10359 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10362 // default: highlight background to yellow
10365 // custom: highlight foreground text to blue for 2 seconds
10366 el.highlight("0000ff", { attr: 'color', duration: 2 });
10368 // common config options shown with default values
10369 el.highlight("ffff9c", {
10370 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10371 endColor: (current color) or "ffffff",
10376 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10377 * @param {Object} options (optional) Object literal with any of the Fx config options
10378 * @return {Roo.Element} The Element
10380 highlight : function(color, o){
10381 var el = this.getFxEl();
10384 el.queueFx(o, function(){
10385 color = color || "ffff9c";
10386 attr = o.attr || "backgroundColor";
10388 this.clearOpacity();
10391 var origColor = this.getColor(attr);
10392 var restoreColor = this.dom.style[attr];
10393 endColor = (o.endColor || origColor) || "ffffff";
10395 var after = function(){
10396 el.dom.style[attr] = restoreColor;
10401 a[attr] = {from: color, to: endColor};
10402 arguments.callee.anim = this.fxanim(a,
10412 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10415 // default: a single light blue ripple
10418 // custom: 3 red ripples lasting 3 seconds total
10419 el.frame("ff0000", 3, { duration: 3 });
10421 // common config options shown with default values
10422 el.frame("C3DAF9", 1, {
10423 duration: 1 //duration of entire animation (not each individual ripple)
10424 // Note: Easing is not configurable and will be ignored if included
10427 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10428 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10429 * @param {Object} options (optional) Object literal with any of the Fx config options
10430 * @return {Roo.Element} The Element
10432 frame : function(color, count, o){
10433 var el = this.getFxEl();
10436 el.queueFx(o, function(){
10437 color = color || "#C3DAF9";
10438 if(color.length == 6){
10439 color = "#" + color;
10441 count = count || 1;
10442 duration = o.duration || 1;
10445 var b = this.getBox();
10446 var animFn = function(){
10447 var proxy = this.createProxy({
10450 visbility:"hidden",
10451 position:"absolute",
10452 "z-index":"35000", // yee haw
10453 border:"0px solid " + color
10456 var scale = Roo.isBorderBox ? 2 : 1;
10458 top:{from:b.y, to:b.y - 20},
10459 left:{from:b.x, to:b.x - 20},
10460 borderWidth:{from:0, to:10},
10461 opacity:{from:1, to:0},
10462 height:{from:b.height, to:(b.height + (20*scale))},
10463 width:{from:b.width, to:(b.width + (20*scale))}
10464 }, duration, function(){
10468 animFn.defer((duration/2)*1000, this);
10479 * Creates a pause before any subsequent queued effects begin. If there are
10480 * no effects queued after the pause it will have no effect.
10485 * @param {Number} seconds The length of time to pause (in seconds)
10486 * @return {Roo.Element} The Element
10488 pause : function(seconds){
10489 var el = this.getFxEl();
10492 el.queueFx(o, function(){
10493 setTimeout(function(){
10495 }, seconds * 1000);
10501 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10502 * using the "endOpacity" config option.
10505 // default: fade in from opacity 0 to 100%
10508 // custom: fade in from opacity 0 to 75% over 2 seconds
10509 el.fadeIn({ endOpacity: .75, duration: 2});
10511 // common config options shown with default values
10513 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10518 * @param {Object} options (optional) Object literal with any of the Fx config options
10519 * @return {Roo.Element} The Element
10521 fadeIn : function(o){
10522 var el = this.getFxEl();
10524 el.queueFx(o, function(){
10525 this.setOpacity(0);
10527 this.dom.style.visibility = 'visible';
10528 var to = o.endOpacity || 1;
10529 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10530 o, null, .5, "easeOut", function(){
10532 this.clearOpacity();
10541 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10542 * using the "endOpacity" config option.
10545 // default: fade out from the element's current opacity to 0
10548 // custom: fade out from the element's current opacity to 25% over 2 seconds
10549 el.fadeOut({ endOpacity: .25, duration: 2});
10551 // common config options shown with default values
10553 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10560 * @param {Object} options (optional) Object literal with any of the Fx config options
10561 * @return {Roo.Element} The Element
10563 fadeOut : function(o){
10564 var el = this.getFxEl();
10566 el.queueFx(o, function(){
10567 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10568 o, null, .5, "easeOut", function(){
10569 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10570 this.dom.style.display = "none";
10572 this.dom.style.visibility = "hidden";
10574 this.clearOpacity();
10582 * Animates the transition of an element's dimensions from a starting height/width
10583 * to an ending height/width.
10586 // change height and width to 100x100 pixels
10587 el.scale(100, 100);
10589 // common config options shown with default values. The height and width will default to
10590 // the element's existing values if passed as null.
10593 [element's height], {
10598 * @param {Number} width The new width (pass undefined to keep the original width)
10599 * @param {Number} height The new height (pass undefined to keep the original height)
10600 * @param {Object} options (optional) Object literal with any of the Fx config options
10601 * @return {Roo.Element} The Element
10603 scale : function(w, h, o){
10604 this.shift(Roo.apply({}, o, {
10612 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10613 * Any of these properties not specified in the config object will not be changed. This effect
10614 * requires that at least one new dimension, position or opacity setting must be passed in on
10615 * the config object in order for the function to have any effect.
10618 // slide the element horizontally to x position 200 while changing the height and opacity
10619 el.shift({ x: 200, height: 50, opacity: .8 });
10621 // common config options shown with default values.
10623 width: [element's width],
10624 height: [element's height],
10625 x: [element's x position],
10626 y: [element's y position],
10627 opacity: [element's opacity],
10632 * @param {Object} options Object literal with any of the Fx config options
10633 * @return {Roo.Element} The Element
10635 shift : function(o){
10636 var el = this.getFxEl();
10638 el.queueFx(o, function(){
10639 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10640 if(w !== undefined){
10641 a.width = {to: this.adjustWidth(w)};
10643 if(h !== undefined){
10644 a.height = {to: this.adjustHeight(h)};
10646 if(x !== undefined || y !== undefined){
10648 x !== undefined ? x : this.getX(),
10649 y !== undefined ? y : this.getY()
10652 if(op !== undefined){
10653 a.opacity = {to: op};
10655 if(o.xy !== undefined){
10656 a.points = {to: o.xy};
10658 arguments.callee.anim = this.fxanim(a,
10659 o, 'motion', .35, "easeOut", function(){
10667 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10668 * ending point of the effect.
10671 // default: slide the element downward while fading out
10674 // custom: slide the element out to the right with a 2-second duration
10675 el.ghost('r', { duration: 2 });
10677 // common config options shown with default values
10685 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10686 * @param {Object} options (optional) Object literal with any of the Fx config options
10687 * @return {Roo.Element} The Element
10689 ghost : function(anchor, o){
10690 var el = this.getFxEl();
10693 el.queueFx(o, function(){
10694 anchor = anchor || "b";
10696 // restore values after effect
10697 var r = this.getFxRestore();
10698 var w = this.getWidth(),
10699 h = this.getHeight();
10701 var st = this.dom.style;
10703 var after = function(){
10705 el.setDisplayed(false);
10711 el.setPositioning(r.pos);
10712 st.width = r.width;
10713 st.height = r.height;
10718 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10719 switch(anchor.toLowerCase()){
10746 arguments.callee.anim = this.fxanim(a,
10756 * Ensures that all effects queued after syncFx is called on the element are
10757 * run concurrently. This is the opposite of {@link #sequenceFx}.
10758 * @return {Roo.Element} The Element
10760 syncFx : function(){
10761 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10770 * Ensures that all effects queued after sequenceFx is called on the element are
10771 * run in sequence. This is the opposite of {@link #syncFx}.
10772 * @return {Roo.Element} The Element
10774 sequenceFx : function(){
10775 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10777 concurrent : false,
10784 nextFx : function(){
10785 var ef = this.fxQueue[0];
10792 * Returns true if the element has any effects actively running or queued, else returns false.
10793 * @return {Boolean} True if element has active effects, else false
10795 hasActiveFx : function(){
10796 return this.fxQueue && this.fxQueue[0];
10800 * Stops any running effects and clears the element's internal effects queue if it contains
10801 * any additional effects that haven't started yet.
10802 * @return {Roo.Element} The Element
10804 stopFx : function(){
10805 if(this.hasActiveFx()){
10806 var cur = this.fxQueue[0];
10807 if(cur && cur.anim && cur.anim.isAnimated()){
10808 this.fxQueue = [cur]; // clear out others
10809 cur.anim.stop(true);
10816 beforeFx : function(o){
10817 if(this.hasActiveFx() && !o.concurrent){
10828 * Returns true if the element is currently blocking so that no other effect can be queued
10829 * until this effect is finished, else returns false if blocking is not set. This is commonly
10830 * used to ensure that an effect initiated by a user action runs to completion prior to the
10831 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10832 * @return {Boolean} True if blocking, else false
10834 hasFxBlock : function(){
10835 var q = this.fxQueue;
10836 return q && q[0] && q[0].block;
10840 queueFx : function(o, fn){
10844 if(!this.hasFxBlock()){
10845 Roo.applyIf(o, this.fxDefaults);
10847 var run = this.beforeFx(o);
10848 fn.block = o.block;
10849 this.fxQueue.push(fn);
10861 fxWrap : function(pos, o, vis){
10863 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10866 wrapXY = this.getXY();
10868 var div = document.createElement("div");
10869 div.style.visibility = vis;
10870 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10871 wrap.setPositioning(pos);
10872 if(wrap.getStyle("position") == "static"){
10873 wrap.position("relative");
10875 this.clearPositioning('auto');
10877 wrap.dom.appendChild(this.dom);
10879 wrap.setXY(wrapXY);
10886 fxUnwrap : function(wrap, pos, o){
10887 this.clearPositioning();
10888 this.setPositioning(pos);
10890 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10896 getFxRestore : function(){
10897 var st = this.dom.style;
10898 return {pos: this.getPositioning(), width: st.width, height : st.height};
10902 afterFx : function(o){
10904 this.applyStyles(o.afterStyle);
10907 this.addClass(o.afterCls);
10909 if(o.remove === true){
10912 Roo.callback(o.callback, o.scope, [this]);
10914 this.fxQueue.shift();
10920 getFxEl : function(){ // support for composite element fx
10921 return Roo.get(this.dom);
10925 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10926 animType = animType || 'run';
10928 var anim = Roo.lib.Anim[animType](
10930 (opt.duration || defaultDur) || .35,
10931 (opt.easing || defaultEase) || 'easeOut',
10933 Roo.callback(cb, this);
10942 // backwords compat
10943 Roo.Fx.resize = Roo.Fx.scale;
10945 //When included, Roo.Fx is automatically applied to Element so that all basic
10946 //effects are available directly via the Element API
10947 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10949 * Ext JS Library 1.1.1
10950 * Copyright(c) 2006-2007, Ext JS, LLC.
10952 * Originally Released Under LGPL - original licence link has changed is not relivant.
10955 * <script type="text/javascript">
10960 * @class Roo.CompositeElement
10961 * Standard composite class. Creates a Roo.Element for every element in the collection.
10963 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10964 * actions will be performed on all the elements in this collection.</b>
10966 * All methods return <i>this</i> and can be chained.
10968 var els = Roo.select("#some-el div.some-class", true);
10969 // or select directly from an existing element
10970 var el = Roo.get('some-el');
10971 el.select('div.some-class', true);
10973 els.setWidth(100); // all elements become 100 width
10974 els.hide(true); // all elements fade out and hide
10976 els.setWidth(100).hide(true);
10979 Roo.CompositeElement = function(els){
10980 this.elements = [];
10981 this.addElements(els);
10983 Roo.CompositeElement.prototype = {
10985 addElements : function(els){
10986 if(!els) return this;
10987 if(typeof els == "string"){
10988 els = Roo.Element.selectorFunction(els);
10990 var yels = this.elements;
10991 var index = yels.length-1;
10992 for(var i = 0, len = els.length; i < len; i++) {
10993 yels[++index] = Roo.get(els[i]);
10999 * Clears this composite and adds the elements returned by the passed selector.
11000 * @param {String/Array} els A string CSS selector, an array of elements or an element
11001 * @return {CompositeElement} this
11003 fill : function(els){
11004 this.elements = [];
11010 * Filters this composite to only elements that match the passed selector.
11011 * @param {String} selector A string CSS selector
11012 * @param {Boolean} inverse return inverse filter (not matches)
11013 * @return {CompositeElement} this
11015 filter : function(selector, inverse){
11017 inverse = inverse || false;
11018 this.each(function(el){
11019 var match = inverse ? !el.is(selector) : el.is(selector);
11021 els[els.length] = el.dom;
11028 invoke : function(fn, args){
11029 var els = this.elements;
11030 for(var i = 0, len = els.length; i < len; i++) {
11031 Roo.Element.prototype[fn].apply(els[i], args);
11036 * Adds elements to this composite.
11037 * @param {String/Array} els A string CSS selector, an array of elements or an element
11038 * @return {CompositeElement} this
11040 add : function(els){
11041 if(typeof els == "string"){
11042 this.addElements(Roo.Element.selectorFunction(els));
11043 }else if(els.length !== undefined){
11044 this.addElements(els);
11046 this.addElements([els]);
11051 * Calls the passed function passing (el, this, index) for each element in this composite.
11052 * @param {Function} fn The function to call
11053 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11054 * @return {CompositeElement} this
11056 each : function(fn, scope){
11057 var els = this.elements;
11058 for(var i = 0, len = els.length; i < len; i++){
11059 if(fn.call(scope || els[i], els[i], this, i) === false) {
11067 * Returns the Element object at the specified index
11068 * @param {Number} index
11069 * @return {Roo.Element}
11071 item : function(index){
11072 return this.elements[index] || null;
11076 * Returns the first Element
11077 * @return {Roo.Element}
11079 first : function(){
11080 return this.item(0);
11084 * Returns the last Element
11085 * @return {Roo.Element}
11088 return this.item(this.elements.length-1);
11092 * Returns the number of elements in this composite
11095 getCount : function(){
11096 return this.elements.length;
11100 * Returns true if this composite contains the passed element
11103 contains : function(el){
11104 return this.indexOf(el) !== -1;
11108 * Returns true if this composite contains the passed element
11111 indexOf : function(el){
11112 return this.elements.indexOf(Roo.get(el));
11117 * Removes the specified element(s).
11118 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11119 * or an array of any of those.
11120 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11121 * @return {CompositeElement} this
11123 removeElement : function(el, removeDom){
11124 if(el instanceof Array){
11125 for(var i = 0, len = el.length; i < len; i++){
11126 this.removeElement(el[i]);
11130 var index = typeof el == 'number' ? el : this.indexOf(el);
11133 var d = this.elements[index];
11137 d.parentNode.removeChild(d);
11140 this.elements.splice(index, 1);
11146 * Replaces the specified element with the passed element.
11147 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11149 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11150 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11151 * @return {CompositeElement} this
11153 replaceElement : function(el, replacement, domReplace){
11154 var index = typeof el == 'number' ? el : this.indexOf(el);
11157 this.elements[index].replaceWith(replacement);
11159 this.elements.splice(index, 1, Roo.get(replacement))
11166 * Removes all elements.
11168 clear : function(){
11169 this.elements = [];
11173 Roo.CompositeElement.createCall = function(proto, fnName){
11174 if(!proto[fnName]){
11175 proto[fnName] = function(){
11176 return this.invoke(fnName, arguments);
11180 for(var fnName in Roo.Element.prototype){
11181 if(typeof Roo.Element.prototype[fnName] == "function"){
11182 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11188 * Ext JS Library 1.1.1
11189 * Copyright(c) 2006-2007, Ext JS, LLC.
11191 * Originally Released Under LGPL - original licence link has changed is not relivant.
11194 * <script type="text/javascript">
11198 * @class Roo.CompositeElementLite
11199 * @extends Roo.CompositeElement
11200 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11202 var els = Roo.select("#some-el div.some-class");
11203 // or select directly from an existing element
11204 var el = Roo.get('some-el');
11205 el.select('div.some-class');
11207 els.setWidth(100); // all elements become 100 width
11208 els.hide(true); // all elements fade out and hide
11210 els.setWidth(100).hide(true);
11211 </code></pre><br><br>
11212 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11213 * actions will be performed on all the elements in this collection.</b>
11215 Roo.CompositeElementLite = function(els){
11216 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11217 this.el = new Roo.Element.Flyweight();
11219 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11220 addElements : function(els){
11222 if(els instanceof Array){
11223 this.elements = this.elements.concat(els);
11225 var yels = this.elements;
11226 var index = yels.length-1;
11227 for(var i = 0, len = els.length; i < len; i++) {
11228 yels[++index] = els[i];
11234 invoke : function(fn, args){
11235 var els = this.elements;
11237 for(var i = 0, len = els.length; i < len; i++) {
11239 Roo.Element.prototype[fn].apply(el, args);
11244 * Returns a flyweight Element of the dom element object at the specified index
11245 * @param {Number} index
11246 * @return {Roo.Element}
11248 item : function(index){
11249 if(!this.elements[index]){
11252 this.el.dom = this.elements[index];
11256 // fixes scope with flyweight
11257 addListener : function(eventName, handler, scope, opt){
11258 var els = this.elements;
11259 for(var i = 0, len = els.length; i < len; i++) {
11260 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11266 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11267 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11268 * a reference to the dom node, use el.dom.</b>
11269 * @param {Function} fn The function to call
11270 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11271 * @return {CompositeElement} this
11273 each : function(fn, scope){
11274 var els = this.elements;
11276 for(var i = 0, len = els.length; i < len; i++){
11278 if(fn.call(scope || el, el, this, i) === false){
11285 indexOf : function(el){
11286 return this.elements.indexOf(Roo.getDom(el));
11289 replaceElement : function(el, replacement, domReplace){
11290 var index = typeof el == 'number' ? el : this.indexOf(el);
11292 replacement = Roo.getDom(replacement);
11294 var d = this.elements[index];
11295 d.parentNode.insertBefore(replacement, d);
11296 d.parentNode.removeChild(d);
11298 this.elements.splice(index, 1, replacement);
11303 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11307 * Ext JS Library 1.1.1
11308 * Copyright(c) 2006-2007, Ext JS, LLC.
11310 * Originally Released Under LGPL - original licence link has changed is not relivant.
11313 * <script type="text/javascript">
11319 * @class Roo.data.Connection
11320 * @extends Roo.util.Observable
11321 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11322 * either to a configured URL, or to a URL specified at request time.<br><br>
11324 * Requests made by this class are asynchronous, and will return immediately. No data from
11325 * the server will be available to the statement immediately following the {@link #request} call.
11326 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11328 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11329 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11330 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11331 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11332 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11333 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11334 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11335 * standard DOM methods.
11337 * @param {Object} config a configuration object.
11339 Roo.data.Connection = function(config){
11340 Roo.apply(this, config);
11343 * @event beforerequest
11344 * Fires before a network request is made to retrieve a data object.
11345 * @param {Connection} conn This Connection object.
11346 * @param {Object} options The options config object passed to the {@link #request} method.
11348 "beforerequest" : true,
11350 * @event requestcomplete
11351 * Fires if the request was successfully completed.
11352 * @param {Connection} conn This Connection object.
11353 * @param {Object} response The XHR object containing the response data.
11354 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11355 * @param {Object} options The options config object passed to the {@link #request} method.
11357 "requestcomplete" : true,
11359 * @event requestexception
11360 * Fires if an error HTTP status was returned from the server.
11361 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11362 * @param {Connection} conn This Connection object.
11363 * @param {Object} response The XHR object containing the response data.
11364 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11365 * @param {Object} options The options config object passed to the {@link #request} method.
11367 "requestexception" : true
11369 Roo.data.Connection.superclass.constructor.call(this);
11372 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11374 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11377 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11378 * extra parameters to each request made by this object. (defaults to undefined)
11381 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11382 * to each request made by this object. (defaults to undefined)
11385 * @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)
11388 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11392 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11398 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11401 disableCaching: true,
11404 * Sends an HTTP request to a remote server.
11405 * @param {Object} options An object which may contain the following properties:<ul>
11406 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11407 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11408 * request, a url encoded string or a function to call to get either.</li>
11409 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11410 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11411 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11412 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11413 * <li>options {Object} The parameter to the request call.</li>
11414 * <li>success {Boolean} True if the request succeeded.</li>
11415 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11417 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11418 * The callback is passed the following parameters:<ul>
11419 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11420 * <li>options {Object} The parameter to the request call.</li>
11422 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11423 * The callback is passed the following parameters:<ul>
11424 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11425 * <li>options {Object} The parameter to the request call.</li>
11427 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11428 * for the callback function. Defaults to the browser window.</li>
11429 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11430 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11431 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11432 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11433 * params for the post data. Any params will be appended to the URL.</li>
11434 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11436 * @return {Number} transactionId
11438 request : function(o){
11439 if(this.fireEvent("beforerequest", this, o) !== false){
11442 if(typeof p == "function"){
11443 p = p.call(o.scope||window, o);
11445 if(typeof p == "object"){
11446 p = Roo.urlEncode(o.params);
11448 if(this.extraParams){
11449 var extras = Roo.urlEncode(this.extraParams);
11450 p = p ? (p + '&' + extras) : extras;
11453 var url = o.url || this.url;
11454 if(typeof url == 'function'){
11455 url = url.call(o.scope||window, o);
11459 var form = Roo.getDom(o.form);
11460 url = url || form.action;
11462 var enctype = form.getAttribute("enctype");
11463 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11464 return this.doFormUpload(o, p, url);
11466 var f = Roo.lib.Ajax.serializeForm(form);
11467 p = p ? (p + '&' + f) : f;
11470 var hs = o.headers;
11471 if(this.defaultHeaders){
11472 hs = Roo.apply(hs || {}, this.defaultHeaders);
11479 success: this.handleResponse,
11480 failure: this.handleFailure,
11482 argument: {options: o},
11483 timeout : o.timeout || this.timeout
11486 var method = o.method||this.method||(p ? "POST" : "GET");
11488 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11489 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11492 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11496 }else if(this.autoAbort !== false){
11500 if((method == 'GET' && p) || o.xmlData){
11501 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11504 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11505 return this.transId;
11507 Roo.callback(o.callback, o.scope, [o, null, null]);
11513 * Determine whether this object has a request outstanding.
11514 * @param {Number} transactionId (Optional) defaults to the last transaction
11515 * @return {Boolean} True if there is an outstanding request.
11517 isLoading : function(transId){
11519 return Roo.lib.Ajax.isCallInProgress(transId);
11521 return this.transId ? true : false;
11526 * Aborts any outstanding request.
11527 * @param {Number} transactionId (Optional) defaults to the last transaction
11529 abort : function(transId){
11530 if(transId || this.isLoading()){
11531 Roo.lib.Ajax.abort(transId || this.transId);
11536 handleResponse : function(response){
11537 this.transId = false;
11538 var options = response.argument.options;
11539 response.argument = options ? options.argument : null;
11540 this.fireEvent("requestcomplete", this, response, options);
11541 Roo.callback(options.success, options.scope, [response, options]);
11542 Roo.callback(options.callback, options.scope, [options, true, response]);
11546 handleFailure : function(response, e){
11547 this.transId = false;
11548 var options = response.argument.options;
11549 response.argument = options ? options.argument : null;
11550 this.fireEvent("requestexception", this, response, options, e);
11551 Roo.callback(options.failure, options.scope, [response, options]);
11552 Roo.callback(options.callback, options.scope, [options, false, response]);
11556 doFormUpload : function(o, ps, url){
11558 var frame = document.createElement('iframe');
11561 frame.className = 'x-hidden';
11563 frame.src = Roo.SSL_SECURE_URL;
11565 document.body.appendChild(frame);
11568 document.frames[id].name = id;
11571 var form = Roo.getDom(o.form);
11573 form.method = 'POST';
11574 form.enctype = form.encoding = 'multipart/form-data';
11580 if(ps){ // add dynamic params
11582 ps = Roo.urlDecode(ps, false);
11584 if(ps.hasOwnProperty(k)){
11585 hd = document.createElement('input');
11586 hd.type = 'hidden';
11589 form.appendChild(hd);
11596 var r = { // bogus response object
11601 r.argument = o ? o.argument : null;
11606 doc = frame.contentWindow.document;
11608 doc = (frame.contentDocument || window.frames[id].document);
11610 if(doc && doc.body){
11611 r.responseText = doc.body.innerHTML;
11613 if(doc && doc.XMLDocument){
11614 r.responseXML = doc.XMLDocument;
11616 r.responseXML = doc;
11623 Roo.EventManager.removeListener(frame, 'load', cb, this);
11625 this.fireEvent("requestcomplete", this, r, o);
11626 Roo.callback(o.success, o.scope, [r, o]);
11627 Roo.callback(o.callback, o.scope, [o, true, r]);
11629 setTimeout(function(){document.body.removeChild(frame);}, 100);
11632 Roo.EventManager.on(frame, 'load', cb, this);
11635 if(hiddens){ // remove dynamic params
11636 for(var i = 0, len = hiddens.length; i < len; i++){
11637 form.removeChild(hiddens[i]);
11644 * Ext JS Library 1.1.1
11645 * Copyright(c) 2006-2007, Ext JS, LLC.
11647 * Originally Released Under LGPL - original licence link has changed is not relivant.
11650 * <script type="text/javascript">
11654 * Global Ajax request class.
11657 * @extends Roo.data.Connection
11660 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11661 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11662 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11663 * @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)
11664 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11665 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11666 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11668 Roo.Ajax = new Roo.data.Connection({
11677 * Serialize the passed form into a url encoded string
11679 * @param {String/HTMLElement} form
11682 serializeForm : function(form){
11683 return Roo.lib.Ajax.serializeForm(form);
11687 * Ext JS Library 1.1.1
11688 * Copyright(c) 2006-2007, Ext JS, LLC.
11690 * Originally Released Under LGPL - original licence link has changed is not relivant.
11693 * <script type="text/javascript">
11698 * @class Roo.UpdateManager
11699 * @extends Roo.util.Observable
11700 * Provides AJAX-style update for Element object.<br><br>
11703 * // Get it from a Roo.Element object
11704 * var el = Roo.get("foo");
11705 * var mgr = el.getUpdateManager();
11706 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11708 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11710 * // or directly (returns the same UpdateManager instance)
11711 * var mgr = new Roo.UpdateManager("myElementId");
11712 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11713 * mgr.on("update", myFcnNeedsToKnow);
11715 // short handed call directly from the element object
11716 Roo.get("foo").load({
11720 text: "Loading Foo..."
11724 * Create new UpdateManager directly.
11725 * @param {String/HTMLElement/Roo.Element} el The element to update
11726 * @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).
11728 Roo.UpdateManager = function(el, forceNew){
11730 if(!forceNew && el.updateManager){
11731 return el.updateManager;
11734 * The Element object
11735 * @type Roo.Element
11739 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11742 this.defaultUrl = null;
11746 * @event beforeupdate
11747 * Fired before an update is made, return false from your handler and the update is cancelled.
11748 * @param {Roo.Element} el
11749 * @param {String/Object/Function} url
11750 * @param {String/Object} params
11752 "beforeupdate": true,
11755 * Fired after successful update is made.
11756 * @param {Roo.Element} el
11757 * @param {Object} oResponseObject The response Object
11762 * Fired on update failure.
11763 * @param {Roo.Element} el
11764 * @param {Object} oResponseObject The response Object
11768 var d = Roo.UpdateManager.defaults;
11770 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11773 this.sslBlankUrl = d.sslBlankUrl;
11775 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11778 this.disableCaching = d.disableCaching;
11780 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11783 this.indicatorText = d.indicatorText;
11785 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11788 this.showLoadIndicator = d.showLoadIndicator;
11790 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11793 this.timeout = d.timeout;
11796 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11799 this.loadScripts = d.loadScripts;
11802 * Transaction object of current executing transaction
11804 this.transaction = null;
11809 this.autoRefreshProcId = null;
11811 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11814 this.refreshDelegate = this.refresh.createDelegate(this);
11816 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11819 this.updateDelegate = this.update.createDelegate(this);
11821 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11824 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11828 this.successDelegate = this.processSuccess.createDelegate(this);
11832 this.failureDelegate = this.processFailure.createDelegate(this);
11834 if(!this.renderer){
11836 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11838 this.renderer = new Roo.UpdateManager.BasicRenderer();
11841 Roo.UpdateManager.superclass.constructor.call(this);
11844 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11846 * Get the Element this UpdateManager is bound to
11847 * @return {Roo.Element} The element
11849 getEl : function(){
11853 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11854 * @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:
11857 url: "your-url.php",<br/>
11858 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11859 callback: yourFunction,<br/>
11860 scope: yourObject, //(optional scope) <br/>
11861 discardUrl: false, <br/>
11862 nocache: false,<br/>
11863 text: "Loading...",<br/>
11865 scripts: false<br/>
11868 * The only required property is url. The optional properties nocache, text and scripts
11869 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11870 * @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}
11871 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11872 * @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.
11874 update : function(url, params, callback, discardUrl){
11875 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11876 var method = this.method,
11878 if(typeof url == "object"){ // must be config object
11881 params = params || cfg.params;
11882 callback = callback || cfg.callback;
11883 discardUrl = discardUrl || cfg.discardUrl;
11884 if(callback && cfg.scope){
11885 callback = callback.createDelegate(cfg.scope);
11887 if(typeof cfg.method != "undefined"){method = cfg.method;};
11888 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11889 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11890 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11891 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11893 this.showLoading();
11895 this.defaultUrl = url;
11897 if(typeof url == "function"){
11898 url = url.call(this);
11901 method = method || (params ? "POST" : "GET");
11902 if(method == "GET"){
11903 url = this.prepareUrl(url);
11906 var o = Roo.apply(cfg ||{}, {
11909 success: this.successDelegate,
11910 failure: this.failureDelegate,
11911 callback: undefined,
11912 timeout: (this.timeout*1000),
11913 argument: {"url": url, "form": null, "callback": callback, "params": params}
11915 Roo.log("updated manager called with timeout of " + o.timeout);
11916 this.transaction = Roo.Ajax.request(o);
11921 * 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.
11922 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11923 * @param {String/HTMLElement} form The form Id or form element
11924 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11925 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11926 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11928 formUpdate : function(form, url, reset, callback){
11929 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11930 if(typeof url == "function"){
11931 url = url.call(this);
11933 form = Roo.getDom(form);
11934 this.transaction = Roo.Ajax.request({
11937 success: this.successDelegate,
11938 failure: this.failureDelegate,
11939 timeout: (this.timeout*1000),
11940 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11942 this.showLoading.defer(1, this);
11947 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11948 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11950 refresh : function(callback){
11951 if(this.defaultUrl == null){
11954 this.update(this.defaultUrl, null, callback, true);
11958 * Set this element to auto refresh.
11959 * @param {Number} interval How often to update (in seconds).
11960 * @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)
11961 * @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}
11962 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11963 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11965 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11967 this.update(url || this.defaultUrl, params, callback, true);
11969 if(this.autoRefreshProcId){
11970 clearInterval(this.autoRefreshProcId);
11972 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11976 * Stop auto refresh on this element.
11978 stopAutoRefresh : function(){
11979 if(this.autoRefreshProcId){
11980 clearInterval(this.autoRefreshProcId);
11981 delete this.autoRefreshProcId;
11985 isAutoRefreshing : function(){
11986 return this.autoRefreshProcId ? true : false;
11989 * Called to update the element to "Loading" state. Override to perform custom action.
11991 showLoading : function(){
11992 if(this.showLoadIndicator){
11993 this.el.update(this.indicatorText);
11998 * Adds unique parameter to query string if disableCaching = true
12001 prepareUrl : function(url){
12002 if(this.disableCaching){
12003 var append = "_dc=" + (new Date().getTime());
12004 if(url.indexOf("?") !== -1){
12005 url += "&" + append;
12007 url += "?" + append;
12016 processSuccess : function(response){
12017 this.transaction = null;
12018 if(response.argument.form && response.argument.reset){
12019 try{ // put in try/catch since some older FF releases had problems with this
12020 response.argument.form.reset();
12023 if(this.loadScripts){
12024 this.renderer.render(this.el, response, this,
12025 this.updateComplete.createDelegate(this, [response]));
12027 this.renderer.render(this.el, response, this);
12028 this.updateComplete(response);
12032 updateComplete : function(response){
12033 this.fireEvent("update", this.el, response);
12034 if(typeof response.argument.callback == "function"){
12035 response.argument.callback(this.el, true, response);
12042 processFailure : function(response){
12043 this.transaction = null;
12044 this.fireEvent("failure", this.el, response);
12045 if(typeof response.argument.callback == "function"){
12046 response.argument.callback(this.el, false, response);
12051 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12052 * @param {Object} renderer The object implementing the render() method
12054 setRenderer : function(renderer){
12055 this.renderer = renderer;
12058 getRenderer : function(){
12059 return this.renderer;
12063 * Set the defaultUrl used for updates
12064 * @param {String/Function} defaultUrl The url or a function to call to get the url
12066 setDefaultUrl : function(defaultUrl){
12067 this.defaultUrl = defaultUrl;
12071 * Aborts the executing transaction
12073 abort : function(){
12074 if(this.transaction){
12075 Roo.Ajax.abort(this.transaction);
12080 * Returns true if an update is in progress
12081 * @return {Boolean}
12083 isUpdating : function(){
12084 if(this.transaction){
12085 return Roo.Ajax.isLoading(this.transaction);
12092 * @class Roo.UpdateManager.defaults
12093 * @static (not really - but it helps the doc tool)
12094 * The defaults collection enables customizing the default properties of UpdateManager
12096 Roo.UpdateManager.defaults = {
12098 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12104 * True to process scripts by default (Defaults to false).
12107 loadScripts : false,
12110 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12113 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12115 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12118 disableCaching : false,
12120 * Whether to show indicatorText when loading (Defaults to true).
12123 showLoadIndicator : true,
12125 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12128 indicatorText : '<div class="loading-indicator">Loading...</div>'
12132 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12134 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12135 * @param {String/HTMLElement/Roo.Element} el The element to update
12136 * @param {String} url The url
12137 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12138 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12141 * @member Roo.UpdateManager
12143 Roo.UpdateManager.updateElement = function(el, url, params, options){
12144 var um = Roo.get(el, true).getUpdateManager();
12145 Roo.apply(um, options);
12146 um.update(url, params, options ? options.callback : null);
12148 // alias for backwards compat
12149 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12151 * @class Roo.UpdateManager.BasicRenderer
12152 * Default Content renderer. Updates the elements innerHTML with the responseText.
12154 Roo.UpdateManager.BasicRenderer = function(){};
12156 Roo.UpdateManager.BasicRenderer.prototype = {
12158 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12159 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12160 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12161 * @param {Roo.Element} el The element being rendered
12162 * @param {Object} response The YUI Connect response object
12163 * @param {UpdateManager} updateManager The calling update manager
12164 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12166 render : function(el, response, updateManager, callback){
12167 el.update(response.responseText, updateManager.loadScripts, callback);
12173 * (c)) Alan Knowles
12179 * @class Roo.DomTemplate
12180 * @extends Roo.Template
12181 * An effort at a dom based template engine..
12183 * Similar to XTemplate, except it uses dom parsing to create the template..
12185 * Supported features:
12190 {a_variable} - output encoded.
12191 {a_variable.format:("Y-m-d")} - call a method on the variable
12192 {a_variable:raw} - unencoded output
12193 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12194 {a_variable:this.method_on_template(...)} - call a method on the template object.
12199 <div roo-for="a_variable or condition.."></div>
12200 <div roo-if="a_variable or condition"></div>
12201 <div roo-exec="some javascript"></div>
12202 <div roo-name="named_template"></div>
12207 Roo.DomTemplate = function()
12209 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12216 Roo.extend(Roo.DomTemplate, Roo.Template, {
12218 * id counter for sub templates.
12222 * flag to indicate if dom parser is inside a pre,
12223 * it will strip whitespace if not.
12228 * The various sub templates
12236 * basic tag replacing syntax
12239 * // you can fake an object call by doing this
12243 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12244 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12246 iterChild : function (node, method) {
12248 var oldPre = this.inPre;
12249 if (node.tagName == 'PRE') {
12252 for( var i = 0; i < node.childNodes.length; i++) {
12253 method.call(this, node.childNodes[i]);
12255 this.inPre = oldPre;
12261 * compile the template
12263 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12266 compile: function()
12270 // covert the html into DOM...
12274 doc = document.implementation.createHTMLDocument("");
12275 doc.documentElement.innerHTML = this.html ;
12276 div = doc.documentElement;
12278 // old IE... - nasty -- it causes all sorts of issues.. with
12279 // images getting pulled from server..
12280 div = document.createElement('div');
12281 div.innerHTML = this.html;
12283 //doc.documentElement.innerHTML = htmlBody
12289 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12291 var tpls = this.tpls;
12293 // create a top level template from the snippet..
12295 //Roo.log(div.innerHTML);
12302 body : div.innerHTML,
12315 Roo.each(tpls, function(tp){
12316 this.compileTpl(tp);
12317 this.tpls[tp.id] = tp;
12320 this.master = tpls[0];
12326 compileNode : function(node, istop) {
12331 // skip anything not a tag..
12332 if (node.nodeType != 1) {
12333 if (node.nodeType == 3 && !this.inPre) {
12334 // reduce white space..
12335 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12358 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12359 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12360 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12361 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12367 // just itterate children..
12368 this.iterChild(node,this.compileNode);
12371 tpl.uid = this.id++;
12372 tpl.value = node.getAttribute('roo-' + tpl.attr);
12373 node.removeAttribute('roo-'+ tpl.attr);
12374 if (tpl.attr != 'name') {
12375 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12376 node.parentNode.replaceChild(placeholder, node);
12379 var placeholder = document.createElement('span');
12380 placeholder.className = 'roo-tpl-' + tpl.value;
12381 node.parentNode.replaceChild(placeholder, node);
12384 // parent now sees '{domtplXXXX}
12385 this.iterChild(node,this.compileNode);
12387 // we should now have node body...
12388 var div = document.createElement('div');
12389 div.appendChild(node);
12391 // this has the unfortunate side effect of converting tagged attributes
12392 // eg. href="{...}" into %7C...%7D
12393 // this has been fixed by searching for those combo's although it's a bit hacky..
12396 tpl.body = div.innerHTML;
12403 switch (tpl.value) {
12404 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12405 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12406 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12411 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12415 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12419 tpl.id = tpl.value; // replace non characters???
12425 this.tpls.push(tpl);
12435 * Compile a segment of the template into a 'sub-template'
12441 compileTpl : function(tpl)
12443 var fm = Roo.util.Format;
12444 var useF = this.disableFormats !== true;
12446 var sep = Roo.isGecko ? "+\n" : ",\n";
12448 var undef = function(str) {
12449 Roo.debug && Roo.log("Property not found :" + str);
12453 //Roo.log(tpl.body);
12457 var fn = function(m, lbrace, name, format, args)
12460 //Roo.log(arguments);
12461 args = args ? args.replace(/\\'/g,"'") : args;
12462 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12463 if (typeof(format) == 'undefined') {
12464 format = 'htmlEncode';
12466 if (format == 'raw' ) {
12470 if(name.substr(0, 6) == 'domtpl'){
12471 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12474 // build an array of options to determine if value is undefined..
12476 // basically get 'xxxx.yyyy' then do
12477 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12478 // (function () { Roo.log("Property not found"); return ''; })() :
12483 Roo.each(name.split('.'), function(st) {
12484 lookfor += (lookfor.length ? '.': '') + st;
12485 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12488 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12491 if(format && useF){
12493 args = args ? ',' + args : "";
12495 if(format.substr(0, 5) != "this."){
12496 format = "fm." + format + '(';
12498 format = 'this.call("'+ format.substr(5) + '", ';
12502 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12505 if (args && args.length) {
12506 // called with xxyx.yuu:(test,test)
12508 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12510 // raw.. - :raw modifier..
12511 return "'"+ sep + udef_st + name + ")"+sep+"'";
12515 // branched to use + in gecko and [].join() in others
12517 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12518 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12521 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12522 body.push(tpl.body.replace(/(\r\n|\n)/g,
12523 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12524 body.push("'].join('');};};");
12525 body = body.join('');
12528 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12530 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12537 * same as applyTemplate, except it's done to one of the subTemplates
12538 * when using named templates, you can do:
12540 * var str = pl.applySubTemplate('your-name', values);
12543 * @param {Number} id of the template
12544 * @param {Object} values to apply to template
12545 * @param {Object} parent (normaly the instance of this object)
12547 applySubTemplate : function(id, values, parent)
12551 var t = this.tpls[id];
12555 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12556 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12560 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12567 if(t.execCall && t.execCall.call(this, values, parent)){
12571 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12577 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12578 parent = t.target ? values : parent;
12579 if(t.forCall && vs instanceof Array){
12581 for(var i = 0, len = vs.length; i < len; i++){
12583 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12585 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12587 //Roo.log(t.compiled);
12591 return buf.join('');
12594 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12599 return t.compiled.call(this, vs, parent);
12601 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12603 //Roo.log(t.compiled);
12611 applyTemplate : function(values){
12612 return this.master.compiled.call(this, values, {});
12613 //var s = this.subs;
12616 apply : function(){
12617 return this.applyTemplate.apply(this, arguments);
12622 Roo.DomTemplate.from = function(el){
12623 el = Roo.getDom(el);
12624 return new Roo.Domtemplate(el.value || el.innerHTML);
12627 * Ext JS Library 1.1.1
12628 * Copyright(c) 2006-2007, Ext JS, LLC.
12630 * Originally Released Under LGPL - original licence link has changed is not relivant.
12633 * <script type="text/javascript">
12637 * @class Roo.util.DelayedTask
12638 * Provides a convenient method of performing setTimeout where a new
12639 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12640 * You can use this class to buffer
12641 * the keypress events for a certain number of milliseconds, and perform only if they stop
12642 * for that amount of time.
12643 * @constructor The parameters to this constructor serve as defaults and are not required.
12644 * @param {Function} fn (optional) The default function to timeout
12645 * @param {Object} scope (optional) The default scope of that timeout
12646 * @param {Array} args (optional) The default Array of arguments
12648 Roo.util.DelayedTask = function(fn, scope, args){
12649 var id = null, d, t;
12651 var call = function(){
12652 var now = new Date().getTime();
12656 fn.apply(scope, args || []);
12660 * Cancels any pending timeout and queues a new one
12661 * @param {Number} delay The milliseconds to delay
12662 * @param {Function} newFn (optional) Overrides function passed to constructor
12663 * @param {Object} newScope (optional) Overrides scope passed to constructor
12664 * @param {Array} newArgs (optional) Overrides args passed to constructor
12666 this.delay = function(delay, newFn, newScope, newArgs){
12667 if(id && delay != d){
12671 t = new Date().getTime();
12673 scope = newScope || scope;
12674 args = newArgs || args;
12676 id = setInterval(call, d);
12681 * Cancel the last queued timeout
12683 this.cancel = function(){
12691 * Ext JS Library 1.1.1
12692 * Copyright(c) 2006-2007, Ext JS, LLC.
12694 * Originally Released Under LGPL - original licence link has changed is not relivant.
12697 * <script type="text/javascript">
12701 Roo.util.TaskRunner = function(interval){
12702 interval = interval || 10;
12703 var tasks = [], removeQueue = [];
12705 var running = false;
12707 var stopThread = function(){
12713 var startThread = function(){
12716 id = setInterval(runTasks, interval);
12720 var removeTask = function(task){
12721 removeQueue.push(task);
12727 var runTasks = function(){
12728 if(removeQueue.length > 0){
12729 for(var i = 0, len = removeQueue.length; i < len; i++){
12730 tasks.remove(removeQueue[i]);
12733 if(tasks.length < 1){
12738 var now = new Date().getTime();
12739 for(var i = 0, len = tasks.length; i < len; ++i){
12741 var itime = now - t.taskRunTime;
12742 if(t.interval <= itime){
12743 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12744 t.taskRunTime = now;
12745 if(rt === false || t.taskRunCount === t.repeat){
12750 if(t.duration && t.duration <= (now - t.taskStartTime)){
12757 * Queues a new task.
12758 * @param {Object} task
12760 this.start = function(task){
12762 task.taskStartTime = new Date().getTime();
12763 task.taskRunTime = 0;
12764 task.taskRunCount = 0;
12769 this.stop = function(task){
12774 this.stopAll = function(){
12776 for(var i = 0, len = tasks.length; i < len; i++){
12777 if(tasks[i].onStop){
12786 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12788 * Ext JS Library 1.1.1
12789 * Copyright(c) 2006-2007, Ext JS, LLC.
12791 * Originally Released Under LGPL - original licence link has changed is not relivant.
12794 * <script type="text/javascript">
12799 * @class Roo.util.MixedCollection
12800 * @extends Roo.util.Observable
12801 * A Collection class that maintains both numeric indexes and keys and exposes events.
12803 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12804 * collection (defaults to false)
12805 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12806 * and return the key value for that item. This is used when available to look up the key on items that
12807 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12808 * equivalent to providing an implementation for the {@link #getKey} method.
12810 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12818 * Fires when the collection is cleared.
12823 * Fires when an item is added to the collection.
12824 * @param {Number} index The index at which the item was added.
12825 * @param {Object} o The item added.
12826 * @param {String} key The key associated with the added item.
12831 * Fires when an item is replaced in the collection.
12832 * @param {String} key he key associated with the new added.
12833 * @param {Object} old The item being replaced.
12834 * @param {Object} new The new item.
12839 * Fires when an item is removed from the collection.
12840 * @param {Object} o The item being removed.
12841 * @param {String} key (optional) The key associated with the removed item.
12846 this.allowFunctions = allowFunctions === true;
12848 this.getKey = keyFn;
12850 Roo.util.MixedCollection.superclass.constructor.call(this);
12853 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12854 allowFunctions : false,
12857 * Adds an item to the collection.
12858 * @param {String} key The key to associate with the item
12859 * @param {Object} o The item to add.
12860 * @return {Object} The item added.
12862 add : function(key, o){
12863 if(arguments.length == 1){
12865 key = this.getKey(o);
12867 if(typeof key == "undefined" || key === null){
12869 this.items.push(o);
12870 this.keys.push(null);
12872 var old = this.map[key];
12874 return this.replace(key, o);
12877 this.items.push(o);
12879 this.keys.push(key);
12881 this.fireEvent("add", this.length-1, o, key);
12886 * MixedCollection has a generic way to fetch keys if you implement getKey.
12889 var mc = new Roo.util.MixedCollection();
12890 mc.add(someEl.dom.id, someEl);
12891 mc.add(otherEl.dom.id, otherEl);
12895 var mc = new Roo.util.MixedCollection();
12896 mc.getKey = function(el){
12902 // or via the constructor
12903 var mc = new Roo.util.MixedCollection(false, function(el){
12909 * @param o {Object} The item for which to find the key.
12910 * @return {Object} The key for the passed item.
12912 getKey : function(o){
12917 * Replaces an item in the collection.
12918 * @param {String} key The key associated with the item to replace, or the item to replace.
12919 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12920 * @return {Object} The new item.
12922 replace : function(key, o){
12923 if(arguments.length == 1){
12925 key = this.getKey(o);
12927 var old = this.item(key);
12928 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12929 return this.add(key, o);
12931 var index = this.indexOfKey(key);
12932 this.items[index] = o;
12934 this.fireEvent("replace", key, old, o);
12939 * Adds all elements of an Array or an Object to the collection.
12940 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12941 * an Array of values, each of which are added to the collection.
12943 addAll : function(objs){
12944 if(arguments.length > 1 || objs instanceof Array){
12945 var args = arguments.length > 1 ? arguments : objs;
12946 for(var i = 0, len = args.length; i < len; i++){
12950 for(var key in objs){
12951 if(this.allowFunctions || typeof objs[key] != "function"){
12952 this.add(key, objs[key]);
12959 * Executes the specified function once for every item in the collection, passing each
12960 * item as the first and only parameter. returning false from the function will stop the iteration.
12961 * @param {Function} fn The function to execute for each item.
12962 * @param {Object} scope (optional) The scope in which to execute the function.
12964 each : function(fn, scope){
12965 var items = [].concat(this.items); // each safe for removal
12966 for(var i = 0, len = items.length; i < len; i++){
12967 if(fn.call(scope || items[i], items[i], i, len) === false){
12974 * Executes the specified function once for every key in the collection, passing each
12975 * key, and its associated item as the first two parameters.
12976 * @param {Function} fn The function to execute for each item.
12977 * @param {Object} scope (optional) The scope in which to execute the function.
12979 eachKey : function(fn, scope){
12980 for(var i = 0, len = this.keys.length; i < len; i++){
12981 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12986 * Returns the first item in the collection which elicits a true return value from the
12987 * passed selection function.
12988 * @param {Function} fn The selection function to execute for each item.
12989 * @param {Object} scope (optional) The scope in which to execute the function.
12990 * @return {Object} The first item in the collection which returned true from the selection function.
12992 find : function(fn, scope){
12993 for(var i = 0, len = this.items.length; i < len; i++){
12994 if(fn.call(scope || window, this.items[i], this.keys[i])){
12995 return this.items[i];
13002 * Inserts an item at the specified index in the collection.
13003 * @param {Number} index The index to insert the item at.
13004 * @param {String} key The key to associate with the new item, or the item itself.
13005 * @param {Object} o (optional) If the second parameter was a key, the new item.
13006 * @return {Object} The item inserted.
13008 insert : function(index, key, o){
13009 if(arguments.length == 2){
13011 key = this.getKey(o);
13013 if(index >= this.length){
13014 return this.add(key, o);
13017 this.items.splice(index, 0, o);
13018 if(typeof key != "undefined" && key != null){
13021 this.keys.splice(index, 0, key);
13022 this.fireEvent("add", index, o, key);
13027 * Removed an item from the collection.
13028 * @param {Object} o The item to remove.
13029 * @return {Object} The item removed.
13031 remove : function(o){
13032 return this.removeAt(this.indexOf(o));
13036 * Remove an item from a specified index in the collection.
13037 * @param {Number} index The index within the collection of the item to remove.
13039 removeAt : function(index){
13040 if(index < this.length && index >= 0){
13042 var o = this.items[index];
13043 this.items.splice(index, 1);
13044 var key = this.keys[index];
13045 if(typeof key != "undefined"){
13046 delete this.map[key];
13048 this.keys.splice(index, 1);
13049 this.fireEvent("remove", o, key);
13054 * Removed an item associated with the passed key fom the collection.
13055 * @param {String} key The key of the item to remove.
13057 removeKey : function(key){
13058 return this.removeAt(this.indexOfKey(key));
13062 * Returns the number of items in the collection.
13063 * @return {Number} the number of items in the collection.
13065 getCount : function(){
13066 return this.length;
13070 * Returns index within the collection of the passed Object.
13071 * @param {Object} o The item to find the index of.
13072 * @return {Number} index of the item.
13074 indexOf : function(o){
13075 if(!this.items.indexOf){
13076 for(var i = 0, len = this.items.length; i < len; i++){
13077 if(this.items[i] == o) return i;
13081 return this.items.indexOf(o);
13086 * Returns index within the collection of the passed key.
13087 * @param {String} key The key to find the index of.
13088 * @return {Number} index of the key.
13090 indexOfKey : function(key){
13091 if(!this.keys.indexOf){
13092 for(var i = 0, len = this.keys.length; i < len; i++){
13093 if(this.keys[i] == key) return i;
13097 return this.keys.indexOf(key);
13102 * Returns the item associated with the passed key OR index. Key has priority over index.
13103 * @param {String/Number} key The key or index of the item.
13104 * @return {Object} The item associated with the passed key.
13106 item : function(key){
13107 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13108 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13112 * Returns the item at the specified index.
13113 * @param {Number} index The index of the item.
13116 itemAt : function(index){
13117 return this.items[index];
13121 * Returns the item associated with the passed key.
13122 * @param {String/Number} key The key of the item.
13123 * @return {Object} The item associated with the passed key.
13125 key : function(key){
13126 return this.map[key];
13130 * Returns true if the collection contains the passed Object as an item.
13131 * @param {Object} o The Object to look for in the collection.
13132 * @return {Boolean} True if the collection contains the Object as an item.
13134 contains : function(o){
13135 return this.indexOf(o) != -1;
13139 * Returns true if the collection contains the passed Object as a key.
13140 * @param {String} key The key to look for in the collection.
13141 * @return {Boolean} True if the collection contains the Object as a key.
13143 containsKey : function(key){
13144 return typeof this.map[key] != "undefined";
13148 * Removes all items from the collection.
13150 clear : function(){
13155 this.fireEvent("clear");
13159 * Returns the first item in the collection.
13160 * @return {Object} the first item in the collection..
13162 first : function(){
13163 return this.items[0];
13167 * Returns the last item in the collection.
13168 * @return {Object} the last item in the collection..
13171 return this.items[this.length-1];
13174 _sort : function(property, dir, fn){
13175 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13176 fn = fn || function(a, b){
13179 var c = [], k = this.keys, items = this.items;
13180 for(var i = 0, len = items.length; i < len; i++){
13181 c[c.length] = {key: k[i], value: items[i], index: i};
13183 c.sort(function(a, b){
13184 var v = fn(a[property], b[property]) * dsc;
13186 v = (a.index < b.index ? -1 : 1);
13190 for(var i = 0, len = c.length; i < len; i++){
13191 items[i] = c[i].value;
13194 this.fireEvent("sort", this);
13198 * Sorts this collection with the passed comparison function
13199 * @param {String} direction (optional) "ASC" or "DESC"
13200 * @param {Function} fn (optional) comparison function
13202 sort : function(dir, fn){
13203 this._sort("value", dir, fn);
13207 * Sorts this collection by keys
13208 * @param {String} direction (optional) "ASC" or "DESC"
13209 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13211 keySort : function(dir, fn){
13212 this._sort("key", dir, fn || function(a, b){
13213 return String(a).toUpperCase()-String(b).toUpperCase();
13218 * Returns a range of items in this collection
13219 * @param {Number} startIndex (optional) defaults to 0
13220 * @param {Number} endIndex (optional) default to the last item
13221 * @return {Array} An array of items
13223 getRange : function(start, end){
13224 var items = this.items;
13225 if(items.length < 1){
13228 start = start || 0;
13229 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13232 for(var i = start; i <= end; i++) {
13233 r[r.length] = items[i];
13236 for(var i = start; i >= end; i--) {
13237 r[r.length] = items[i];
13244 * Filter the <i>objects</i> in this collection by a specific property.
13245 * Returns a new collection that has been filtered.
13246 * @param {String} property A property on your objects
13247 * @param {String/RegExp} value Either string that the property values
13248 * should start with or a RegExp to test against the property
13249 * @return {MixedCollection} The new filtered collection
13251 filter : function(property, value){
13252 if(!value.exec){ // not a regex
13253 value = String(value);
13254 if(value.length == 0){
13255 return this.clone();
13257 value = new RegExp("^" + Roo.escapeRe(value), "i");
13259 return this.filterBy(function(o){
13260 return o && value.test(o[property]);
13265 * Filter by a function. * Returns a new collection that has been filtered.
13266 * The passed function will be called with each
13267 * object in the collection. If the function returns true, the value is included
13268 * otherwise it is filtered.
13269 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13270 * @param {Object} scope (optional) The scope of the function (defaults to this)
13271 * @return {MixedCollection} The new filtered collection
13273 filterBy : function(fn, scope){
13274 var r = new Roo.util.MixedCollection();
13275 r.getKey = this.getKey;
13276 var k = this.keys, it = this.items;
13277 for(var i = 0, len = it.length; i < len; i++){
13278 if(fn.call(scope||this, it[i], k[i])){
13279 r.add(k[i], it[i]);
13286 * Creates a duplicate of this collection
13287 * @return {MixedCollection}
13289 clone : function(){
13290 var r = new Roo.util.MixedCollection();
13291 var k = this.keys, it = this.items;
13292 for(var i = 0, len = it.length; i < len; i++){
13293 r.add(k[i], it[i]);
13295 r.getKey = this.getKey;
13300 * Returns the item associated with the passed key or index.
13302 * @param {String/Number} key The key or index of the item.
13303 * @return {Object} The item associated with the passed key.
13305 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13307 * Ext JS Library 1.1.1
13308 * Copyright(c) 2006-2007, Ext JS, LLC.
13310 * Originally Released Under LGPL - original licence link has changed is not relivant.
13313 * <script type="text/javascript">
13316 * @class Roo.util.JSON
13317 * Modified version of Douglas Crockford"s json.js that doesn"t
13318 * mess with the Object prototype
13319 * http://www.json.org/js.html
13322 Roo.util.JSON = new (function(){
13323 var useHasOwn = {}.hasOwnProperty ? true : false;
13325 // crashes Safari in some instances
13326 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13328 var pad = function(n) {
13329 return n < 10 ? "0" + n : n;
13342 var encodeString = function(s){
13343 if (/["\\\x00-\x1f]/.test(s)) {
13344 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13349 c = b.charCodeAt();
13351 Math.floor(c / 16).toString(16) +
13352 (c % 16).toString(16);
13355 return '"' + s + '"';
13358 var encodeArray = function(o){
13359 var a = ["["], b, i, l = o.length, v;
13360 for (i = 0; i < l; i += 1) {
13362 switch (typeof v) {
13371 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13379 var encodeDate = function(o){
13380 return '"' + o.getFullYear() + "-" +
13381 pad(o.getMonth() + 1) + "-" +
13382 pad(o.getDate()) + "T" +
13383 pad(o.getHours()) + ":" +
13384 pad(o.getMinutes()) + ":" +
13385 pad(o.getSeconds()) + '"';
13389 * Encodes an Object, Array or other value
13390 * @param {Mixed} o The variable to encode
13391 * @return {String} The JSON string
13393 this.encode = function(o)
13395 // should this be extended to fully wrap stringify..
13397 if(typeof o == "undefined" || o === null){
13399 }else if(o instanceof Array){
13400 return encodeArray(o);
13401 }else if(o instanceof Date){
13402 return encodeDate(o);
13403 }else if(typeof o == "string"){
13404 return encodeString(o);
13405 }else if(typeof o == "number"){
13406 return isFinite(o) ? String(o) : "null";
13407 }else if(typeof o == "boolean"){
13410 var a = ["{"], b, i, v;
13412 if(!useHasOwn || o.hasOwnProperty(i)) {
13414 switch (typeof v) {
13423 a.push(this.encode(i), ":",
13424 v === null ? "null" : this.encode(v));
13435 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13436 * @param {String} json The JSON string
13437 * @return {Object} The resulting object
13439 this.decode = function(json){
13441 return /** eval:var:json */ eval("(" + json + ')');
13445 * Shorthand for {@link Roo.util.JSON#encode}
13446 * @member Roo encode
13448 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13450 * Shorthand for {@link Roo.util.JSON#decode}
13451 * @member Roo decode
13453 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13456 * Ext JS Library 1.1.1
13457 * Copyright(c) 2006-2007, Ext JS, LLC.
13459 * Originally Released Under LGPL - original licence link has changed is not relivant.
13462 * <script type="text/javascript">
13466 * @class Roo.util.Format
13467 * Reusable data formatting functions
13470 Roo.util.Format = function(){
13471 var trimRe = /^\s+|\s+$/g;
13474 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13475 * @param {String} value The string to truncate
13476 * @param {Number} length The maximum length to allow before truncating
13477 * @return {String} The converted text
13479 ellipsis : function(value, len){
13480 if(value && value.length > len){
13481 return value.substr(0, len-3)+"...";
13487 * Checks a reference and converts it to empty string if it is undefined
13488 * @param {Mixed} value Reference to check
13489 * @return {Mixed} Empty string if converted, otherwise the original value
13491 undef : function(value){
13492 return typeof value != "undefined" ? value : "";
13496 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13497 * @param {String} value The string to encode
13498 * @return {String} The encoded text
13500 htmlEncode : function(value){
13501 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13505 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13506 * @param {String} value The string to decode
13507 * @return {String} The decoded text
13509 htmlDecode : function(value){
13510 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13514 * Trims any whitespace from either side of a string
13515 * @param {String} value The text to trim
13516 * @return {String} The trimmed text
13518 trim : function(value){
13519 return String(value).replace(trimRe, "");
13523 * Returns a substring from within an original string
13524 * @param {String} value The original text
13525 * @param {Number} start The start index of the substring
13526 * @param {Number} length The length of the substring
13527 * @return {String} The substring
13529 substr : function(value, start, length){
13530 return String(value).substr(start, length);
13534 * Converts a string to all lower case letters
13535 * @param {String} value The text to convert
13536 * @return {String} The converted text
13538 lowercase : function(value){
13539 return String(value).toLowerCase();
13543 * Converts a string to all upper case letters
13544 * @param {String} value The text to convert
13545 * @return {String} The converted text
13547 uppercase : function(value){
13548 return String(value).toUpperCase();
13552 * Converts the first character only of a string to upper case
13553 * @param {String} value The text to convert
13554 * @return {String} The converted text
13556 capitalize : function(value){
13557 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13561 call : function(value, fn){
13562 if(arguments.length > 2){
13563 var args = Array.prototype.slice.call(arguments, 2);
13564 args.unshift(value);
13566 return /** eval:var:value */ eval(fn).apply(window, args);
13568 /** eval:var:value */
13569 return /** eval:var:value */ eval(fn).call(window, value);
13575 * safer version of Math.toFixed..??/
13576 * @param {Number/String} value The numeric value to format
13577 * @param {Number/String} value Decimal places
13578 * @return {String} The formatted currency string
13580 toFixed : function(v, n)
13582 // why not use to fixed - precision is buggered???
13584 return Math.round(v-0);
13586 var fact = Math.pow(10,n+1);
13587 v = (Math.round((v-0)*fact))/fact;
13588 var z = (''+fact).substring(2);
13589 if (v == Math.floor(v)) {
13590 return Math.floor(v) + '.' + z;
13593 // now just padd decimals..
13594 var ps = String(v).split('.');
13595 var fd = (ps[1] + z);
13596 var r = fd.substring(0,n);
13597 var rm = fd.substring(n);
13599 return ps[0] + '.' + r;
13601 r*=1; // turn it into a number;
13603 if (String(r).length != n) {
13606 r = String(r).substring(1); // chop the end off.
13609 return ps[0] + '.' + r;
13614 * Format a number as US currency
13615 * @param {Number/String} value The numeric value to format
13616 * @return {String} The formatted currency string
13618 usMoney : function(v){
13619 return '$' + Roo.util.Format.number(v);
13624 * eventually this should probably emulate php's number_format
13625 * @param {Number/String} value The numeric value to format
13626 * @param {Number} decimals number of decimal places
13627 * @return {String} The formatted currency string
13629 number : function(v,decimals)
13631 // multiply and round.
13632 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13633 var mul = Math.pow(10, decimals);
13634 var zero = String(mul).substring(1);
13635 v = (Math.round((v-0)*mul))/mul;
13637 // if it's '0' number.. then
13639 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13641 var ps = v.split('.');
13645 var r = /(\d+)(\d{3})/;
13647 while (r.test(whole)) {
13648 whole = whole.replace(r, '$1' + ',' + '$2');
13654 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13655 // does not have decimals
13656 (decimals ? ('.' + zero) : '');
13659 return whole + sub ;
13663 * Parse a value into a formatted date using the specified format pattern.
13664 * @param {Mixed} value The value to format
13665 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13666 * @return {String} The formatted date string
13668 date : function(v, format){
13672 if(!(v instanceof Date)){
13673 v = new Date(Date.parse(v));
13675 return v.dateFormat(format || Roo.util.Format.defaults.date);
13679 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13680 * @param {String} format Any valid date format string
13681 * @return {Function} The date formatting function
13683 dateRenderer : function(format){
13684 return function(v){
13685 return Roo.util.Format.date(v, format);
13690 stripTagsRE : /<\/?[^>]+>/gi,
13693 * Strips all HTML tags
13694 * @param {Mixed} value The text from which to strip tags
13695 * @return {String} The stripped text
13697 stripTags : function(v){
13698 return !v ? v : String(v).replace(this.stripTagsRE, "");
13702 Roo.util.Format.defaults = {
13706 * Ext JS Library 1.1.1
13707 * Copyright(c) 2006-2007, Ext JS, LLC.
13709 * Originally Released Under LGPL - original licence link has changed is not relivant.
13712 * <script type="text/javascript">
13719 * @class Roo.MasterTemplate
13720 * @extends Roo.Template
13721 * Provides a template that can have child templates. The syntax is:
13723 var t = new Roo.MasterTemplate(
13724 '<select name="{name}">',
13725 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13728 t.add('options', {value: 'foo', text: 'bar'});
13729 // or you can add multiple child elements in one shot
13730 t.addAll('options', [
13731 {value: 'foo', text: 'bar'},
13732 {value: 'foo2', text: 'bar2'},
13733 {value: 'foo3', text: 'bar3'}
13735 // then append, applying the master template values
13736 t.append('my-form', {name: 'my-select'});
13738 * A name attribute for the child template is not required if you have only one child
13739 * template or you want to refer to them by index.
13741 Roo.MasterTemplate = function(){
13742 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13743 this.originalHtml = this.html;
13745 var m, re = this.subTemplateRe;
13748 while(m = re.exec(this.html)){
13749 var name = m[1], content = m[2];
13754 tpl : new Roo.Template(content)
13757 st[name] = st[subIndex];
13759 st[subIndex].tpl.compile();
13760 st[subIndex].tpl.call = this.call.createDelegate(this);
13763 this.subCount = subIndex;
13766 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13768 * The regular expression used to match sub templates
13772 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13775 * Applies the passed values to a child template.
13776 * @param {String/Number} name (optional) The name or index of the child template
13777 * @param {Array/Object} values The values to be applied to the template
13778 * @return {MasterTemplate} this
13780 add : function(name, values){
13781 if(arguments.length == 1){
13782 values = arguments[0];
13785 var s = this.subs[name];
13786 s.buffer[s.buffer.length] = s.tpl.apply(values);
13791 * Applies all the passed values to a child template.
13792 * @param {String/Number} name (optional) The name or index of the child template
13793 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13794 * @param {Boolean} reset (optional) True to reset the template first
13795 * @return {MasterTemplate} this
13797 fill : function(name, values, reset){
13799 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13807 for(var i = 0, len = values.length; i < len; i++){
13808 this.add(name, values[i]);
13814 * Resets the template for reuse
13815 * @return {MasterTemplate} this
13817 reset : function(){
13819 for(var i = 0; i < this.subCount; i++){
13825 applyTemplate : function(values){
13827 var replaceIndex = -1;
13828 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13829 return s[++replaceIndex].buffer.join("");
13831 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13834 apply : function(){
13835 return this.applyTemplate.apply(this, arguments);
13838 compile : function(){return this;}
13842 * Alias for fill().
13845 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13847 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13848 * var tpl = Roo.MasterTemplate.from('element-id');
13849 * @param {String/HTMLElement} el
13850 * @param {Object} config
13853 Roo.MasterTemplate.from = function(el, config){
13854 el = Roo.getDom(el);
13855 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13858 * Ext JS Library 1.1.1
13859 * Copyright(c) 2006-2007, Ext JS, LLC.
13861 * Originally Released Under LGPL - original licence link has changed is not relivant.
13864 * <script type="text/javascript">
13869 * @class Roo.util.CSS
13870 * Utility class for manipulating CSS rules
13873 Roo.util.CSS = function(){
13875 var doc = document;
13877 var camelRe = /(-[a-z])/gi;
13878 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13882 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13883 * tag and appended to the HEAD of the document.
13884 * @param {String|Object} cssText The text containing the css rules
13885 * @param {String} id An id to add to the stylesheet for later removal
13886 * @return {StyleSheet}
13888 createStyleSheet : function(cssText, id){
13890 var head = doc.getElementsByTagName("head")[0];
13891 var nrules = doc.createElement("style");
13892 nrules.setAttribute("type", "text/css");
13894 nrules.setAttribute("id", id);
13896 if (typeof(cssText) != 'string') {
13897 // support object maps..
13898 // not sure if this a good idea..
13899 // perhaps it should be merged with the general css handling
13900 // and handle js style props.
13901 var cssTextNew = [];
13902 for(var n in cssText) {
13904 for(var k in cssText[n]) {
13905 citems.push( k + ' : ' +cssText[n][k] + ';' );
13907 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13910 cssText = cssTextNew.join("\n");
13916 head.appendChild(nrules);
13917 ss = nrules.styleSheet;
13918 ss.cssText = cssText;
13921 nrules.appendChild(doc.createTextNode(cssText));
13923 nrules.cssText = cssText;
13925 head.appendChild(nrules);
13926 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13928 this.cacheStyleSheet(ss);
13933 * Removes a style or link tag by id
13934 * @param {String} id The id of the tag
13936 removeStyleSheet : function(id){
13937 var existing = doc.getElementById(id);
13939 existing.parentNode.removeChild(existing);
13944 * Dynamically swaps an existing stylesheet reference for a new one
13945 * @param {String} id The id of an existing link tag to remove
13946 * @param {String} url The href of the new stylesheet to include
13948 swapStyleSheet : function(id, url){
13949 this.removeStyleSheet(id);
13950 var ss = doc.createElement("link");
13951 ss.setAttribute("rel", "stylesheet");
13952 ss.setAttribute("type", "text/css");
13953 ss.setAttribute("id", id);
13954 ss.setAttribute("href", url);
13955 doc.getElementsByTagName("head")[0].appendChild(ss);
13959 * Refresh the rule cache if you have dynamically added stylesheets
13960 * @return {Object} An object (hash) of rules indexed by selector
13962 refreshCache : function(){
13963 return this.getRules(true);
13967 cacheStyleSheet : function(stylesheet){
13971 try{// try catch for cross domain access issue
13972 var ssRules = stylesheet.cssRules || stylesheet.rules;
13973 for(var j = ssRules.length-1; j >= 0; --j){
13974 rules[ssRules[j].selectorText] = ssRules[j];
13980 * Gets all css rules for the document
13981 * @param {Boolean} refreshCache true to refresh the internal cache
13982 * @return {Object} An object (hash) of rules indexed by selector
13984 getRules : function(refreshCache){
13985 if(rules == null || refreshCache){
13987 var ds = doc.styleSheets;
13988 for(var i =0, len = ds.length; i < len; i++){
13990 this.cacheStyleSheet(ds[i]);
13998 * Gets an an individual CSS rule by selector(s)
13999 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14000 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14001 * @return {CSSRule} The CSS rule or null if one is not found
14003 getRule : function(selector, refreshCache){
14004 var rs = this.getRules(refreshCache);
14005 if(!(selector instanceof Array)){
14006 return rs[selector];
14008 for(var i = 0; i < selector.length; i++){
14009 if(rs[selector[i]]){
14010 return rs[selector[i]];
14018 * Updates a rule property
14019 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14020 * @param {String} property The css property
14021 * @param {String} value The new value for the property
14022 * @return {Boolean} true If a rule was found and updated
14024 updateRule : function(selector, property, value){
14025 if(!(selector instanceof Array)){
14026 var rule = this.getRule(selector);
14028 rule.style[property.replace(camelRe, camelFn)] = value;
14032 for(var i = 0; i < selector.length; i++){
14033 if(this.updateRule(selector[i], property, value)){
14043 * Ext JS Library 1.1.1
14044 * Copyright(c) 2006-2007, Ext JS, LLC.
14046 * Originally Released Under LGPL - original licence link has changed is not relivant.
14049 * <script type="text/javascript">
14055 * @class Roo.util.ClickRepeater
14056 * @extends Roo.util.Observable
14058 * A wrapper class which can be applied to any element. Fires a "click" event while the
14059 * mouse is pressed. The interval between firings may be specified in the config but
14060 * defaults to 10 milliseconds.
14062 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14064 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14065 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14066 * Similar to an autorepeat key delay.
14067 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14068 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14069 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14070 * "interval" and "delay" are ignored. "immediate" is honored.
14071 * @cfg {Boolean} preventDefault True to prevent the default click event
14072 * @cfg {Boolean} stopDefault True to stop the default click event
14075 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14076 * 2007-02-02 jvs Renamed to ClickRepeater
14077 * 2007-02-03 jvs Modifications for FF Mac and Safari
14080 * @param {String/HTMLElement/Element} el The element to listen on
14081 * @param {Object} config
14083 Roo.util.ClickRepeater = function(el, config)
14085 this.el = Roo.get(el);
14086 this.el.unselectable();
14088 Roo.apply(this, config);
14093 * Fires when the mouse button is depressed.
14094 * @param {Roo.util.ClickRepeater} this
14096 "mousedown" : true,
14099 * Fires on a specified interval during the time the element is pressed.
14100 * @param {Roo.util.ClickRepeater} this
14105 * Fires when the mouse key is released.
14106 * @param {Roo.util.ClickRepeater} this
14111 this.el.on("mousedown", this.handleMouseDown, this);
14112 if(this.preventDefault || this.stopDefault){
14113 this.el.on("click", function(e){
14114 if(this.preventDefault){
14115 e.preventDefault();
14117 if(this.stopDefault){
14123 // allow inline handler
14125 this.on("click", this.handler, this.scope || this);
14128 Roo.util.ClickRepeater.superclass.constructor.call(this);
14131 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14134 preventDefault : true,
14135 stopDefault : false,
14139 handleMouseDown : function(){
14140 clearTimeout(this.timer);
14142 if(this.pressClass){
14143 this.el.addClass(this.pressClass);
14145 this.mousedownTime = new Date();
14147 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14148 this.el.on("mouseout", this.handleMouseOut, this);
14150 this.fireEvent("mousedown", this);
14151 this.fireEvent("click", this);
14153 this.timer = this.click.defer(this.delay || this.interval, this);
14157 click : function(){
14158 this.fireEvent("click", this);
14159 this.timer = this.click.defer(this.getInterval(), this);
14163 getInterval: function(){
14164 if(!this.accelerate){
14165 return this.interval;
14167 var pressTime = this.mousedownTime.getElapsed();
14168 if(pressTime < 500){
14170 }else if(pressTime < 1700){
14172 }else if(pressTime < 2600){
14174 }else if(pressTime < 3500){
14176 }else if(pressTime < 4400){
14178 }else if(pressTime < 5300){
14180 }else if(pressTime < 6200){
14188 handleMouseOut : function(){
14189 clearTimeout(this.timer);
14190 if(this.pressClass){
14191 this.el.removeClass(this.pressClass);
14193 this.el.on("mouseover", this.handleMouseReturn, this);
14197 handleMouseReturn : function(){
14198 this.el.un("mouseover", this.handleMouseReturn);
14199 if(this.pressClass){
14200 this.el.addClass(this.pressClass);
14206 handleMouseUp : function(){
14207 clearTimeout(this.timer);
14208 this.el.un("mouseover", this.handleMouseReturn);
14209 this.el.un("mouseout", this.handleMouseOut);
14210 Roo.get(document).un("mouseup", this.handleMouseUp);
14211 this.el.removeClass(this.pressClass);
14212 this.fireEvent("mouseup", this);
14216 * Ext JS Library 1.1.1
14217 * Copyright(c) 2006-2007, Ext JS, LLC.
14219 * Originally Released Under LGPL - original licence link has changed is not relivant.
14222 * <script type="text/javascript">
14227 * @class Roo.KeyNav
14228 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14229 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14230 * way to implement custom navigation schemes for any UI component.</p>
14231 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14232 * pageUp, pageDown, del, home, end. Usage:</p>
14234 var nav = new Roo.KeyNav("my-element", {
14235 "left" : function(e){
14236 this.moveLeft(e.ctrlKey);
14238 "right" : function(e){
14239 this.moveRight(e.ctrlKey);
14241 "enter" : function(e){
14248 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14249 * @param {Object} config The config
14251 Roo.KeyNav = function(el, config){
14252 this.el = Roo.get(el);
14253 Roo.apply(this, config);
14254 if(!this.disabled){
14255 this.disabled = true;
14260 Roo.KeyNav.prototype = {
14262 * @cfg {Boolean} disabled
14263 * True to disable this KeyNav instance (defaults to false)
14267 * @cfg {String} defaultEventAction
14268 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14269 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14270 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14272 defaultEventAction: "stopEvent",
14274 * @cfg {Boolean} forceKeyDown
14275 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14276 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14277 * handle keydown instead of keypress.
14279 forceKeyDown : false,
14282 prepareEvent : function(e){
14283 var k = e.getKey();
14284 var h = this.keyToHandler[k];
14285 //if(h && this[h]){
14286 // e.stopPropagation();
14288 if(Roo.isSafari && h && k >= 37 && k <= 40){
14294 relay : function(e){
14295 var k = e.getKey();
14296 var h = this.keyToHandler[k];
14298 if(this.doRelay(e, this[h], h) !== true){
14299 e[this.defaultEventAction]();
14305 doRelay : function(e, h, hname){
14306 return h.call(this.scope || this, e);
14309 // possible handlers
14323 // quick lookup hash
14340 * Enable this KeyNav
14342 enable: function(){
14344 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14345 // the EventObject will normalize Safari automatically
14346 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14347 this.el.on("keydown", this.relay, this);
14349 this.el.on("keydown", this.prepareEvent, this);
14350 this.el.on("keypress", this.relay, this);
14352 this.disabled = false;
14357 * Disable this KeyNav
14359 disable: function(){
14360 if(!this.disabled){
14361 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14362 this.el.un("keydown", this.relay);
14364 this.el.un("keydown", this.prepareEvent);
14365 this.el.un("keypress", this.relay);
14367 this.disabled = true;
14372 * Ext JS Library 1.1.1
14373 * Copyright(c) 2006-2007, Ext JS, LLC.
14375 * Originally Released Under LGPL - original licence link has changed is not relivant.
14378 * <script type="text/javascript">
14383 * @class Roo.KeyMap
14384 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14385 * The constructor accepts the same config object as defined by {@link #addBinding}.
14386 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14387 * combination it will call the function with this signature (if the match is a multi-key
14388 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14389 * A KeyMap can also handle a string representation of keys.<br />
14392 // map one key by key code
14393 var map = new Roo.KeyMap("my-element", {
14394 key: 13, // or Roo.EventObject.ENTER
14399 // map multiple keys to one action by string
14400 var map = new Roo.KeyMap("my-element", {
14406 // map multiple keys to multiple actions by strings and array of codes
14407 var map = new Roo.KeyMap("my-element", [
14410 fn: function(){ alert("Return was pressed"); }
14413 fn: function(){ alert('a, b or c was pressed'); }
14418 fn: function(){ alert('Control + shift + tab was pressed.'); }
14422 * <b>Note: A KeyMap starts enabled</b>
14424 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14425 * @param {Object} config The config (see {@link #addBinding})
14426 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14428 Roo.KeyMap = function(el, config, eventName){
14429 this.el = Roo.get(el);
14430 this.eventName = eventName || "keydown";
14431 this.bindings = [];
14433 this.addBinding(config);
14438 Roo.KeyMap.prototype = {
14440 * True to stop the event from bubbling and prevent the default browser action if the
14441 * key was handled by the KeyMap (defaults to false)
14447 * Add a new binding to this KeyMap. The following config object properties are supported:
14449 Property Type Description
14450 ---------- --------------- ----------------------------------------------------------------------
14451 key String/Array A single keycode or an array of keycodes to handle
14452 shift Boolean True to handle key only when shift is pressed (defaults to false)
14453 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14454 alt Boolean True to handle key only when alt is pressed (defaults to false)
14455 fn Function The function to call when KeyMap finds the expected key combination
14456 scope Object The scope of the callback function
14462 var map = new Roo.KeyMap(document, {
14463 key: Roo.EventObject.ENTER,
14468 //Add a new binding to the existing KeyMap later
14476 * @param {Object/Array} config A single KeyMap config or an array of configs
14478 addBinding : function(config){
14479 if(config instanceof Array){
14480 for(var i = 0, len = config.length; i < len; i++){
14481 this.addBinding(config[i]);
14485 var keyCode = config.key,
14486 shift = config.shift,
14487 ctrl = config.ctrl,
14490 scope = config.scope;
14491 if(typeof keyCode == "string"){
14493 var keyString = keyCode.toUpperCase();
14494 for(var j = 0, len = keyString.length; j < len; j++){
14495 ks.push(keyString.charCodeAt(j));
14499 var keyArray = keyCode instanceof Array;
14500 var handler = function(e){
14501 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14502 var k = e.getKey();
14504 for(var i = 0, len = keyCode.length; i < len; i++){
14505 if(keyCode[i] == k){
14506 if(this.stopEvent){
14509 fn.call(scope || window, k, e);
14515 if(this.stopEvent){
14518 fn.call(scope || window, k, e);
14523 this.bindings.push(handler);
14527 * Shorthand for adding a single key listener
14528 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14529 * following options:
14530 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14531 * @param {Function} fn The function to call
14532 * @param {Object} scope (optional) The scope of the function
14534 on : function(key, fn, scope){
14535 var keyCode, shift, ctrl, alt;
14536 if(typeof key == "object" && !(key instanceof Array)){
14555 handleKeyDown : function(e){
14556 if(this.enabled){ //just in case
14557 var b = this.bindings;
14558 for(var i = 0, len = b.length; i < len; i++){
14559 b[i].call(this, e);
14565 * Returns true if this KeyMap is enabled
14566 * @return {Boolean}
14568 isEnabled : function(){
14569 return this.enabled;
14573 * Enables this KeyMap
14575 enable: function(){
14577 this.el.on(this.eventName, this.handleKeyDown, this);
14578 this.enabled = true;
14583 * Disable this KeyMap
14585 disable: function(){
14587 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14588 this.enabled = false;
14593 * Ext JS Library 1.1.1
14594 * Copyright(c) 2006-2007, Ext JS, LLC.
14596 * Originally Released Under LGPL - original licence link has changed is not relivant.
14599 * <script type="text/javascript">
14604 * @class Roo.util.TextMetrics
14605 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14606 * wide, in pixels, a given block of text will be.
14609 Roo.util.TextMetrics = function(){
14613 * Measures the size of the specified text
14614 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14615 * that can affect the size of the rendered text
14616 * @param {String} text The text to measure
14617 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14618 * in order to accurately measure the text height
14619 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14621 measure : function(el, text, fixedWidth){
14623 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14626 shared.setFixedWidth(fixedWidth || 'auto');
14627 return shared.getSize(text);
14631 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14632 * the overhead of multiple calls to initialize the style properties on each measurement.
14633 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14634 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14635 * in order to accurately measure the text height
14636 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14638 createInstance : function(el, fixedWidth){
14639 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14646 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14647 var ml = new Roo.Element(document.createElement('div'));
14648 document.body.appendChild(ml.dom);
14649 ml.position('absolute');
14650 ml.setLeftTop(-1000, -1000);
14654 ml.setWidth(fixedWidth);
14659 * Returns the size of the specified text based on the internal element's style and width properties
14660 * @memberOf Roo.util.TextMetrics.Instance#
14661 * @param {String} text The text to measure
14662 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14664 getSize : function(text){
14666 var s = ml.getSize();
14672 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14673 * that can affect the size of the rendered text
14674 * @memberOf Roo.util.TextMetrics.Instance#
14675 * @param {String/HTMLElement} el The element, dom node or id
14677 bind : function(el){
14679 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14684 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14685 * to set a fixed width in order to accurately measure the text height.
14686 * @memberOf Roo.util.TextMetrics.Instance#
14687 * @param {Number} width The width to set on the element
14689 setFixedWidth : function(width){
14690 ml.setWidth(width);
14694 * Returns the measured width of the specified text
14695 * @memberOf Roo.util.TextMetrics.Instance#
14696 * @param {String} text The text to measure
14697 * @return {Number} width The width in pixels
14699 getWidth : function(text){
14700 ml.dom.style.width = 'auto';
14701 return this.getSize(text).width;
14705 * Returns the measured height of the specified text. For multiline text, be sure to call
14706 * {@link #setFixedWidth} if necessary.
14707 * @memberOf Roo.util.TextMetrics.Instance#
14708 * @param {String} text The text to measure
14709 * @return {Number} height The height in pixels
14711 getHeight : function(text){
14712 return this.getSize(text).height;
14716 instance.bind(bindTo);
14721 // backwards compat
14722 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14724 * Ext JS Library 1.1.1
14725 * Copyright(c) 2006-2007, Ext JS, LLC.
14727 * Originally Released Under LGPL - original licence link has changed is not relivant.
14730 * <script type="text/javascript">
14734 * @class Roo.state.Provider
14735 * Abstract base class for state provider implementations. This class provides methods
14736 * for encoding and decoding <b>typed</b> variables including dates and defines the
14737 * Provider interface.
14739 Roo.state.Provider = function(){
14741 * @event statechange
14742 * Fires when a state change occurs.
14743 * @param {Provider} this This state provider
14744 * @param {String} key The state key which was changed
14745 * @param {String} value The encoded value for the state
14748 "statechange": true
14751 Roo.state.Provider.superclass.constructor.call(this);
14753 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14755 * Returns the current value for a key
14756 * @param {String} name The key name
14757 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14758 * @return {Mixed} The state data
14760 get : function(name, defaultValue){
14761 return typeof this.state[name] == "undefined" ?
14762 defaultValue : this.state[name];
14766 * Clears a value from the state
14767 * @param {String} name The key name
14769 clear : function(name){
14770 delete this.state[name];
14771 this.fireEvent("statechange", this, name, null);
14775 * Sets the value for a key
14776 * @param {String} name The key name
14777 * @param {Mixed} value The value to set
14779 set : function(name, value){
14780 this.state[name] = value;
14781 this.fireEvent("statechange", this, name, value);
14785 * Decodes a string previously encoded with {@link #encodeValue}.
14786 * @param {String} value The value to decode
14787 * @return {Mixed} The decoded value
14789 decodeValue : function(cookie){
14790 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14791 var matches = re.exec(unescape(cookie));
14792 if(!matches || !matches[1]) return; // non state cookie
14793 var type = matches[1];
14794 var v = matches[2];
14797 return parseFloat(v);
14799 return new Date(Date.parse(v));
14804 var values = v.split("^");
14805 for(var i = 0, len = values.length; i < len; i++){
14806 all.push(this.decodeValue(values[i]));
14811 var values = v.split("^");
14812 for(var i = 0, len = values.length; i < len; i++){
14813 var kv = values[i].split("=");
14814 all[kv[0]] = this.decodeValue(kv[1]);
14823 * Encodes a value including type information. Decode with {@link #decodeValue}.
14824 * @param {Mixed} value The value to encode
14825 * @return {String} The encoded value
14827 encodeValue : function(v){
14829 if(typeof v == "number"){
14831 }else if(typeof v == "boolean"){
14832 enc = "b:" + (v ? "1" : "0");
14833 }else if(v instanceof Date){
14834 enc = "d:" + v.toGMTString();
14835 }else if(v instanceof Array){
14837 for(var i = 0, len = v.length; i < len; i++){
14838 flat += this.encodeValue(v[i]);
14839 if(i != len-1) flat += "^";
14842 }else if(typeof v == "object"){
14845 if(typeof v[key] != "function"){
14846 flat += key + "=" + this.encodeValue(v[key]) + "^";
14849 enc = "o:" + flat.substring(0, flat.length-1);
14853 return escape(enc);
14859 * Ext JS Library 1.1.1
14860 * Copyright(c) 2006-2007, Ext JS, LLC.
14862 * Originally Released Under LGPL - original licence link has changed is not relivant.
14865 * <script type="text/javascript">
14868 * @class Roo.state.Manager
14869 * This is the global state manager. By default all components that are "state aware" check this class
14870 * for state information if you don't pass them a custom state provider. In order for this class
14871 * to be useful, it must be initialized with a provider when your application initializes.
14873 // in your initialization function
14875 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14877 // supposed you have a {@link Roo.BorderLayout}
14878 var layout = new Roo.BorderLayout(...);
14879 layout.restoreState();
14880 // or a {Roo.BasicDialog}
14881 var dialog = new Roo.BasicDialog(...);
14882 dialog.restoreState();
14886 Roo.state.Manager = function(){
14887 var provider = new Roo.state.Provider();
14891 * Configures the default state provider for your application
14892 * @param {Provider} stateProvider The state provider to set
14894 setProvider : function(stateProvider){
14895 provider = stateProvider;
14899 * Returns the current value for a key
14900 * @param {String} name The key name
14901 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14902 * @return {Mixed} The state data
14904 get : function(key, defaultValue){
14905 return provider.get(key, defaultValue);
14909 * Sets the value for a key
14910 * @param {String} name The key name
14911 * @param {Mixed} value The state data
14913 set : function(key, value){
14914 provider.set(key, value);
14918 * Clears a value from the state
14919 * @param {String} name The key name
14921 clear : function(key){
14922 provider.clear(key);
14926 * Gets the currently configured state provider
14927 * @return {Provider} The state provider
14929 getProvider : function(){
14936 * Ext JS Library 1.1.1
14937 * Copyright(c) 2006-2007, Ext JS, LLC.
14939 * Originally Released Under LGPL - original licence link has changed is not relivant.
14942 * <script type="text/javascript">
14945 * @class Roo.state.CookieProvider
14946 * @extends Roo.state.Provider
14947 * The default Provider implementation which saves state via cookies.
14950 var cp = new Roo.state.CookieProvider({
14952 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14953 domain: "roojs.com"
14955 Roo.state.Manager.setProvider(cp);
14957 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14958 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14959 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14960 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14961 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14962 * domain the page is running on including the 'www' like 'www.roojs.com')
14963 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14965 * Create a new CookieProvider
14966 * @param {Object} config The configuration object
14968 Roo.state.CookieProvider = function(config){
14969 Roo.state.CookieProvider.superclass.constructor.call(this);
14971 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14972 this.domain = null;
14973 this.secure = false;
14974 Roo.apply(this, config);
14975 this.state = this.readCookies();
14978 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14980 set : function(name, value){
14981 if(typeof value == "undefined" || value === null){
14985 this.setCookie(name, value);
14986 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14990 clear : function(name){
14991 this.clearCookie(name);
14992 Roo.state.CookieProvider.superclass.clear.call(this, name);
14996 readCookies : function(){
14998 var c = document.cookie + ";";
14999 var re = /\s?(.*?)=(.*?);/g;
15001 while((matches = re.exec(c)) != null){
15002 var name = matches[1];
15003 var value = matches[2];
15004 if(name && name.substring(0,3) == "ys-"){
15005 cookies[name.substr(3)] = this.decodeValue(value);
15012 setCookie : function(name, value){
15013 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15014 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15015 ((this.path == null) ? "" : ("; path=" + this.path)) +
15016 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15017 ((this.secure == true) ? "; secure" : "");
15021 clearCookie : function(name){
15022 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15023 ((this.path == null) ? "" : ("; path=" + this.path)) +
15024 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15025 ((this.secure == true) ? "; secure" : "");
15029 * Ext JS Library 1.1.1
15030 * Copyright(c) 2006-2007, Ext JS, LLC.
15032 * Originally Released Under LGPL - original licence link has changed is not relivant.
15035 * <script type="text/javascript">
15040 * @class Roo.ComponentMgr
15041 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15044 Roo.ComponentMgr = function(){
15045 var all = new Roo.util.MixedCollection();
15049 * Registers a component.
15050 * @param {Roo.Component} c The component
15052 register : function(c){
15057 * Unregisters a component.
15058 * @param {Roo.Component} c The component
15060 unregister : function(c){
15065 * Returns a component by id
15066 * @param {String} id The component id
15068 get : function(id){
15069 return all.get(id);
15073 * Registers a function that will be called when a specified component is added to ComponentMgr
15074 * @param {String} id The component id
15075 * @param {Funtction} fn The callback function
15076 * @param {Object} scope The scope of the callback
15078 onAvailable : function(id, fn, scope){
15079 all.on("add", function(index, o){
15081 fn.call(scope || o, o);
15082 all.un("add", fn, scope);
15089 * Ext JS Library 1.1.1
15090 * Copyright(c) 2006-2007, Ext JS, LLC.
15092 * Originally Released Under LGPL - original licence link has changed is not relivant.
15095 * <script type="text/javascript">
15099 * @class Roo.Component
15100 * @extends Roo.util.Observable
15101 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15102 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15103 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15104 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15105 * All visual components (widgets) that require rendering into a layout should subclass Component.
15107 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15108 * 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
15109 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15111 Roo.Component = function(config){
15112 config = config || {};
15113 if(config.tagName || config.dom || typeof config == "string"){ // element object
15114 config = {el: config, id: config.id || config};
15116 this.initialConfig = config;
15118 Roo.apply(this, config);
15122 * Fires after the component is disabled.
15123 * @param {Roo.Component} this
15128 * Fires after the component is enabled.
15129 * @param {Roo.Component} this
15133 * @event beforeshow
15134 * Fires before the component is shown. Return false to stop the show.
15135 * @param {Roo.Component} this
15140 * Fires after the component is shown.
15141 * @param {Roo.Component} this
15145 * @event beforehide
15146 * Fires before the component is hidden. Return false to stop the hide.
15147 * @param {Roo.Component} this
15152 * Fires after the component is hidden.
15153 * @param {Roo.Component} this
15157 * @event beforerender
15158 * Fires before the component is rendered. Return false to stop the render.
15159 * @param {Roo.Component} this
15161 beforerender : true,
15164 * Fires after the component is rendered.
15165 * @param {Roo.Component} this
15169 * @event beforedestroy
15170 * Fires before the component is destroyed. Return false to stop the destroy.
15171 * @param {Roo.Component} this
15173 beforedestroy : true,
15176 * Fires after the component is destroyed.
15177 * @param {Roo.Component} this
15182 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15184 Roo.ComponentMgr.register(this);
15185 Roo.Component.superclass.constructor.call(this);
15186 this.initComponent();
15187 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15188 this.render(this.renderTo);
15189 delete this.renderTo;
15194 Roo.Component.AUTO_ID = 1000;
15196 Roo.extend(Roo.Component, Roo.util.Observable, {
15198 * @scope Roo.Component.prototype
15200 * true if this component is hidden. Read-only.
15205 * true if this component is disabled. Read-only.
15210 * true if this component has been rendered. Read-only.
15214 /** @cfg {String} disableClass
15215 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15217 disabledClass : "x-item-disabled",
15218 /** @cfg {Boolean} allowDomMove
15219 * Whether the component can move the Dom node when rendering (defaults to true).
15221 allowDomMove : true,
15222 /** @cfg {String} hideMode (display|visibility)
15223 * How this component should hidden. Supported values are
15224 * "visibility" (css visibility), "offsets" (negative offset position) and
15225 * "display" (css display) - defaults to "display".
15227 hideMode: 'display',
15230 ctype : "Roo.Component",
15233 * @cfg {String} actionMode
15234 * which property holds the element that used for hide() / show() / disable() / enable()
15240 getActionEl : function(){
15241 return this[this.actionMode];
15244 initComponent : Roo.emptyFn,
15246 * If this is a lazy rendering component, render it to its container element.
15247 * @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.
15249 render : function(container, position){
15250 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15251 if(!container && this.el){
15252 this.el = Roo.get(this.el);
15253 container = this.el.dom.parentNode;
15254 this.allowDomMove = false;
15256 this.container = Roo.get(container);
15257 this.rendered = true;
15258 if(position !== undefined){
15259 if(typeof position == 'number'){
15260 position = this.container.dom.childNodes[position];
15262 position = Roo.getDom(position);
15265 this.onRender(this.container, position || null);
15267 this.el.addClass(this.cls);
15271 this.el.applyStyles(this.style);
15274 this.fireEvent("render", this);
15275 this.afterRender(this.container);
15287 // default function is not really useful
15288 onRender : function(ct, position){
15290 this.el = Roo.get(this.el);
15291 if(this.allowDomMove !== false){
15292 ct.dom.insertBefore(this.el.dom, position);
15298 getAutoCreate : function(){
15299 var cfg = typeof this.autoCreate == "object" ?
15300 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15301 if(this.id && !cfg.id){
15308 afterRender : Roo.emptyFn,
15311 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15312 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15314 destroy : function(){
15315 if(this.fireEvent("beforedestroy", this) !== false){
15316 this.purgeListeners();
15317 this.beforeDestroy();
15319 this.el.removeAllListeners();
15321 if(this.actionMode == "container"){
15322 this.container.remove();
15326 Roo.ComponentMgr.unregister(this);
15327 this.fireEvent("destroy", this);
15332 beforeDestroy : function(){
15337 onDestroy : function(){
15342 * Returns the underlying {@link Roo.Element}.
15343 * @return {Roo.Element} The element
15345 getEl : function(){
15350 * Returns the id of this component.
15353 getId : function(){
15358 * Try to focus this component.
15359 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15360 * @return {Roo.Component} this
15362 focus : function(selectText){
15365 if(selectText === true){
15366 this.el.dom.select();
15381 * Disable this component.
15382 * @return {Roo.Component} this
15384 disable : function(){
15388 this.disabled = true;
15389 this.fireEvent("disable", this);
15394 onDisable : function(){
15395 this.getActionEl().addClass(this.disabledClass);
15396 this.el.dom.disabled = true;
15400 * Enable this component.
15401 * @return {Roo.Component} this
15403 enable : function(){
15407 this.disabled = false;
15408 this.fireEvent("enable", this);
15413 onEnable : function(){
15414 this.getActionEl().removeClass(this.disabledClass);
15415 this.el.dom.disabled = false;
15419 * Convenience function for setting disabled/enabled by boolean.
15420 * @param {Boolean} disabled
15422 setDisabled : function(disabled){
15423 this[disabled ? "disable" : "enable"]();
15427 * Show this component.
15428 * @return {Roo.Component} this
15431 if(this.fireEvent("beforeshow", this) !== false){
15432 this.hidden = false;
15436 this.fireEvent("show", this);
15442 onShow : function(){
15443 var ae = this.getActionEl();
15444 if(this.hideMode == 'visibility'){
15445 ae.dom.style.visibility = "visible";
15446 }else if(this.hideMode == 'offsets'){
15447 ae.removeClass('x-hidden');
15449 ae.dom.style.display = "";
15454 * Hide this component.
15455 * @return {Roo.Component} this
15458 if(this.fireEvent("beforehide", this) !== false){
15459 this.hidden = true;
15463 this.fireEvent("hide", this);
15469 onHide : function(){
15470 var ae = this.getActionEl();
15471 if(this.hideMode == 'visibility'){
15472 ae.dom.style.visibility = "hidden";
15473 }else if(this.hideMode == 'offsets'){
15474 ae.addClass('x-hidden');
15476 ae.dom.style.display = "none";
15481 * Convenience function to hide or show this component by boolean.
15482 * @param {Boolean} visible True to show, false to hide
15483 * @return {Roo.Component} this
15485 setVisible: function(visible){
15495 * Returns true if this component is visible.
15497 isVisible : function(){
15498 return this.getActionEl().isVisible();
15501 cloneConfig : function(overrides){
15502 overrides = overrides || {};
15503 var id = overrides.id || Roo.id();
15504 var cfg = Roo.applyIf(overrides, this.initialConfig);
15505 cfg.id = id; // prevent dup id
15506 return new this.constructor(cfg);
15510 * Ext JS Library 1.1.1
15511 * Copyright(c) 2006-2007, Ext JS, LLC.
15513 * Originally Released Under LGPL - original licence link has changed is not relivant.
15516 * <script type="text/javascript">
15520 * @class Roo.BoxComponent
15521 * @extends Roo.Component
15522 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15523 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15524 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15525 * layout containers.
15527 * @param {Roo.Element/String/Object} config The configuration options.
15529 Roo.BoxComponent = function(config){
15530 Roo.Component.call(this, config);
15534 * Fires after the component is resized.
15535 * @param {Roo.Component} this
15536 * @param {Number} adjWidth The box-adjusted width that was set
15537 * @param {Number} adjHeight The box-adjusted height that was set
15538 * @param {Number} rawWidth The width that was originally specified
15539 * @param {Number} rawHeight The height that was originally specified
15544 * Fires after the component is moved.
15545 * @param {Roo.Component} this
15546 * @param {Number} x The new x position
15547 * @param {Number} y The new y position
15553 Roo.extend(Roo.BoxComponent, Roo.Component, {
15554 // private, set in afterRender to signify that the component has been rendered
15556 // private, used to defer height settings to subclasses
15557 deferHeight: false,
15558 /** @cfg {Number} width
15559 * width (optional) size of component
15561 /** @cfg {Number} height
15562 * height (optional) size of component
15566 * Sets the width and height of the component. This method fires the resize event. This method can accept
15567 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15568 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15569 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15570 * @return {Roo.BoxComponent} this
15572 setSize : function(w, h){
15573 // support for standard size objects
15574 if(typeof w == 'object'){
15579 if(!this.boxReady){
15585 // prevent recalcs when not needed
15586 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15589 this.lastSize = {width: w, height: h};
15591 var adj = this.adjustSize(w, h);
15592 var aw = adj.width, ah = adj.height;
15593 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15594 var rz = this.getResizeEl();
15595 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15596 rz.setSize(aw, ah);
15597 }else if(!this.deferHeight && ah !== undefined){
15599 }else if(aw !== undefined){
15602 this.onResize(aw, ah, w, h);
15603 this.fireEvent('resize', this, aw, ah, w, h);
15609 * Gets the current size of the component's underlying element.
15610 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15612 getSize : function(){
15613 return this.el.getSize();
15617 * Gets the current XY position of the component's underlying element.
15618 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15619 * @return {Array} The XY position of the element (e.g., [100, 200])
15621 getPosition : function(local){
15622 if(local === true){
15623 return [this.el.getLeft(true), this.el.getTop(true)];
15625 return this.xy || this.el.getXY();
15629 * Gets the current box measurements of the component's underlying element.
15630 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15631 * @returns {Object} box An object in the format {x, y, width, height}
15633 getBox : function(local){
15634 var s = this.el.getSize();
15636 s.x = this.el.getLeft(true);
15637 s.y = this.el.getTop(true);
15639 var xy = this.xy || this.el.getXY();
15647 * Sets the current box measurements of the component's underlying element.
15648 * @param {Object} box An object in the format {x, y, width, height}
15649 * @returns {Roo.BoxComponent} this
15651 updateBox : function(box){
15652 this.setSize(box.width, box.height);
15653 this.setPagePosition(box.x, box.y);
15658 getResizeEl : function(){
15659 return this.resizeEl || this.el;
15663 getPositionEl : function(){
15664 return this.positionEl || this.el;
15668 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15669 * This method fires the move event.
15670 * @param {Number} left The new left
15671 * @param {Number} top The new top
15672 * @returns {Roo.BoxComponent} this
15674 setPosition : function(x, y){
15677 if(!this.boxReady){
15680 var adj = this.adjustPosition(x, y);
15681 var ax = adj.x, ay = adj.y;
15683 var el = this.getPositionEl();
15684 if(ax !== undefined || ay !== undefined){
15685 if(ax !== undefined && ay !== undefined){
15686 el.setLeftTop(ax, ay);
15687 }else if(ax !== undefined){
15689 }else if(ay !== undefined){
15692 this.onPosition(ax, ay);
15693 this.fireEvent('move', this, ax, ay);
15699 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15700 * This method fires the move event.
15701 * @param {Number} x The new x position
15702 * @param {Number} y The new y position
15703 * @returns {Roo.BoxComponent} this
15705 setPagePosition : function(x, y){
15708 if(!this.boxReady){
15711 if(x === undefined || y === undefined){ // cannot translate undefined points
15714 var p = this.el.translatePoints(x, y);
15715 this.setPosition(p.left, p.top);
15720 onRender : function(ct, position){
15721 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15723 this.resizeEl = Roo.get(this.resizeEl);
15725 if(this.positionEl){
15726 this.positionEl = Roo.get(this.positionEl);
15731 afterRender : function(){
15732 Roo.BoxComponent.superclass.afterRender.call(this);
15733 this.boxReady = true;
15734 this.setSize(this.width, this.height);
15735 if(this.x || this.y){
15736 this.setPosition(this.x, this.y);
15738 if(this.pageX || this.pageY){
15739 this.setPagePosition(this.pageX, this.pageY);
15744 * Force the component's size to recalculate based on the underlying element's current height and width.
15745 * @returns {Roo.BoxComponent} this
15747 syncSize : function(){
15748 delete this.lastSize;
15749 this.setSize(this.el.getWidth(), this.el.getHeight());
15754 * Called after the component is resized, this method is empty by default but can be implemented by any
15755 * subclass that needs to perform custom logic after a resize occurs.
15756 * @param {Number} adjWidth The box-adjusted width that was set
15757 * @param {Number} adjHeight The box-adjusted height that was set
15758 * @param {Number} rawWidth The width that was originally specified
15759 * @param {Number} rawHeight The height that was originally specified
15761 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15766 * Called after the component is moved, this method is empty by default but can be implemented by any
15767 * subclass that needs to perform custom logic after a move occurs.
15768 * @param {Number} x The new x position
15769 * @param {Number} y The new y position
15771 onPosition : function(x, y){
15776 adjustSize : function(w, h){
15777 if(this.autoWidth){
15780 if(this.autoHeight){
15783 return {width : w, height: h};
15787 adjustPosition : function(x, y){
15788 return {x : x, y: y};
15791 * Original code for Roojs - LGPL
15792 * <script type="text/javascript">
15796 * @class Roo.XComponent
15797 * A delayed Element creator...
15798 * Or a way to group chunks of interface together.
15799 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15800 * used in conjunction with XComponent.build() it will create an instance of each element,
15801 * then call addxtype() to build the User interface.
15803 * Mypart.xyx = new Roo.XComponent({
15805 parent : 'Mypart.xyz', // empty == document.element.!!
15809 disabled : function() {}
15811 tree : function() { // return an tree of xtype declared components
15815 xtype : 'NestedLayoutPanel',
15822 * It can be used to build a big heiracy, with parent etc.
15823 * or you can just use this to render a single compoent to a dom element
15824 * MYPART.render(Roo.Element | String(id) | dom_element )
15831 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15832 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15834 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15836 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15837 * - if mulitple topModules exist, the last one is defined as the top module.
15841 * When the top level or multiple modules are to embedded into a existing HTML page,
15842 * the parent element can container '#id' of the element where the module will be drawn.
15846 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15847 * it relies more on a include mechanism, where sub modules are included into an outer page.
15848 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15850 * Bootstrap Roo Included elements
15852 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15853 * hence confusing the component builder as it thinks there are multiple top level elements.
15857 * @extends Roo.util.Observable
15859 * @param cfg {Object} configuration of component
15862 Roo.XComponent = function(cfg) {
15863 Roo.apply(this, cfg);
15867 * Fires when this the componnt is built
15868 * @param {Roo.XComponent} c the component
15873 this.region = this.region || 'center'; // default..
15874 Roo.XComponent.register(this);
15875 this.modules = false;
15876 this.el = false; // where the layout goes..
15880 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15883 * The created element (with Roo.factory())
15884 * @type {Roo.Layout}
15890 * for BC - use el in new code
15891 * @type {Roo.Layout}
15897 * for BC - use el in new code
15898 * @type {Roo.Layout}
15903 * @cfg {Function|boolean} disabled
15904 * If this module is disabled by some rule, return true from the funtion
15909 * @cfg {String} parent
15910 * Name of parent element which it get xtype added to..
15915 * @cfg {String} order
15916 * Used to set the order in which elements are created (usefull for multiple tabs)
15921 * @cfg {String} name
15922 * String to display while loading.
15926 * @cfg {String} region
15927 * Region to render component to (defaults to center)
15932 * @cfg {Array} items
15933 * A single item array - the first element is the root of the tree..
15934 * It's done this way to stay compatible with the Xtype system...
15940 * The method that retuns the tree of parts that make up this compoennt
15947 * render element to dom or tree
15948 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15951 render : function(el)
15955 var hp = this.parent ? 1 : 0;
15956 Roo.debug && Roo.log(this);
15958 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15959 // if parent is a '#.....' string, then let's use that..
15960 var ename = this.parent.substr(1);
15961 this.parent = false;
15962 Roo.debug && Roo.log(ename);
15964 case 'bootstrap-body' :
15965 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15966 this.parent = { el : new Roo.bootstrap.Body() };
15967 Roo.debug && Roo.log("setting el to doc body");
15970 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15974 this.parent = { el : true};
15977 el = Roo.get(ename);
15982 if (!el && !this.parent) {
15983 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15987 Roo.debug && Roo.log("EL:");
15988 Roo.debug && Roo.log(el);
15989 Roo.debug && Roo.log("this.parent.el:");
15990 Roo.debug && Roo.log(this.parent.el);
15992 var tree = this._tree ? this._tree() : this.tree();
15994 // altertive root elements ??? - we need a better way to indicate these.
15995 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15996 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15998 if (!this.parent && is_alt) {
15999 //el = Roo.get(document.body);
16000 this.parent = { el : true };
16005 if (!this.parent) {
16007 Roo.debug && Roo.log("no parent - creating one");
16009 el = el ? Roo.get(el) : false;
16011 // it's a top level one..
16013 el : new Roo.BorderLayout(el || document.body, {
16019 tabPosition: 'top',
16020 //resizeTabs: true,
16021 alwaysShowTabs: el && hp? false : true,
16022 hideTabs: el || !hp ? true : false,
16029 if (!this.parent.el) {
16030 // probably an old style ctor, which has been disabled.
16034 // The 'tree' method is '_tree now'
16036 tree.region = tree.region || this.region;
16038 if (this.parent.el === true) {
16039 // bootstrap... - body..
16040 this.parent.el = Roo.factory(tree);
16043 this.el = this.parent.el.addxtype(tree);
16044 this.fireEvent('built', this);
16046 this.panel = this.el;
16047 this.layout = this.panel.layout;
16048 this.parentLayout = this.parent.layout || false;
16054 Roo.apply(Roo.XComponent, {
16056 * @property hideProgress
16057 * true to disable the building progress bar.. usefull on single page renders.
16060 hideProgress : false,
16062 * @property buildCompleted
16063 * True when the builder has completed building the interface.
16066 buildCompleted : false,
16069 * @property topModule
16070 * the upper most module - uses document.element as it's constructor.
16077 * @property modules
16078 * array of modules to be created by registration system.
16079 * @type {Array} of Roo.XComponent
16084 * @property elmodules
16085 * array of modules to be created by which use #ID
16086 * @type {Array} of Roo.XComponent
16092 * @property build_from_html
16093 * Build elements from html - used by bootstrap HTML stuff
16094 * - this is cleared after build is completed
16095 * @type {boolean} true (default false)
16098 build_from_html : false,
16101 * Register components to be built later.
16103 * This solves the following issues
16104 * - Building is not done on page load, but after an authentication process has occured.
16105 * - Interface elements are registered on page load
16106 * - Parent Interface elements may not be loaded before child, so this handles that..
16113 module : 'Pman.Tab.projectMgr',
16115 parent : 'Pman.layout',
16116 disabled : false, // or use a function..
16119 * * @param {Object} details about module
16121 register : function(obj) {
16123 Roo.XComponent.event.fireEvent('register', obj);
16124 switch(typeof(obj.disabled) ) {
16130 if ( obj.disabled() ) {
16136 if (obj.disabled) {
16142 this.modules.push(obj);
16146 * convert a string to an object..
16147 * eg. 'AAA.BBB' -> finds AAA.BBB
16151 toObject : function(str)
16153 if (!str || typeof(str) == 'object') {
16156 if (str.substring(0,1) == '#') {
16160 var ar = str.split('.');
16165 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16167 throw "Module not found : " + str;
16171 throw "Module not found : " + str;
16173 Roo.each(ar, function(e) {
16174 if (typeof(o[e]) == 'undefined') {
16175 throw "Module not found : " + str;
16186 * move modules into their correct place in the tree..
16189 preBuild : function ()
16192 Roo.each(this.modules , function (obj)
16194 Roo.XComponent.event.fireEvent('beforebuild', obj);
16196 var opar = obj.parent;
16198 obj.parent = this.toObject(opar);
16200 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16205 Roo.debug && Roo.log("GOT top level module");
16206 Roo.debug && Roo.log(obj);
16207 obj.modules = new Roo.util.MixedCollection(false,
16208 function(o) { return o.order + '' }
16210 this.topModule = obj;
16213 // parent is a string (usually a dom element name..)
16214 if (typeof(obj.parent) == 'string') {
16215 this.elmodules.push(obj);
16218 if (obj.parent.constructor != Roo.XComponent) {
16219 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16221 if (!obj.parent.modules) {
16222 obj.parent.modules = new Roo.util.MixedCollection(false,
16223 function(o) { return o.order + '' }
16226 if (obj.parent.disabled) {
16227 obj.disabled = true;
16229 obj.parent.modules.add(obj);
16234 * make a list of modules to build.
16235 * @return {Array} list of modules.
16238 buildOrder : function()
16241 var cmp = function(a,b) {
16242 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16244 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16245 throw "No top level modules to build";
16248 // make a flat list in order of modules to build.
16249 var mods = this.topModule ? [ this.topModule ] : [];
16252 // elmodules (is a list of DOM based modules )
16253 Roo.each(this.elmodules, function(e) {
16255 if (!this.topModule &&
16256 typeof(e.parent) == 'string' &&
16257 e.parent.substring(0,1) == '#' &&
16258 Roo.get(e.parent.substr(1))
16261 _this.topModule = e;
16267 // add modules to their parents..
16268 var addMod = function(m) {
16269 Roo.debug && Roo.log("build Order: add: " + m.name);
16272 if (m.modules && !m.disabled) {
16273 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16274 m.modules.keySort('ASC', cmp );
16275 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16277 m.modules.each(addMod);
16279 Roo.debug && Roo.log("build Order: no child modules");
16281 // not sure if this is used any more..
16283 m.finalize.name = m.name + " (clean up) ";
16284 mods.push(m.finalize);
16288 if (this.topModule && this.topModule.modules) {
16289 this.topModule.modules.keySort('ASC', cmp );
16290 this.topModule.modules.each(addMod);
16296 * Build the registered modules.
16297 * @param {Object} parent element.
16298 * @param {Function} optional method to call after module has been added.
16302 build : function(opts)
16305 if (typeof(opts) != 'undefined') {
16306 Roo.apply(this,opts);
16310 var mods = this.buildOrder();
16312 //this.allmods = mods;
16313 //Roo.debug && Roo.log(mods);
16315 if (!mods.length) { // should not happen
16316 throw "NO modules!!!";
16320 var msg = "Building Interface...";
16321 // flash it up as modal - so we store the mask!?
16322 if (!this.hideProgress && Roo.MessageBox) {
16323 Roo.MessageBox.show({ title: 'loading' });
16324 Roo.MessageBox.show({
16325 title: "Please wait...",
16334 var total = mods.length;
16337 var progressRun = function() {
16338 if (!mods.length) {
16339 Roo.debug && Roo.log('hide?');
16340 if (!this.hideProgress && Roo.MessageBox) {
16341 Roo.MessageBox.hide();
16343 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16345 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16351 var m = mods.shift();
16354 Roo.debug && Roo.log(m);
16355 // not sure if this is supported any more.. - modules that are are just function
16356 if (typeof(m) == 'function') {
16358 return progressRun.defer(10, _this);
16362 msg = "Building Interface " + (total - mods.length) +
16364 (m.name ? (' - ' + m.name) : '');
16365 Roo.debug && Roo.log(msg);
16366 if (!this.hideProgress && Roo.MessageBox) {
16367 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16371 // is the module disabled?
16372 var disabled = (typeof(m.disabled) == 'function') ?
16373 m.disabled.call(m.module.disabled) : m.disabled;
16377 return progressRun(); // we do not update the display!
16385 // it's 10 on top level, and 1 on others??? why...
16386 return progressRun.defer(10, _this);
16389 progressRun.defer(1, _this);
16403 * wrapper for event.on - aliased later..
16404 * Typically use to register a event handler for register:
16406 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16415 Roo.XComponent.event = new Roo.util.Observable({
16419 * Fires when an Component is registered,
16420 * set the disable property on the Component to stop registration.
16421 * @param {Roo.XComponent} c the component being registerd.
16426 * @event beforebuild
16427 * Fires before each Component is built
16428 * can be used to apply permissions.
16429 * @param {Roo.XComponent} c the component being registerd.
16432 'beforebuild' : true,
16434 * @event buildcomplete
16435 * Fires on the top level element when all elements have been built
16436 * @param {Roo.XComponent} the top level component.
16438 'buildcomplete' : true
16443 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16446 * Ext JS Library 1.1.1
16447 * Copyright(c) 2006-2007, Ext JS, LLC.
16449 * Originally Released Under LGPL - original licence link has changed is not relivant.
16452 * <script type="text/javascript">
16458 * These classes are derivatives of the similarly named classes in the YUI Library.
16459 * The original license:
16460 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16461 * Code licensed under the BSD License:
16462 * http://developer.yahoo.net/yui/license.txt
16467 var Event=Roo.EventManager;
16468 var Dom=Roo.lib.Dom;
16471 * @class Roo.dd.DragDrop
16472 * @extends Roo.util.Observable
16473 * Defines the interface and base operation of items that that can be
16474 * dragged or can be drop targets. It was designed to be extended, overriding
16475 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16476 * Up to three html elements can be associated with a DragDrop instance:
16478 * <li>linked element: the element that is passed into the constructor.
16479 * This is the element which defines the boundaries for interaction with
16480 * other DragDrop objects.</li>
16481 * <li>handle element(s): The drag operation only occurs if the element that
16482 * was clicked matches a handle element. By default this is the linked
16483 * element, but there are times that you will want only a portion of the
16484 * linked element to initiate the drag operation, and the setHandleElId()
16485 * method provides a way to define this.</li>
16486 * <li>drag element: this represents the element that would be moved along
16487 * with the cursor during a drag operation. By default, this is the linked
16488 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16489 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16492 * This class should not be instantiated until the onload event to ensure that
16493 * the associated elements are available.
16494 * The following would define a DragDrop obj that would interact with any
16495 * other DragDrop obj in the "group1" group:
16497 * dd = new Roo.dd.DragDrop("div1", "group1");
16499 * Since none of the event handlers have been implemented, nothing would
16500 * actually happen if you were to run the code above. Normally you would
16501 * override this class or one of the default implementations, but you can
16502 * also override the methods you want on an instance of the class...
16504 * dd.onDragDrop = function(e, id) {
16505 * alert("dd was dropped on " + id);
16509 * @param {String} id of the element that is linked to this instance
16510 * @param {String} sGroup the group of related DragDrop objects
16511 * @param {object} config an object containing configurable attributes
16512 * Valid properties for DragDrop:
16513 * padding, isTarget, maintainOffset, primaryButtonOnly
16515 Roo.dd.DragDrop = function(id, sGroup, config) {
16517 this.init(id, sGroup, config);
16522 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16525 * The id of the element associated with this object. This is what we
16526 * refer to as the "linked element" because the size and position of
16527 * this element is used to determine when the drag and drop objects have
16535 * Configuration attributes passed into the constructor
16542 * The id of the element that will be dragged. By default this is same
16543 * as the linked element , but could be changed to another element. Ex:
16545 * @property dragElId
16552 * the id of the element that initiates the drag operation. By default
16553 * this is the linked element, but could be changed to be a child of this
16554 * element. This lets us do things like only starting the drag when the
16555 * header element within the linked html element is clicked.
16556 * @property handleElId
16563 * An associative array of HTML tags that will be ignored if clicked.
16564 * @property invalidHandleTypes
16565 * @type {string: string}
16567 invalidHandleTypes: null,
16570 * An associative array of ids for elements that will be ignored if clicked
16571 * @property invalidHandleIds
16572 * @type {string: string}
16574 invalidHandleIds: null,
16577 * An indexted array of css class names for elements that will be ignored
16579 * @property invalidHandleClasses
16582 invalidHandleClasses: null,
16585 * The linked element's absolute X position at the time the drag was
16587 * @property startPageX
16594 * The linked element's absolute X position at the time the drag was
16596 * @property startPageY
16603 * The group defines a logical collection of DragDrop objects that are
16604 * related. Instances only get events when interacting with other
16605 * DragDrop object in the same group. This lets us define multiple
16606 * groups using a single DragDrop subclass if we want.
16608 * @type {string: string}
16613 * Individual drag/drop instances can be locked. This will prevent
16614 * onmousedown start drag.
16622 * Lock this instance
16625 lock: function() { this.locked = true; },
16628 * Unlock this instace
16631 unlock: function() { this.locked = false; },
16634 * By default, all insances can be a drop target. This can be disabled by
16635 * setting isTarget to false.
16642 * The padding configured for this drag and drop object for calculating
16643 * the drop zone intersection with this object.
16650 * Cached reference to the linked element
16651 * @property _domRef
16657 * Internal typeof flag
16658 * @property __ygDragDrop
16661 __ygDragDrop: true,
16664 * Set to true when horizontal contraints are applied
16665 * @property constrainX
16672 * Set to true when vertical contraints are applied
16673 * @property constrainY
16680 * The left constraint
16688 * The right constraint
16696 * The up constraint
16705 * The down constraint
16713 * Maintain offsets when we resetconstraints. Set to true when you want
16714 * the position of the element relative to its parent to stay the same
16715 * when the page changes
16717 * @property maintainOffset
16720 maintainOffset: false,
16723 * Array of pixel locations the element will snap to if we specified a
16724 * horizontal graduation/interval. This array is generated automatically
16725 * when you define a tick interval.
16732 * Array of pixel locations the element will snap to if we specified a
16733 * vertical graduation/interval. This array is generated automatically
16734 * when you define a tick interval.
16741 * By default the drag and drop instance will only respond to the primary
16742 * button click (left button for a right-handed mouse). Set to true to
16743 * allow drag and drop to start with any mouse click that is propogated
16745 * @property primaryButtonOnly
16748 primaryButtonOnly: true,
16751 * The availabe property is false until the linked dom element is accessible.
16752 * @property available
16758 * By default, drags can only be initiated if the mousedown occurs in the
16759 * region the linked element is. This is done in part to work around a
16760 * bug in some browsers that mis-report the mousedown if the previous
16761 * mouseup happened outside of the window. This property is set to true
16762 * if outer handles are defined.
16764 * @property hasOuterHandles
16768 hasOuterHandles: false,
16771 * Code that executes immediately before the startDrag event
16772 * @method b4StartDrag
16775 b4StartDrag: function(x, y) { },
16778 * Abstract method called after a drag/drop object is clicked
16779 * and the drag or mousedown time thresholds have beeen met.
16780 * @method startDrag
16781 * @param {int} X click location
16782 * @param {int} Y click location
16784 startDrag: function(x, y) { /* override this */ },
16787 * Code that executes immediately before the onDrag event
16791 b4Drag: function(e) { },
16794 * Abstract method called during the onMouseMove event while dragging an
16797 * @param {Event} e the mousemove event
16799 onDrag: function(e) { /* override this */ },
16802 * Abstract method called when this element fist begins hovering over
16803 * another DragDrop obj
16804 * @method onDragEnter
16805 * @param {Event} e the mousemove event
16806 * @param {String|DragDrop[]} id In POINT mode, the element
16807 * id this is hovering over. In INTERSECT mode, an array of one or more
16808 * dragdrop items being hovered over.
16810 onDragEnter: function(e, id) { /* override this */ },
16813 * Code that executes immediately before the onDragOver event
16814 * @method b4DragOver
16817 b4DragOver: function(e) { },
16820 * Abstract method called when this element is hovering over another
16822 * @method onDragOver
16823 * @param {Event} e the mousemove event
16824 * @param {String|DragDrop[]} id In POINT mode, the element
16825 * id this is hovering over. In INTERSECT mode, an array of dd items
16826 * being hovered over.
16828 onDragOver: function(e, id) { /* override this */ },
16831 * Code that executes immediately before the onDragOut event
16832 * @method b4DragOut
16835 b4DragOut: function(e) { },
16838 * Abstract method called when we are no longer hovering over an element
16839 * @method onDragOut
16840 * @param {Event} e the mousemove event
16841 * @param {String|DragDrop[]} id In POINT mode, the element
16842 * id this was hovering over. In INTERSECT mode, an array of dd items
16843 * that the mouse is no longer over.
16845 onDragOut: function(e, id) { /* override this */ },
16848 * Code that executes immediately before the onDragDrop event
16849 * @method b4DragDrop
16852 b4DragDrop: function(e) { },
16855 * Abstract method called when this item is dropped on another DragDrop
16857 * @method onDragDrop
16858 * @param {Event} e the mouseup event
16859 * @param {String|DragDrop[]} id In POINT mode, the element
16860 * id this was dropped on. In INTERSECT mode, an array of dd items this
16863 onDragDrop: function(e, id) { /* override this */ },
16866 * Abstract method called when this item is dropped on an area with no
16868 * @method onInvalidDrop
16869 * @param {Event} e the mouseup event
16871 onInvalidDrop: function(e) { /* override this */ },
16874 * Code that executes immediately before the endDrag event
16875 * @method b4EndDrag
16878 b4EndDrag: function(e) { },
16881 * Fired when we are done dragging the object
16883 * @param {Event} e the mouseup event
16885 endDrag: function(e) { /* override this */ },
16888 * Code executed immediately before the onMouseDown event
16889 * @method b4MouseDown
16890 * @param {Event} e the mousedown event
16893 b4MouseDown: function(e) { },
16896 * Event handler that fires when a drag/drop obj gets a mousedown
16897 * @method onMouseDown
16898 * @param {Event} e the mousedown event
16900 onMouseDown: function(e) { /* override this */ },
16903 * Event handler that fires when a drag/drop obj gets a mouseup
16904 * @method onMouseUp
16905 * @param {Event} e the mouseup event
16907 onMouseUp: function(e) { /* override this */ },
16910 * Override the onAvailable method to do what is needed after the initial
16911 * position was determined.
16912 * @method onAvailable
16914 onAvailable: function () {
16918 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16921 defaultPadding : {left:0, right:0, top:0, bottom:0},
16924 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16928 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16929 { dragElId: "existingProxyDiv" });
16930 dd.startDrag = function(){
16931 this.constrainTo("parent-id");
16934 * Or you can initalize it using the {@link Roo.Element} object:
16936 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16937 startDrag : function(){
16938 this.constrainTo("parent-id");
16942 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16943 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16944 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16945 * an object containing the sides to pad. For example: {right:10, bottom:10}
16946 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16948 constrainTo : function(constrainTo, pad, inContent){
16949 if(typeof pad == "number"){
16950 pad = {left: pad, right:pad, top:pad, bottom:pad};
16952 pad = pad || this.defaultPadding;
16953 var b = Roo.get(this.getEl()).getBox();
16954 var ce = Roo.get(constrainTo);
16955 var s = ce.getScroll();
16956 var c, cd = ce.dom;
16957 if(cd == document.body){
16958 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16961 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16965 var topSpace = b.y - c.y;
16966 var leftSpace = b.x - c.x;
16968 this.resetConstraints();
16969 this.setXConstraint(leftSpace - (pad.left||0), // left
16970 c.width - leftSpace - b.width - (pad.right||0) //right
16972 this.setYConstraint(topSpace - (pad.top||0), //top
16973 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16978 * Returns a reference to the linked element
16980 * @return {HTMLElement} the html element
16982 getEl: function() {
16983 if (!this._domRef) {
16984 this._domRef = Roo.getDom(this.id);
16987 return this._domRef;
16991 * Returns a reference to the actual element to drag. By default this is
16992 * the same as the html element, but it can be assigned to another
16993 * element. An example of this can be found in Roo.dd.DDProxy
16994 * @method getDragEl
16995 * @return {HTMLElement} the html element
16997 getDragEl: function() {
16998 return Roo.getDom(this.dragElId);
17002 * Sets up the DragDrop object. Must be called in the constructor of any
17003 * Roo.dd.DragDrop subclass
17005 * @param id the id of the linked element
17006 * @param {String} sGroup the group of related items
17007 * @param {object} config configuration attributes
17009 init: function(id, sGroup, config) {
17010 this.initTarget(id, sGroup, config);
17011 if (!Roo.isTouch) {
17012 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17014 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17015 // Event.on(this.id, "selectstart", Event.preventDefault);
17019 * Initializes Targeting functionality only... the object does not
17020 * get a mousedown handler.
17021 * @method initTarget
17022 * @param id the id of the linked element
17023 * @param {String} sGroup the group of related items
17024 * @param {object} config configuration attributes
17026 initTarget: function(id, sGroup, config) {
17028 // configuration attributes
17029 this.config = config || {};
17031 // create a local reference to the drag and drop manager
17032 this.DDM = Roo.dd.DDM;
17033 // initialize the groups array
17036 // assume that we have an element reference instead of an id if the
17037 // parameter is not a string
17038 if (typeof id !== "string") {
17045 // add to an interaction group
17046 this.addToGroup((sGroup) ? sGroup : "default");
17048 // We don't want to register this as the handle with the manager
17049 // so we just set the id rather than calling the setter.
17050 this.handleElId = id;
17052 // the linked element is the element that gets dragged by default
17053 this.setDragElId(id);
17055 // by default, clicked anchors will not start drag operations.
17056 this.invalidHandleTypes = { A: "A" };
17057 this.invalidHandleIds = {};
17058 this.invalidHandleClasses = [];
17060 this.applyConfig();
17062 this.handleOnAvailable();
17066 * Applies the configuration parameters that were passed into the constructor.
17067 * This is supposed to happen at each level through the inheritance chain. So
17068 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17069 * DragDrop in order to get all of the parameters that are available in
17071 * @method applyConfig
17073 applyConfig: function() {
17075 // configurable properties:
17076 // padding, isTarget, maintainOffset, primaryButtonOnly
17077 this.padding = this.config.padding || [0, 0, 0, 0];
17078 this.isTarget = (this.config.isTarget !== false);
17079 this.maintainOffset = (this.config.maintainOffset);
17080 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17085 * Executed when the linked element is available
17086 * @method handleOnAvailable
17089 handleOnAvailable: function() {
17090 this.available = true;
17091 this.resetConstraints();
17092 this.onAvailable();
17096 * Configures the padding for the target zone in px. Effectively expands
17097 * (or reduces) the virtual object size for targeting calculations.
17098 * Supports css-style shorthand; if only one parameter is passed, all sides
17099 * will have that padding, and if only two are passed, the top and bottom
17100 * will have the first param, the left and right the second.
17101 * @method setPadding
17102 * @param {int} iTop Top pad
17103 * @param {int} iRight Right pad
17104 * @param {int} iBot Bot pad
17105 * @param {int} iLeft Left pad
17107 setPadding: function(iTop, iRight, iBot, iLeft) {
17108 // this.padding = [iLeft, iRight, iTop, iBot];
17109 if (!iRight && 0 !== iRight) {
17110 this.padding = [iTop, iTop, iTop, iTop];
17111 } else if (!iBot && 0 !== iBot) {
17112 this.padding = [iTop, iRight, iTop, iRight];
17114 this.padding = [iTop, iRight, iBot, iLeft];
17119 * Stores the initial placement of the linked element.
17120 * @method setInitialPosition
17121 * @param {int} diffX the X offset, default 0
17122 * @param {int} diffY the Y offset, default 0
17124 setInitPosition: function(diffX, diffY) {
17125 var el = this.getEl();
17127 if (!this.DDM.verifyEl(el)) {
17131 var dx = diffX || 0;
17132 var dy = diffY || 0;
17134 var p = Dom.getXY( el );
17136 this.initPageX = p[0] - dx;
17137 this.initPageY = p[1] - dy;
17139 this.lastPageX = p[0];
17140 this.lastPageY = p[1];
17143 this.setStartPosition(p);
17147 * Sets the start position of the element. This is set when the obj
17148 * is initialized, the reset when a drag is started.
17149 * @method setStartPosition
17150 * @param pos current position (from previous lookup)
17153 setStartPosition: function(pos) {
17154 var p = pos || Dom.getXY( this.getEl() );
17155 this.deltaSetXY = null;
17157 this.startPageX = p[0];
17158 this.startPageY = p[1];
17162 * Add this instance to a group of related drag/drop objects. All
17163 * instances belong to at least one group, and can belong to as many
17164 * groups as needed.
17165 * @method addToGroup
17166 * @param sGroup {string} the name of the group
17168 addToGroup: function(sGroup) {
17169 this.groups[sGroup] = true;
17170 this.DDM.regDragDrop(this, sGroup);
17174 * Remove's this instance from the supplied interaction group
17175 * @method removeFromGroup
17176 * @param {string} sGroup The group to drop
17178 removeFromGroup: function(sGroup) {
17179 if (this.groups[sGroup]) {
17180 delete this.groups[sGroup];
17183 this.DDM.removeDDFromGroup(this, sGroup);
17187 * Allows you to specify that an element other than the linked element
17188 * will be moved with the cursor during a drag
17189 * @method setDragElId
17190 * @param id {string} the id of the element that will be used to initiate the drag
17192 setDragElId: function(id) {
17193 this.dragElId = id;
17197 * Allows you to specify a child of the linked element that should be
17198 * used to initiate the drag operation. An example of this would be if
17199 * you have a content div with text and links. Clicking anywhere in the
17200 * content area would normally start the drag operation. Use this method
17201 * to specify that an element inside of the content div is the element
17202 * that starts the drag operation.
17203 * @method setHandleElId
17204 * @param id {string} the id of the element that will be used to
17205 * initiate the drag.
17207 setHandleElId: function(id) {
17208 if (typeof id !== "string") {
17211 this.handleElId = id;
17212 this.DDM.regHandle(this.id, id);
17216 * Allows you to set an element outside of the linked element as a drag
17218 * @method setOuterHandleElId
17219 * @param id the id of the element that will be used to initiate the drag
17221 setOuterHandleElId: function(id) {
17222 if (typeof id !== "string") {
17225 Event.on(id, "mousedown",
17226 this.handleMouseDown, this);
17227 this.setHandleElId(id);
17229 this.hasOuterHandles = true;
17233 * Remove all drag and drop hooks for this element
17236 unreg: function() {
17237 Event.un(this.id, "mousedown",
17238 this.handleMouseDown);
17239 Event.un(this.id, "touchstart",
17240 this.handleMouseDown);
17241 this._domRef = null;
17242 this.DDM._remove(this);
17245 destroy : function(){
17250 * Returns true if this instance is locked, or the drag drop mgr is locked
17251 * (meaning that all drag/drop is disabled on the page.)
17253 * @return {boolean} true if this obj or all drag/drop is locked, else
17256 isLocked: function() {
17257 return (this.DDM.isLocked() || this.locked);
17261 * Fired when this object is clicked
17262 * @method handleMouseDown
17264 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17267 handleMouseDown: function(e, oDD){
17269 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17270 //Roo.log('not touch/ button !=0');
17273 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17274 return; // double touch..
17278 if (this.isLocked()) {
17279 //Roo.log('locked');
17283 this.DDM.refreshCache(this.groups);
17284 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17285 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17286 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17287 //Roo.log('no outer handes or not over target');
17290 // Roo.log('check validator');
17291 if (this.clickValidator(e)) {
17292 // Roo.log('validate success');
17293 // set the initial element position
17294 this.setStartPosition();
17297 this.b4MouseDown(e);
17298 this.onMouseDown(e);
17300 this.DDM.handleMouseDown(e, this);
17302 this.DDM.stopEvent(e);
17310 clickValidator: function(e) {
17311 var target = e.getTarget();
17312 return ( this.isValidHandleChild(target) &&
17313 (this.id == this.handleElId ||
17314 this.DDM.handleWasClicked(target, this.id)) );
17318 * Allows you to specify a tag name that should not start a drag operation
17319 * when clicked. This is designed to facilitate embedding links within a
17320 * drag handle that do something other than start the drag.
17321 * @method addInvalidHandleType
17322 * @param {string} tagName the type of element to exclude
17324 addInvalidHandleType: function(tagName) {
17325 var type = tagName.toUpperCase();
17326 this.invalidHandleTypes[type] = type;
17330 * Lets you to specify an element id for a child of a drag handle
17331 * that should not initiate a drag
17332 * @method addInvalidHandleId
17333 * @param {string} id the element id of the element you wish to ignore
17335 addInvalidHandleId: function(id) {
17336 if (typeof id !== "string") {
17339 this.invalidHandleIds[id] = id;
17343 * Lets you specify a css class of elements that will not initiate a drag
17344 * @method addInvalidHandleClass
17345 * @param {string} cssClass the class of the elements you wish to ignore
17347 addInvalidHandleClass: function(cssClass) {
17348 this.invalidHandleClasses.push(cssClass);
17352 * Unsets an excluded tag name set by addInvalidHandleType
17353 * @method removeInvalidHandleType
17354 * @param {string} tagName the type of element to unexclude
17356 removeInvalidHandleType: function(tagName) {
17357 var type = tagName.toUpperCase();
17358 // this.invalidHandleTypes[type] = null;
17359 delete this.invalidHandleTypes[type];
17363 * Unsets an invalid handle id
17364 * @method removeInvalidHandleId
17365 * @param {string} id the id of the element to re-enable
17367 removeInvalidHandleId: function(id) {
17368 if (typeof id !== "string") {
17371 delete this.invalidHandleIds[id];
17375 * Unsets an invalid css class
17376 * @method removeInvalidHandleClass
17377 * @param {string} cssClass the class of the element(s) you wish to
17380 removeInvalidHandleClass: function(cssClass) {
17381 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17382 if (this.invalidHandleClasses[i] == cssClass) {
17383 delete this.invalidHandleClasses[i];
17389 * Checks the tag exclusion list to see if this click should be ignored
17390 * @method isValidHandleChild
17391 * @param {HTMLElement} node the HTMLElement to evaluate
17392 * @return {boolean} true if this is a valid tag type, false if not
17394 isValidHandleChild: function(node) {
17397 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17400 nodeName = node.nodeName.toUpperCase();
17402 nodeName = node.nodeName;
17404 valid = valid && !this.invalidHandleTypes[nodeName];
17405 valid = valid && !this.invalidHandleIds[node.id];
17407 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17408 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17417 * Create the array of horizontal tick marks if an interval was specified
17418 * in setXConstraint().
17419 * @method setXTicks
17422 setXTicks: function(iStartX, iTickSize) {
17424 this.xTickSize = iTickSize;
17428 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17430 this.xTicks[this.xTicks.length] = i;
17435 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17437 this.xTicks[this.xTicks.length] = i;
17442 this.xTicks.sort(this.DDM.numericSort) ;
17446 * Create the array of vertical tick marks if an interval was specified in
17447 * setYConstraint().
17448 * @method setYTicks
17451 setYTicks: function(iStartY, iTickSize) {
17453 this.yTickSize = iTickSize;
17457 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17459 this.yTicks[this.yTicks.length] = i;
17464 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17466 this.yTicks[this.yTicks.length] = i;
17471 this.yTicks.sort(this.DDM.numericSort) ;
17475 * By default, the element can be dragged any place on the screen. Use
17476 * this method to limit the horizontal travel of the element. Pass in
17477 * 0,0 for the parameters if you want to lock the drag to the y axis.
17478 * @method setXConstraint
17479 * @param {int} iLeft the number of pixels the element can move to the left
17480 * @param {int} iRight the number of pixels the element can move to the
17482 * @param {int} iTickSize optional parameter for specifying that the
17484 * should move iTickSize pixels at a time.
17486 setXConstraint: function(iLeft, iRight, iTickSize) {
17487 this.leftConstraint = iLeft;
17488 this.rightConstraint = iRight;
17490 this.minX = this.initPageX - iLeft;
17491 this.maxX = this.initPageX + iRight;
17492 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17494 this.constrainX = true;
17498 * Clears any constraints applied to this instance. Also clears ticks
17499 * since they can't exist independent of a constraint at this time.
17500 * @method clearConstraints
17502 clearConstraints: function() {
17503 this.constrainX = false;
17504 this.constrainY = false;
17509 * Clears any tick interval defined for this instance
17510 * @method clearTicks
17512 clearTicks: function() {
17513 this.xTicks = null;
17514 this.yTicks = null;
17515 this.xTickSize = 0;
17516 this.yTickSize = 0;
17520 * By default, the element can be dragged any place on the screen. Set
17521 * this to limit the vertical travel of the element. Pass in 0,0 for the
17522 * parameters if you want to lock the drag to the x axis.
17523 * @method setYConstraint
17524 * @param {int} iUp the number of pixels the element can move up
17525 * @param {int} iDown the number of pixels the element can move down
17526 * @param {int} iTickSize optional parameter for specifying that the
17527 * element should move iTickSize pixels at a time.
17529 setYConstraint: function(iUp, iDown, iTickSize) {
17530 this.topConstraint = iUp;
17531 this.bottomConstraint = iDown;
17533 this.minY = this.initPageY - iUp;
17534 this.maxY = this.initPageY + iDown;
17535 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17537 this.constrainY = true;
17542 * resetConstraints must be called if you manually reposition a dd element.
17543 * @method resetConstraints
17544 * @param {boolean} maintainOffset
17546 resetConstraints: function() {
17549 // Maintain offsets if necessary
17550 if (this.initPageX || this.initPageX === 0) {
17551 // figure out how much this thing has moved
17552 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17553 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17555 this.setInitPosition(dx, dy);
17557 // This is the first time we have detected the element's position
17559 this.setInitPosition();
17562 if (this.constrainX) {
17563 this.setXConstraint( this.leftConstraint,
17564 this.rightConstraint,
17568 if (this.constrainY) {
17569 this.setYConstraint( this.topConstraint,
17570 this.bottomConstraint,
17576 * Normally the drag element is moved pixel by pixel, but we can specify
17577 * that it move a number of pixels at a time. This method resolves the
17578 * location when we have it set up like this.
17580 * @param {int} val where we want to place the object
17581 * @param {int[]} tickArray sorted array of valid points
17582 * @return {int} the closest tick
17585 getTick: function(val, tickArray) {
17588 // If tick interval is not defined, it is effectively 1 pixel,
17589 // so we return the value passed to us.
17591 } else if (tickArray[0] >= val) {
17592 // The value is lower than the first tick, so we return the first
17594 return tickArray[0];
17596 for (var i=0, len=tickArray.length; i<len; ++i) {
17598 if (tickArray[next] && tickArray[next] >= val) {
17599 var diff1 = val - tickArray[i];
17600 var diff2 = tickArray[next] - val;
17601 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17605 // The value is larger than the last tick, so we return the last
17607 return tickArray[tickArray.length - 1];
17614 * @return {string} string representation of the dd obj
17616 toString: function() {
17617 return ("DragDrop " + this.id);
17625 * Ext JS Library 1.1.1
17626 * Copyright(c) 2006-2007, Ext JS, LLC.
17628 * Originally Released Under LGPL - original licence link has changed is not relivant.
17631 * <script type="text/javascript">
17636 * The drag and drop utility provides a framework for building drag and drop
17637 * applications. In addition to enabling drag and drop for specific elements,
17638 * the drag and drop elements are tracked by the manager class, and the
17639 * interactions between the various elements are tracked during the drag and
17640 * the implementing code is notified about these important moments.
17643 // Only load the library once. Rewriting the manager class would orphan
17644 // existing drag and drop instances.
17645 if (!Roo.dd.DragDropMgr) {
17648 * @class Roo.dd.DragDropMgr
17649 * DragDropMgr is a singleton that tracks the element interaction for
17650 * all DragDrop items in the window. Generally, you will not call
17651 * this class directly, but it does have helper methods that could
17652 * be useful in your DragDrop implementations.
17655 Roo.dd.DragDropMgr = function() {
17657 var Event = Roo.EventManager;
17662 * Two dimensional Array of registered DragDrop objects. The first
17663 * dimension is the DragDrop item group, the second the DragDrop
17666 * @type {string: string}
17673 * Array of element ids defined as drag handles. Used to determine
17674 * if the element that generated the mousedown event is actually the
17675 * handle and not the html element itself.
17676 * @property handleIds
17677 * @type {string: string}
17684 * the DragDrop object that is currently being dragged
17685 * @property dragCurrent
17693 * the DragDrop object(s) that are being hovered over
17694 * @property dragOvers
17702 * the X distance between the cursor and the object being dragged
17711 * the Y distance between the cursor and the object being dragged
17720 * Flag to determine if we should prevent the default behavior of the
17721 * events we define. By default this is true, but this can be set to
17722 * false if you need the default behavior (not recommended)
17723 * @property preventDefault
17727 preventDefault: true,
17730 * Flag to determine if we should stop the propagation of the events
17731 * we generate. This is true by default but you may want to set it to
17732 * false if the html element contains other features that require the
17734 * @property stopPropagation
17738 stopPropagation: true,
17741 * Internal flag that is set to true when drag and drop has been
17743 * @property initialized
17750 * All drag and drop can be disabled.
17758 * Called the first time an element is registered.
17764 this.initialized = true;
17768 * In point mode, drag and drop interaction is defined by the
17769 * location of the cursor during the drag/drop
17777 * In intersect mode, drag and drop interactio nis defined by the
17778 * overlap of two or more drag and drop objects.
17779 * @property INTERSECT
17786 * The current drag and drop mode. Default: POINT
17794 * Runs method on all drag and drop objects
17795 * @method _execOnAll
17799 _execOnAll: function(sMethod, args) {
17800 for (var i in this.ids) {
17801 for (var j in this.ids[i]) {
17802 var oDD = this.ids[i][j];
17803 if (! this.isTypeOfDD(oDD)) {
17806 oDD[sMethod].apply(oDD, args);
17812 * Drag and drop initialization. Sets up the global event handlers
17817 _onLoad: function() {
17821 if (!Roo.isTouch) {
17822 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17823 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17825 Event.on(document, "touchend", this.handleMouseUp, this, true);
17826 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17828 Event.on(window, "unload", this._onUnload, this, true);
17829 Event.on(window, "resize", this._onResize, this, true);
17830 // Event.on(window, "mouseout", this._test);
17835 * Reset constraints on all drag and drop objs
17836 * @method _onResize
17840 _onResize: function(e) {
17841 this._execOnAll("resetConstraints", []);
17845 * Lock all drag and drop functionality
17849 lock: function() { this.locked = true; },
17852 * Unlock all drag and drop functionality
17856 unlock: function() { this.locked = false; },
17859 * Is drag and drop locked?
17861 * @return {boolean} True if drag and drop is locked, false otherwise.
17864 isLocked: function() { return this.locked; },
17867 * Location cache that is set for all drag drop objects when a drag is
17868 * initiated, cleared when the drag is finished.
17869 * @property locationCache
17876 * Set useCache to false if you want to force object the lookup of each
17877 * drag and drop linked element constantly during a drag.
17878 * @property useCache
17885 * The number of pixels that the mouse needs to move after the
17886 * mousedown before the drag is initiated. Default=3;
17887 * @property clickPixelThresh
17891 clickPixelThresh: 3,
17894 * The number of milliseconds after the mousedown event to initiate the
17895 * drag if we don't get a mouseup event. Default=1000
17896 * @property clickTimeThresh
17900 clickTimeThresh: 350,
17903 * Flag that indicates that either the drag pixel threshold or the
17904 * mousdown time threshold has been met
17905 * @property dragThreshMet
17910 dragThreshMet: false,
17913 * Timeout used for the click time threshold
17914 * @property clickTimeout
17919 clickTimeout: null,
17922 * The X position of the mousedown event stored for later use when a
17923 * drag threshold is met.
17932 * The Y position of the mousedown event stored for later use when a
17933 * drag threshold is met.
17942 * Each DragDrop instance must be registered with the DragDropMgr.
17943 * This is executed in DragDrop.init()
17944 * @method regDragDrop
17945 * @param {DragDrop} oDD the DragDrop object to register
17946 * @param {String} sGroup the name of the group this element belongs to
17949 regDragDrop: function(oDD, sGroup) {
17950 if (!this.initialized) { this.init(); }
17952 if (!this.ids[sGroup]) {
17953 this.ids[sGroup] = {};
17955 this.ids[sGroup][oDD.id] = oDD;
17959 * Removes the supplied dd instance from the supplied group. Executed
17960 * by DragDrop.removeFromGroup, so don't call this function directly.
17961 * @method removeDDFromGroup
17965 removeDDFromGroup: function(oDD, sGroup) {
17966 if (!this.ids[sGroup]) {
17967 this.ids[sGroup] = {};
17970 var obj = this.ids[sGroup];
17971 if (obj && obj[oDD.id]) {
17972 delete obj[oDD.id];
17977 * Unregisters a drag and drop item. This is executed in
17978 * DragDrop.unreg, use that method instead of calling this directly.
17983 _remove: function(oDD) {
17984 for (var g in oDD.groups) {
17985 if (g && this.ids[g][oDD.id]) {
17986 delete this.ids[g][oDD.id];
17989 delete this.handleIds[oDD.id];
17993 * Each DragDrop handle element must be registered. This is done
17994 * automatically when executing DragDrop.setHandleElId()
17995 * @method regHandle
17996 * @param {String} sDDId the DragDrop id this element is a handle for
17997 * @param {String} sHandleId the id of the element that is the drag
18001 regHandle: function(sDDId, sHandleId) {
18002 if (!this.handleIds[sDDId]) {
18003 this.handleIds[sDDId] = {};
18005 this.handleIds[sDDId][sHandleId] = sHandleId;
18009 * Utility function to determine if a given element has been
18010 * registered as a drag drop item.
18011 * @method isDragDrop
18012 * @param {String} id the element id to check
18013 * @return {boolean} true if this element is a DragDrop item,
18017 isDragDrop: function(id) {
18018 return ( this.getDDById(id) ) ? true : false;
18022 * Returns the drag and drop instances that are in all groups the
18023 * passed in instance belongs to.
18024 * @method getRelated
18025 * @param {DragDrop} p_oDD the obj to get related data for
18026 * @param {boolean} bTargetsOnly if true, only return targetable objs
18027 * @return {DragDrop[]} the related instances
18030 getRelated: function(p_oDD, bTargetsOnly) {
18032 for (var i in p_oDD.groups) {
18033 for (j in this.ids[i]) {
18034 var dd = this.ids[i][j];
18035 if (! this.isTypeOfDD(dd)) {
18038 if (!bTargetsOnly || dd.isTarget) {
18039 oDDs[oDDs.length] = dd;
18048 * Returns true if the specified dd target is a legal target for
18049 * the specifice drag obj
18050 * @method isLegalTarget
18051 * @param {DragDrop} the drag obj
18052 * @param {DragDrop} the target
18053 * @return {boolean} true if the target is a legal target for the
18057 isLegalTarget: function (oDD, oTargetDD) {
18058 var targets = this.getRelated(oDD, true);
18059 for (var i=0, len=targets.length;i<len;++i) {
18060 if (targets[i].id == oTargetDD.id) {
18069 * My goal is to be able to transparently determine if an object is
18070 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18071 * returns "object", oDD.constructor.toString() always returns
18072 * "DragDrop" and not the name of the subclass. So for now it just
18073 * evaluates a well-known variable in DragDrop.
18074 * @method isTypeOfDD
18075 * @param {Object} the object to evaluate
18076 * @return {boolean} true if typeof oDD = DragDrop
18079 isTypeOfDD: function (oDD) {
18080 return (oDD && oDD.__ygDragDrop);
18084 * Utility function to determine if a given element has been
18085 * registered as a drag drop handle for the given Drag Drop object.
18087 * @param {String} id the element id to check
18088 * @return {boolean} true if this element is a DragDrop handle, false
18092 isHandle: function(sDDId, sHandleId) {
18093 return ( this.handleIds[sDDId] &&
18094 this.handleIds[sDDId][sHandleId] );
18098 * Returns the DragDrop instance for a given id
18099 * @method getDDById
18100 * @param {String} id the id of the DragDrop object
18101 * @return {DragDrop} the drag drop object, null if it is not found
18104 getDDById: function(id) {
18105 for (var i in this.ids) {
18106 if (this.ids[i][id]) {
18107 return this.ids[i][id];
18114 * Fired after a registered DragDrop object gets the mousedown event.
18115 * Sets up the events required to track the object being dragged
18116 * @method handleMouseDown
18117 * @param {Event} e the event
18118 * @param oDD the DragDrop object being dragged
18122 handleMouseDown: function(e, oDD) {
18124 Roo.QuickTips.disable();
18126 this.currentTarget = e.getTarget();
18128 this.dragCurrent = oDD;
18130 var el = oDD.getEl();
18132 // track start position
18133 this.startX = e.getPageX();
18134 this.startY = e.getPageY();
18136 this.deltaX = this.startX - el.offsetLeft;
18137 this.deltaY = this.startY - el.offsetTop;
18139 this.dragThreshMet = false;
18141 this.clickTimeout = setTimeout(
18143 var DDM = Roo.dd.DDM;
18144 DDM.startDrag(DDM.startX, DDM.startY);
18146 this.clickTimeThresh );
18150 * Fired when either the drag pixel threshol or the mousedown hold
18151 * time threshold has been met.
18152 * @method startDrag
18153 * @param x {int} the X position of the original mousedown
18154 * @param y {int} the Y position of the original mousedown
18157 startDrag: function(x, y) {
18158 clearTimeout(this.clickTimeout);
18159 if (this.dragCurrent) {
18160 this.dragCurrent.b4StartDrag(x, y);
18161 this.dragCurrent.startDrag(x, y);
18163 this.dragThreshMet = true;
18167 * Internal function to handle the mouseup event. Will be invoked
18168 * from the context of the document.
18169 * @method handleMouseUp
18170 * @param {Event} e the event
18174 handleMouseUp: function(e) {
18177 Roo.QuickTips.enable();
18179 if (! this.dragCurrent) {
18183 clearTimeout(this.clickTimeout);
18185 if (this.dragThreshMet) {
18186 this.fireEvents(e, true);
18196 * Utility to stop event propagation and event default, if these
18197 * features are turned on.
18198 * @method stopEvent
18199 * @param {Event} e the event as returned by this.getEvent()
18202 stopEvent: function(e){
18203 if(this.stopPropagation) {
18204 e.stopPropagation();
18207 if (this.preventDefault) {
18208 e.preventDefault();
18213 * Internal function to clean up event handlers after the drag
18214 * operation is complete
18216 * @param {Event} e the event
18220 stopDrag: function(e) {
18221 // Fire the drag end event for the item that was dragged
18222 if (this.dragCurrent) {
18223 if (this.dragThreshMet) {
18224 this.dragCurrent.b4EndDrag(e);
18225 this.dragCurrent.endDrag(e);
18228 this.dragCurrent.onMouseUp(e);
18231 this.dragCurrent = null;
18232 this.dragOvers = {};
18236 * Internal function to handle the mousemove event. Will be invoked
18237 * from the context of the html element.
18239 * @TODO figure out what we can do about mouse events lost when the
18240 * user drags objects beyond the window boundary. Currently we can
18241 * detect this in internet explorer by verifying that the mouse is
18242 * down during the mousemove event. Firefox doesn't give us the
18243 * button state on the mousemove event.
18244 * @method handleMouseMove
18245 * @param {Event} e the event
18249 handleMouseMove: function(e) {
18250 if (! this.dragCurrent) {
18254 // var button = e.which || e.button;
18256 // check for IE mouseup outside of page boundary
18257 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18259 return this.handleMouseUp(e);
18262 if (!this.dragThreshMet) {
18263 var diffX = Math.abs(this.startX - e.getPageX());
18264 var diffY = Math.abs(this.startY - e.getPageY());
18265 if (diffX > this.clickPixelThresh ||
18266 diffY > this.clickPixelThresh) {
18267 this.startDrag(this.startX, this.startY);
18271 if (this.dragThreshMet) {
18272 this.dragCurrent.b4Drag(e);
18273 this.dragCurrent.onDrag(e);
18274 if(!this.dragCurrent.moveOnly){
18275 this.fireEvents(e, false);
18285 * Iterates over all of the DragDrop elements to find ones we are
18286 * hovering over or dropping on
18287 * @method fireEvents
18288 * @param {Event} e the event
18289 * @param {boolean} isDrop is this a drop op or a mouseover op?
18293 fireEvents: function(e, isDrop) {
18294 var dc = this.dragCurrent;
18296 // If the user did the mouse up outside of the window, we could
18297 // get here even though we have ended the drag.
18298 if (!dc || dc.isLocked()) {
18302 var pt = e.getPoint();
18304 // cache the previous dragOver array
18310 var enterEvts = [];
18312 // Check to see if the object(s) we were hovering over is no longer
18313 // being hovered over so we can fire the onDragOut event
18314 for (var i in this.dragOvers) {
18316 var ddo = this.dragOvers[i];
18318 if (! this.isTypeOfDD(ddo)) {
18322 if (! this.isOverTarget(pt, ddo, this.mode)) {
18323 outEvts.push( ddo );
18326 oldOvers[i] = true;
18327 delete this.dragOvers[i];
18330 for (var sGroup in dc.groups) {
18332 if ("string" != typeof sGroup) {
18336 for (i in this.ids[sGroup]) {
18337 var oDD = this.ids[sGroup][i];
18338 if (! this.isTypeOfDD(oDD)) {
18342 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18343 if (this.isOverTarget(pt, oDD, this.mode)) {
18344 // look for drop interactions
18346 dropEvts.push( oDD );
18347 // look for drag enter and drag over interactions
18350 // initial drag over: dragEnter fires
18351 if (!oldOvers[oDD.id]) {
18352 enterEvts.push( oDD );
18353 // subsequent drag overs: dragOver fires
18355 overEvts.push( oDD );
18358 this.dragOvers[oDD.id] = oDD;
18366 if (outEvts.length) {
18367 dc.b4DragOut(e, outEvts);
18368 dc.onDragOut(e, outEvts);
18371 if (enterEvts.length) {
18372 dc.onDragEnter(e, enterEvts);
18375 if (overEvts.length) {
18376 dc.b4DragOver(e, overEvts);
18377 dc.onDragOver(e, overEvts);
18380 if (dropEvts.length) {
18381 dc.b4DragDrop(e, dropEvts);
18382 dc.onDragDrop(e, dropEvts);
18386 // fire dragout events
18388 for (i=0, len=outEvts.length; i<len; ++i) {
18389 dc.b4DragOut(e, outEvts[i].id);
18390 dc.onDragOut(e, outEvts[i].id);
18393 // fire enter events
18394 for (i=0,len=enterEvts.length; i<len; ++i) {
18395 // dc.b4DragEnter(e, oDD.id);
18396 dc.onDragEnter(e, enterEvts[i].id);
18399 // fire over events
18400 for (i=0,len=overEvts.length; i<len; ++i) {
18401 dc.b4DragOver(e, overEvts[i].id);
18402 dc.onDragOver(e, overEvts[i].id);
18405 // fire drop events
18406 for (i=0, len=dropEvts.length; i<len; ++i) {
18407 dc.b4DragDrop(e, dropEvts[i].id);
18408 dc.onDragDrop(e, dropEvts[i].id);
18413 // notify about a drop that did not find a target
18414 if (isDrop && !dropEvts.length) {
18415 dc.onInvalidDrop(e);
18421 * Helper function for getting the best match from the list of drag
18422 * and drop objects returned by the drag and drop events when we are
18423 * in INTERSECT mode. It returns either the first object that the
18424 * cursor is over, or the object that has the greatest overlap with
18425 * the dragged element.
18426 * @method getBestMatch
18427 * @param {DragDrop[]} dds The array of drag and drop objects
18429 * @return {DragDrop} The best single match
18432 getBestMatch: function(dds) {
18434 // Return null if the input is not what we expect
18435 //if (!dds || !dds.length || dds.length == 0) {
18437 // If there is only one item, it wins
18438 //} else if (dds.length == 1) {
18440 var len = dds.length;
18445 // Loop through the targeted items
18446 for (var i=0; i<len; ++i) {
18448 // If the cursor is over the object, it wins. If the
18449 // cursor is over multiple matches, the first one we come
18451 if (dd.cursorIsOver) {
18454 // Otherwise the object with the most overlap wins
18457 winner.overlap.getArea() < dd.overlap.getArea()) {
18468 * Refreshes the cache of the top-left and bottom-right points of the
18469 * drag and drop objects in the specified group(s). This is in the
18470 * format that is stored in the drag and drop instance, so typical
18473 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18477 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18479 * @TODO this really should be an indexed array. Alternatively this
18480 * method could accept both.
18481 * @method refreshCache
18482 * @param {Object} groups an associative array of groups to refresh
18485 refreshCache: function(groups) {
18486 for (var sGroup in groups) {
18487 if ("string" != typeof sGroup) {
18490 for (var i in this.ids[sGroup]) {
18491 var oDD = this.ids[sGroup][i];
18493 if (this.isTypeOfDD(oDD)) {
18494 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18495 var loc = this.getLocation(oDD);
18497 this.locationCache[oDD.id] = loc;
18499 delete this.locationCache[oDD.id];
18500 // this will unregister the drag and drop object if
18501 // the element is not in a usable state
18510 * This checks to make sure an element exists and is in the DOM. The
18511 * main purpose is to handle cases where innerHTML is used to remove
18512 * drag and drop objects from the DOM. IE provides an 'unspecified
18513 * error' when trying to access the offsetParent of such an element
18515 * @param {HTMLElement} el the element to check
18516 * @return {boolean} true if the element looks usable
18519 verifyEl: function(el) {
18524 parent = el.offsetParent;
18527 parent = el.offsetParent;
18538 * Returns a Region object containing the drag and drop element's position
18539 * and size, including the padding configured for it
18540 * @method getLocation
18541 * @param {DragDrop} oDD the drag and drop object to get the
18543 * @return {Roo.lib.Region} a Region object representing the total area
18544 * the element occupies, including any padding
18545 * the instance is configured for.
18548 getLocation: function(oDD) {
18549 if (! this.isTypeOfDD(oDD)) {
18553 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18556 pos= Roo.lib.Dom.getXY(el);
18564 x2 = x1 + el.offsetWidth;
18566 y2 = y1 + el.offsetHeight;
18568 t = y1 - oDD.padding[0];
18569 r = x2 + oDD.padding[1];
18570 b = y2 + oDD.padding[2];
18571 l = x1 - oDD.padding[3];
18573 return new Roo.lib.Region( t, r, b, l );
18577 * Checks the cursor location to see if it over the target
18578 * @method isOverTarget
18579 * @param {Roo.lib.Point} pt The point to evaluate
18580 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18581 * @return {boolean} true if the mouse is over the target
18585 isOverTarget: function(pt, oTarget, intersect) {
18586 // use cache if available
18587 var loc = this.locationCache[oTarget.id];
18588 if (!loc || !this.useCache) {
18589 loc = this.getLocation(oTarget);
18590 this.locationCache[oTarget.id] = loc;
18598 oTarget.cursorIsOver = loc.contains( pt );
18600 // DragDrop is using this as a sanity check for the initial mousedown
18601 // in this case we are done. In POINT mode, if the drag obj has no
18602 // contraints, we are also done. Otherwise we need to evaluate the
18603 // location of the target as related to the actual location of the
18604 // dragged element.
18605 var dc = this.dragCurrent;
18606 if (!dc || !dc.getTargetCoord ||
18607 (!intersect && !dc.constrainX && !dc.constrainY)) {
18608 return oTarget.cursorIsOver;
18611 oTarget.overlap = null;
18613 // Get the current location of the drag element, this is the
18614 // location of the mouse event less the delta that represents
18615 // where the original mousedown happened on the element. We
18616 // need to consider constraints and ticks as well.
18617 var pos = dc.getTargetCoord(pt.x, pt.y);
18619 var el = dc.getDragEl();
18620 var curRegion = new Roo.lib.Region( pos.y,
18621 pos.x + el.offsetWidth,
18622 pos.y + el.offsetHeight,
18625 var overlap = curRegion.intersect(loc);
18628 oTarget.overlap = overlap;
18629 return (intersect) ? true : oTarget.cursorIsOver;
18636 * unload event handler
18637 * @method _onUnload
18641 _onUnload: function(e, me) {
18642 Roo.dd.DragDropMgr.unregAll();
18646 * Cleans up the drag and drop events and objects.
18651 unregAll: function() {
18653 if (this.dragCurrent) {
18655 this.dragCurrent = null;
18658 this._execOnAll("unreg", []);
18660 for (i in this.elementCache) {
18661 delete this.elementCache[i];
18664 this.elementCache = {};
18669 * A cache of DOM elements
18670 * @property elementCache
18677 * Get the wrapper for the DOM element specified
18678 * @method getElWrapper
18679 * @param {String} id the id of the element to get
18680 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18682 * @deprecated This wrapper isn't that useful
18685 getElWrapper: function(id) {
18686 var oWrapper = this.elementCache[id];
18687 if (!oWrapper || !oWrapper.el) {
18688 oWrapper = this.elementCache[id] =
18689 new this.ElementWrapper(Roo.getDom(id));
18695 * Returns the actual DOM element
18696 * @method getElement
18697 * @param {String} id the id of the elment to get
18698 * @return {Object} The element
18699 * @deprecated use Roo.getDom instead
18702 getElement: function(id) {
18703 return Roo.getDom(id);
18707 * Returns the style property for the DOM element (i.e.,
18708 * document.getElById(id).style)
18710 * @param {String} id the id of the elment to get
18711 * @return {Object} The style property of the element
18712 * @deprecated use Roo.getDom instead
18715 getCss: function(id) {
18716 var el = Roo.getDom(id);
18717 return (el) ? el.style : null;
18721 * Inner class for cached elements
18722 * @class DragDropMgr.ElementWrapper
18727 ElementWrapper: function(el) {
18732 this.el = el || null;
18737 this.id = this.el && el.id;
18739 * A reference to the style property
18742 this.css = this.el && el.style;
18746 * Returns the X position of an html element
18748 * @param el the element for which to get the position
18749 * @return {int} the X coordinate
18751 * @deprecated use Roo.lib.Dom.getX instead
18754 getPosX: function(el) {
18755 return Roo.lib.Dom.getX(el);
18759 * Returns the Y position of an html element
18761 * @param el the element for which to get the position
18762 * @return {int} the Y coordinate
18763 * @deprecated use Roo.lib.Dom.getY instead
18766 getPosY: function(el) {
18767 return Roo.lib.Dom.getY(el);
18771 * Swap two nodes. In IE, we use the native method, for others we
18772 * emulate the IE behavior
18774 * @param n1 the first node to swap
18775 * @param n2 the other node to swap
18778 swapNode: function(n1, n2) {
18782 var p = n2.parentNode;
18783 var s = n2.nextSibling;
18786 p.insertBefore(n1, n2);
18787 } else if (n2 == n1.nextSibling) {
18788 p.insertBefore(n2, n1);
18790 n1.parentNode.replaceChild(n2, n1);
18791 p.insertBefore(n1, s);
18797 * Returns the current scroll position
18798 * @method getScroll
18802 getScroll: function () {
18803 var t, l, dde=document.documentElement, db=document.body;
18804 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18806 l = dde.scrollLeft;
18813 return { top: t, left: l };
18817 * Returns the specified element style property
18819 * @param {HTMLElement} el the element
18820 * @param {string} styleProp the style property
18821 * @return {string} The value of the style property
18822 * @deprecated use Roo.lib.Dom.getStyle
18825 getStyle: function(el, styleProp) {
18826 return Roo.fly(el).getStyle(styleProp);
18830 * Gets the scrollTop
18831 * @method getScrollTop
18832 * @return {int} the document's scrollTop
18835 getScrollTop: function () { return this.getScroll().top; },
18838 * Gets the scrollLeft
18839 * @method getScrollLeft
18840 * @return {int} the document's scrollTop
18843 getScrollLeft: function () { return this.getScroll().left; },
18846 * Sets the x/y position of an element to the location of the
18849 * @param {HTMLElement} moveEl The element to move
18850 * @param {HTMLElement} targetEl The position reference element
18853 moveToEl: function (moveEl, targetEl) {
18854 var aCoord = Roo.lib.Dom.getXY(targetEl);
18855 Roo.lib.Dom.setXY(moveEl, aCoord);
18859 * Numeric array sort function
18860 * @method numericSort
18863 numericSort: function(a, b) { return (a - b); },
18867 * @property _timeoutCount
18874 * Trying to make the load order less important. Without this we get
18875 * an error if this file is loaded before the Event Utility.
18876 * @method _addListeners
18880 _addListeners: function() {
18881 var DDM = Roo.dd.DDM;
18882 if ( Roo.lib.Event && document ) {
18885 if (DDM._timeoutCount > 2000) {
18887 setTimeout(DDM._addListeners, 10);
18888 if (document && document.body) {
18889 DDM._timeoutCount += 1;
18896 * Recursively searches the immediate parent and all child nodes for
18897 * the handle element in order to determine wheter or not it was
18899 * @method handleWasClicked
18900 * @param node the html element to inspect
18903 handleWasClicked: function(node, id) {
18904 if (this.isHandle(id, node.id)) {
18907 // check to see if this is a text node child of the one we want
18908 var p = node.parentNode;
18911 if (this.isHandle(id, p.id)) {
18926 // shorter alias, save a few bytes
18927 Roo.dd.DDM = Roo.dd.DragDropMgr;
18928 Roo.dd.DDM._addListeners();
18932 * Ext JS Library 1.1.1
18933 * Copyright(c) 2006-2007, Ext JS, LLC.
18935 * Originally Released Under LGPL - original licence link has changed is not relivant.
18938 * <script type="text/javascript">
18943 * A DragDrop implementation where the linked element follows the
18944 * mouse cursor during a drag.
18945 * @extends Roo.dd.DragDrop
18947 * @param {String} id the id of the linked element
18948 * @param {String} sGroup the group of related DragDrop items
18949 * @param {object} config an object containing configurable attributes
18950 * Valid properties for DD:
18953 Roo.dd.DD = function(id, sGroup, config) {
18955 this.init(id, sGroup, config);
18959 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18962 * When set to true, the utility automatically tries to scroll the browser
18963 * window wehn a drag and drop element is dragged near the viewport boundary.
18964 * Defaults to true.
18971 * Sets the pointer offset to the distance between the linked element's top
18972 * left corner and the location the element was clicked
18973 * @method autoOffset
18974 * @param {int} iPageX the X coordinate of the click
18975 * @param {int} iPageY the Y coordinate of the click
18977 autoOffset: function(iPageX, iPageY) {
18978 var x = iPageX - this.startPageX;
18979 var y = iPageY - this.startPageY;
18980 this.setDelta(x, y);
18984 * Sets the pointer offset. You can call this directly to force the
18985 * offset to be in a particular location (e.g., pass in 0,0 to set it
18986 * to the center of the object)
18988 * @param {int} iDeltaX the distance from the left
18989 * @param {int} iDeltaY the distance from the top
18991 setDelta: function(iDeltaX, iDeltaY) {
18992 this.deltaX = iDeltaX;
18993 this.deltaY = iDeltaY;
18997 * Sets the drag element to the location of the mousedown or click event,
18998 * maintaining the cursor location relative to the location on the element
18999 * that was clicked. Override this if you want to place the element in a
19000 * location other than where the cursor is.
19001 * @method setDragElPos
19002 * @param {int} iPageX the X coordinate of the mousedown or drag event
19003 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19005 setDragElPos: function(iPageX, iPageY) {
19006 // the first time we do this, we are going to check to make sure
19007 // the element has css positioning
19009 var el = this.getDragEl();
19010 this.alignElWithMouse(el, iPageX, iPageY);
19014 * Sets the element to the location of the mousedown or click event,
19015 * maintaining the cursor location relative to the location on the element
19016 * that was clicked. Override this if you want to place the element in a
19017 * location other than where the cursor is.
19018 * @method alignElWithMouse
19019 * @param {HTMLElement} el the element to move
19020 * @param {int} iPageX the X coordinate of the mousedown or drag event
19021 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19023 alignElWithMouse: function(el, iPageX, iPageY) {
19024 var oCoord = this.getTargetCoord(iPageX, iPageY);
19025 var fly = el.dom ? el : Roo.fly(el);
19026 if (!this.deltaSetXY) {
19027 var aCoord = [oCoord.x, oCoord.y];
19029 var newLeft = fly.getLeft(true);
19030 var newTop = fly.getTop(true);
19031 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19033 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19036 this.cachePosition(oCoord.x, oCoord.y);
19037 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19042 * Saves the most recent position so that we can reset the constraints and
19043 * tick marks on-demand. We need to know this so that we can calculate the
19044 * number of pixels the element is offset from its original position.
19045 * @method cachePosition
19046 * @param iPageX the current x position (optional, this just makes it so we
19047 * don't have to look it up again)
19048 * @param iPageY the current y position (optional, this just makes it so we
19049 * don't have to look it up again)
19051 cachePosition: function(iPageX, iPageY) {
19053 this.lastPageX = iPageX;
19054 this.lastPageY = iPageY;
19056 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19057 this.lastPageX = aCoord[0];
19058 this.lastPageY = aCoord[1];
19063 * Auto-scroll the window if the dragged object has been moved beyond the
19064 * visible window boundary.
19065 * @method autoScroll
19066 * @param {int} x the drag element's x position
19067 * @param {int} y the drag element's y position
19068 * @param {int} h the height of the drag element
19069 * @param {int} w the width of the drag element
19072 autoScroll: function(x, y, h, w) {
19075 // The client height
19076 var clientH = Roo.lib.Dom.getViewWidth();
19078 // The client width
19079 var clientW = Roo.lib.Dom.getViewHeight();
19081 // The amt scrolled down
19082 var st = this.DDM.getScrollTop();
19084 // The amt scrolled right
19085 var sl = this.DDM.getScrollLeft();
19087 // Location of the bottom of the element
19090 // Location of the right of the element
19093 // The distance from the cursor to the bottom of the visible area,
19094 // adjusted so that we don't scroll if the cursor is beyond the
19095 // element drag constraints
19096 var toBot = (clientH + st - y - this.deltaY);
19098 // The distance from the cursor to the right of the visible area
19099 var toRight = (clientW + sl - x - this.deltaX);
19102 // How close to the edge the cursor must be before we scroll
19103 // var thresh = (document.all) ? 100 : 40;
19106 // How many pixels to scroll per autoscroll op. This helps to reduce
19107 // clunky scrolling. IE is more sensitive about this ... it needs this
19108 // value to be higher.
19109 var scrAmt = (document.all) ? 80 : 30;
19111 // Scroll down if we are near the bottom of the visible page and the
19112 // obj extends below the crease
19113 if ( bot > clientH && toBot < thresh ) {
19114 window.scrollTo(sl, st + scrAmt);
19117 // Scroll up if the window is scrolled down and the top of the object
19118 // goes above the top border
19119 if ( y < st && st > 0 && y - st < thresh ) {
19120 window.scrollTo(sl, st - scrAmt);
19123 // Scroll right if the obj is beyond the right border and the cursor is
19124 // near the border.
19125 if ( right > clientW && toRight < thresh ) {
19126 window.scrollTo(sl + scrAmt, st);
19129 // Scroll left if the window has been scrolled to the right and the obj
19130 // extends past the left border
19131 if ( x < sl && sl > 0 && x - sl < thresh ) {
19132 window.scrollTo(sl - scrAmt, st);
19138 * Finds the location the element should be placed if we want to move
19139 * it to where the mouse location less the click offset would place us.
19140 * @method getTargetCoord
19141 * @param {int} iPageX the X coordinate of the click
19142 * @param {int} iPageY the Y coordinate of the click
19143 * @return an object that contains the coordinates (Object.x and Object.y)
19146 getTargetCoord: function(iPageX, iPageY) {
19149 var x = iPageX - this.deltaX;
19150 var y = iPageY - this.deltaY;
19152 if (this.constrainX) {
19153 if (x < this.minX) { x = this.minX; }
19154 if (x > this.maxX) { x = this.maxX; }
19157 if (this.constrainY) {
19158 if (y < this.minY) { y = this.minY; }
19159 if (y > this.maxY) { y = this.maxY; }
19162 x = this.getTick(x, this.xTicks);
19163 y = this.getTick(y, this.yTicks);
19170 * Sets up config options specific to this class. Overrides
19171 * Roo.dd.DragDrop, but all versions of this method through the
19172 * inheritance chain are called
19174 applyConfig: function() {
19175 Roo.dd.DD.superclass.applyConfig.call(this);
19176 this.scroll = (this.config.scroll !== false);
19180 * Event that fires prior to the onMouseDown event. Overrides
19183 b4MouseDown: function(e) {
19184 // this.resetConstraints();
19185 this.autoOffset(e.getPageX(),
19190 * Event that fires prior to the onDrag event. Overrides
19193 b4Drag: function(e) {
19194 this.setDragElPos(e.getPageX(),
19198 toString: function() {
19199 return ("DD " + this.id);
19202 //////////////////////////////////////////////////////////////////////////
19203 // Debugging ygDragDrop events that can be overridden
19204 //////////////////////////////////////////////////////////////////////////
19206 startDrag: function(x, y) {
19209 onDrag: function(e) {
19212 onDragEnter: function(e, id) {
19215 onDragOver: function(e, id) {
19218 onDragOut: function(e, id) {
19221 onDragDrop: function(e, id) {
19224 endDrag: function(e) {
19231 * Ext JS Library 1.1.1
19232 * Copyright(c) 2006-2007, Ext JS, LLC.
19234 * Originally Released Under LGPL - original licence link has changed is not relivant.
19237 * <script type="text/javascript">
19241 * @class Roo.dd.DDProxy
19242 * A DragDrop implementation that inserts an empty, bordered div into
19243 * the document that follows the cursor during drag operations. At the time of
19244 * the click, the frame div is resized to the dimensions of the linked html
19245 * element, and moved to the exact location of the linked element.
19247 * References to the "frame" element refer to the single proxy element that
19248 * was created to be dragged in place of all DDProxy elements on the
19251 * @extends Roo.dd.DD
19253 * @param {String} id the id of the linked html element
19254 * @param {String} sGroup the group of related DragDrop objects
19255 * @param {object} config an object containing configurable attributes
19256 * Valid properties for DDProxy in addition to those in DragDrop:
19257 * resizeFrame, centerFrame, dragElId
19259 Roo.dd.DDProxy = function(id, sGroup, config) {
19261 this.init(id, sGroup, config);
19267 * The default drag frame div id
19268 * @property Roo.dd.DDProxy.dragElId
19272 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19274 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19277 * By default we resize the drag frame to be the same size as the element
19278 * we want to drag (this is to get the frame effect). We can turn it off
19279 * if we want a different behavior.
19280 * @property resizeFrame
19286 * By default the frame is positioned exactly where the drag element is, so
19287 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19288 * you do not have constraints on the obj is to have the drag frame centered
19289 * around the cursor. Set centerFrame to true for this effect.
19290 * @property centerFrame
19293 centerFrame: false,
19296 * Creates the proxy element if it does not yet exist
19297 * @method createFrame
19299 createFrame: function() {
19301 var body = document.body;
19303 if (!body || !body.firstChild) {
19304 setTimeout( function() { self.createFrame(); }, 50 );
19308 var div = this.getDragEl();
19311 div = document.createElement("div");
19312 div.id = this.dragElId;
19315 s.position = "absolute";
19316 s.visibility = "hidden";
19318 s.border = "2px solid #aaa";
19321 // appendChild can blow up IE if invoked prior to the window load event
19322 // while rendering a table. It is possible there are other scenarios
19323 // that would cause this to happen as well.
19324 body.insertBefore(div, body.firstChild);
19329 * Initialization for the drag frame element. Must be called in the
19330 * constructor of all subclasses
19331 * @method initFrame
19333 initFrame: function() {
19334 this.createFrame();
19337 applyConfig: function() {
19338 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19340 this.resizeFrame = (this.config.resizeFrame !== false);
19341 this.centerFrame = (this.config.centerFrame);
19342 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19346 * Resizes the drag frame to the dimensions of the clicked object, positions
19347 * it over the object, and finally displays it
19348 * @method showFrame
19349 * @param {int} iPageX X click position
19350 * @param {int} iPageY Y click position
19353 showFrame: function(iPageX, iPageY) {
19354 var el = this.getEl();
19355 var dragEl = this.getDragEl();
19356 var s = dragEl.style;
19358 this._resizeProxy();
19360 if (this.centerFrame) {
19361 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19362 Math.round(parseInt(s.height, 10)/2) );
19365 this.setDragElPos(iPageX, iPageY);
19367 Roo.fly(dragEl).show();
19371 * The proxy is automatically resized to the dimensions of the linked
19372 * element when a drag is initiated, unless resizeFrame is set to false
19373 * @method _resizeProxy
19376 _resizeProxy: function() {
19377 if (this.resizeFrame) {
19378 var el = this.getEl();
19379 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19383 // overrides Roo.dd.DragDrop
19384 b4MouseDown: function(e) {
19385 var x = e.getPageX();
19386 var y = e.getPageY();
19387 this.autoOffset(x, y);
19388 this.setDragElPos(x, y);
19391 // overrides Roo.dd.DragDrop
19392 b4StartDrag: function(x, y) {
19393 // show the drag frame
19394 this.showFrame(x, y);
19397 // overrides Roo.dd.DragDrop
19398 b4EndDrag: function(e) {
19399 Roo.fly(this.getDragEl()).hide();
19402 // overrides Roo.dd.DragDrop
19403 // By default we try to move the element to the last location of the frame.
19404 // This is so that the default behavior mirrors that of Roo.dd.DD.
19405 endDrag: function(e) {
19407 var lel = this.getEl();
19408 var del = this.getDragEl();
19410 // Show the drag frame briefly so we can get its position
19411 del.style.visibility = "";
19414 // Hide the linked element before the move to get around a Safari
19416 lel.style.visibility = "hidden";
19417 Roo.dd.DDM.moveToEl(lel, del);
19418 del.style.visibility = "hidden";
19419 lel.style.visibility = "";
19424 beforeMove : function(){
19428 afterDrag : function(){
19432 toString: function() {
19433 return ("DDProxy " + this.id);
19439 * Ext JS Library 1.1.1
19440 * Copyright(c) 2006-2007, Ext JS, LLC.
19442 * Originally Released Under LGPL - original licence link has changed is not relivant.
19445 * <script type="text/javascript">
19449 * @class Roo.dd.DDTarget
19450 * A DragDrop implementation that does not move, but can be a drop
19451 * target. You would get the same result by simply omitting implementation
19452 * for the event callbacks, but this way we reduce the processing cost of the
19453 * event listener and the callbacks.
19454 * @extends Roo.dd.DragDrop
19456 * @param {String} id the id of the element that is a drop target
19457 * @param {String} sGroup the group of related DragDrop objects
19458 * @param {object} config an object containing configurable attributes
19459 * Valid properties for DDTarget in addition to those in
19463 Roo.dd.DDTarget = function(id, sGroup, config) {
19465 this.initTarget(id, sGroup, config);
19467 if (config.listeners || config.events) {
19468 Roo.dd.DragDrop.superclass.constructor.call(this, {
19469 listeners : config.listeners || {},
19470 events : config.events || {}
19475 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19476 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19477 toString: function() {
19478 return ("DDTarget " + this.id);
19483 * Ext JS Library 1.1.1
19484 * Copyright(c) 2006-2007, Ext JS, LLC.
19486 * Originally Released Under LGPL - original licence link has changed is not relivant.
19489 * <script type="text/javascript">
19494 * @class Roo.dd.ScrollManager
19495 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19496 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19499 Roo.dd.ScrollManager = function(){
19500 var ddm = Roo.dd.DragDropMgr;
19507 var onStop = function(e){
19512 var triggerRefresh = function(){
19513 if(ddm.dragCurrent){
19514 ddm.refreshCache(ddm.dragCurrent.groups);
19518 var doScroll = function(){
19519 if(ddm.dragCurrent){
19520 var dds = Roo.dd.ScrollManager;
19522 if(proc.el.scroll(proc.dir, dds.increment)){
19526 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19531 var clearProc = function(){
19533 clearInterval(proc.id);
19540 var startProc = function(el, dir){
19541 Roo.log('scroll startproc');
19545 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19548 var onFire = function(e, isDrop){
19550 if(isDrop || !ddm.dragCurrent){ return; }
19551 var dds = Roo.dd.ScrollManager;
19552 if(!dragEl || dragEl != ddm.dragCurrent){
19553 dragEl = ddm.dragCurrent;
19554 // refresh regions on drag start
19555 dds.refreshCache();
19558 var xy = Roo.lib.Event.getXY(e);
19559 var pt = new Roo.lib.Point(xy[0], xy[1]);
19560 for(var id in els){
19561 var el = els[id], r = el._region;
19562 if(r && r.contains(pt) && el.isScrollable()){
19563 if(r.bottom - pt.y <= dds.thresh){
19565 startProc(el, "down");
19568 }else if(r.right - pt.x <= dds.thresh){
19570 startProc(el, "left");
19573 }else if(pt.y - r.top <= dds.thresh){
19575 startProc(el, "up");
19578 }else if(pt.x - r.left <= dds.thresh){
19580 startProc(el, "right");
19589 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19590 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19594 * Registers new overflow element(s) to auto scroll
19595 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19597 register : function(el){
19598 if(el instanceof Array){
19599 for(var i = 0, len = el.length; i < len; i++) {
19600 this.register(el[i]);
19606 Roo.dd.ScrollManager.els = els;
19610 * Unregisters overflow element(s) so they are no longer scrolled
19611 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19613 unregister : function(el){
19614 if(el instanceof Array){
19615 for(var i = 0, len = el.length; i < len; i++) {
19616 this.unregister(el[i]);
19625 * The number of pixels from the edge of a container the pointer needs to be to
19626 * trigger scrolling (defaults to 25)
19632 * The number of pixels to scroll in each scroll increment (defaults to 50)
19638 * The frequency of scrolls in milliseconds (defaults to 500)
19644 * True to animate the scroll (defaults to true)
19650 * The animation duration in seconds -
19651 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19657 * Manually trigger a cache refresh.
19659 refreshCache : function(){
19660 for(var id in els){
19661 if(typeof els[id] == 'object'){ // for people extending the object prototype
19662 els[id]._region = els[id].getRegion();
19669 * Ext JS Library 1.1.1
19670 * Copyright(c) 2006-2007, Ext JS, LLC.
19672 * Originally Released Under LGPL - original licence link has changed is not relivant.
19675 * <script type="text/javascript">
19680 * @class Roo.dd.Registry
19681 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19682 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19685 Roo.dd.Registry = function(){
19688 var autoIdSeed = 0;
19690 var getId = function(el, autogen){
19691 if(typeof el == "string"){
19695 if(!id && autogen !== false){
19696 id = "roodd-" + (++autoIdSeed);
19704 * Register a drag drop element
19705 * @param {String|HTMLElement} element The id or DOM node to register
19706 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19707 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19708 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19709 * populated in the data object (if applicable):
19711 Value Description<br />
19712 --------- ------------------------------------------<br />
19713 handles Array of DOM nodes that trigger dragging<br />
19714 for the element being registered<br />
19715 isHandle True if the element passed in triggers<br />
19716 dragging itself, else false
19719 register : function(el, data){
19721 if(typeof el == "string"){
19722 el = document.getElementById(el);
19725 elements[getId(el)] = data;
19726 if(data.isHandle !== false){
19727 handles[data.ddel.id] = data;
19730 var hs = data.handles;
19731 for(var i = 0, len = hs.length; i < len; i++){
19732 handles[getId(hs[i])] = data;
19738 * Unregister a drag drop element
19739 * @param {String|HTMLElement} element The id or DOM node to unregister
19741 unregister : function(el){
19742 var id = getId(el, false);
19743 var data = elements[id];
19745 delete elements[id];
19747 var hs = data.handles;
19748 for(var i = 0, len = hs.length; i < len; i++){
19749 delete handles[getId(hs[i], false)];
19756 * Returns the handle registered for a DOM Node by id
19757 * @param {String|HTMLElement} id The DOM node or id to look up
19758 * @return {Object} handle The custom handle data
19760 getHandle : function(id){
19761 if(typeof id != "string"){ // must be element?
19764 return handles[id];
19768 * Returns the handle that is registered for the DOM node that is the target of the event
19769 * @param {Event} e The event
19770 * @return {Object} handle The custom handle data
19772 getHandleFromEvent : function(e){
19773 var t = Roo.lib.Event.getTarget(e);
19774 return t ? handles[t.id] : null;
19778 * Returns a custom data object that is registered for a DOM node by id
19779 * @param {String|HTMLElement} id The DOM node or id to look up
19780 * @return {Object} data The custom data
19782 getTarget : function(id){
19783 if(typeof id != "string"){ // must be element?
19786 return elements[id];
19790 * Returns a custom data object that is registered for the DOM node that is the target of the event
19791 * @param {Event} e The event
19792 * @return {Object} data The custom data
19794 getTargetFromEvent : function(e){
19795 var t = Roo.lib.Event.getTarget(e);
19796 return t ? elements[t.id] || handles[t.id] : null;
19801 * Ext JS Library 1.1.1
19802 * Copyright(c) 2006-2007, Ext JS, LLC.
19804 * Originally Released Under LGPL - original licence link has changed is not relivant.
19807 * <script type="text/javascript">
19812 * @class Roo.dd.StatusProxy
19813 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19814 * default drag proxy used by all Roo.dd components.
19816 * @param {Object} config
19818 Roo.dd.StatusProxy = function(config){
19819 Roo.apply(this, config);
19820 this.id = this.id || Roo.id();
19821 this.el = new Roo.Layer({
19823 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19824 {tag: "div", cls: "x-dd-drop-icon"},
19825 {tag: "div", cls: "x-dd-drag-ghost"}
19828 shadow: !config || config.shadow !== false
19830 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19831 this.dropStatus = this.dropNotAllowed;
19834 Roo.dd.StatusProxy.prototype = {
19836 * @cfg {String} dropAllowed
19837 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19839 dropAllowed : "x-dd-drop-ok",
19841 * @cfg {String} dropNotAllowed
19842 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19844 dropNotAllowed : "x-dd-drop-nodrop",
19847 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19848 * over the current target element.
19849 * @param {String} cssClass The css class for the new drop status indicator image
19851 setStatus : function(cssClass){
19852 cssClass = cssClass || this.dropNotAllowed;
19853 if(this.dropStatus != cssClass){
19854 this.el.replaceClass(this.dropStatus, cssClass);
19855 this.dropStatus = cssClass;
19860 * Resets the status indicator to the default dropNotAllowed value
19861 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19863 reset : function(clearGhost){
19864 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19865 this.dropStatus = this.dropNotAllowed;
19867 this.ghost.update("");
19872 * Updates the contents of the ghost element
19873 * @param {String} html The html that will replace the current innerHTML of the ghost element
19875 update : function(html){
19876 if(typeof html == "string"){
19877 this.ghost.update(html);
19879 this.ghost.update("");
19880 html.style.margin = "0";
19881 this.ghost.dom.appendChild(html);
19883 // ensure float = none set?? cant remember why though.
19884 var el = this.ghost.dom.firstChild;
19886 Roo.fly(el).setStyle('float', 'none');
19891 * Returns the underlying proxy {@link Roo.Layer}
19892 * @return {Roo.Layer} el
19894 getEl : function(){
19899 * Returns the ghost element
19900 * @return {Roo.Element} el
19902 getGhost : function(){
19908 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19910 hide : function(clear){
19918 * Stops the repair animation if it's currently running
19921 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19927 * Displays this proxy
19934 * Force the Layer to sync its shadow and shim positions to the element
19941 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19942 * invalid drop operation by the item being dragged.
19943 * @param {Array} xy The XY position of the element ([x, y])
19944 * @param {Function} callback The function to call after the repair is complete
19945 * @param {Object} scope The scope in which to execute the callback
19947 repair : function(xy, callback, scope){
19948 this.callback = callback;
19949 this.scope = scope;
19950 if(xy && this.animRepair !== false){
19951 this.el.addClass("x-dd-drag-repair");
19952 this.el.hideUnders(true);
19953 this.anim = this.el.shift({
19954 duration: this.repairDuration || .5,
19958 callback: this.afterRepair,
19962 this.afterRepair();
19967 afterRepair : function(){
19969 if(typeof this.callback == "function"){
19970 this.callback.call(this.scope || this);
19972 this.callback = null;
19977 * Ext JS Library 1.1.1
19978 * Copyright(c) 2006-2007, Ext JS, LLC.
19980 * Originally Released Under LGPL - original licence link has changed is not relivant.
19983 * <script type="text/javascript">
19987 * @class Roo.dd.DragSource
19988 * @extends Roo.dd.DDProxy
19989 * A simple class that provides the basic implementation needed to make any element draggable.
19991 * @param {String/HTMLElement/Element} el The container element
19992 * @param {Object} config
19994 Roo.dd.DragSource = function(el, config){
19995 this.el = Roo.get(el);
19996 this.dragData = {};
19998 Roo.apply(this, config);
20001 this.proxy = new Roo.dd.StatusProxy();
20004 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20005 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20007 this.dragging = false;
20010 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20012 * @cfg {String} dropAllowed
20013 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20015 dropAllowed : "x-dd-drop-ok",
20017 * @cfg {String} dropNotAllowed
20018 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20020 dropNotAllowed : "x-dd-drop-nodrop",
20023 * Returns the data object associated with this drag source
20024 * @return {Object} data An object containing arbitrary data
20026 getDragData : function(e){
20027 return this.dragData;
20031 onDragEnter : function(e, id){
20032 var target = Roo.dd.DragDropMgr.getDDById(id);
20033 this.cachedTarget = target;
20034 if(this.beforeDragEnter(target, e, id) !== false){
20035 if(target.isNotifyTarget){
20036 var status = target.notifyEnter(this, e, this.dragData);
20037 this.proxy.setStatus(status);
20039 this.proxy.setStatus(this.dropAllowed);
20042 if(this.afterDragEnter){
20044 * An empty function by default, but provided so that you can perform a custom action
20045 * when the dragged item enters the drop target by providing an implementation.
20046 * @param {Roo.dd.DragDrop} target The drop target
20047 * @param {Event} e The event object
20048 * @param {String} id The id of the dragged element
20049 * @method afterDragEnter
20051 this.afterDragEnter(target, e, id);
20057 * An empty function by default, but provided so that you can perform a custom action
20058 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20059 * @param {Roo.dd.DragDrop} target The drop target
20060 * @param {Event} e The event object
20061 * @param {String} id The id of the dragged element
20062 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20064 beforeDragEnter : function(target, e, id){
20069 alignElWithMouse: function() {
20070 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20075 onDragOver : function(e, id){
20076 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20077 if(this.beforeDragOver(target, e, id) !== false){
20078 if(target.isNotifyTarget){
20079 var status = target.notifyOver(this, e, this.dragData);
20080 this.proxy.setStatus(status);
20083 if(this.afterDragOver){
20085 * An empty function by default, but provided so that you can perform a custom action
20086 * while the dragged item is over the drop target by providing an implementation.
20087 * @param {Roo.dd.DragDrop} target The drop target
20088 * @param {Event} e The event object
20089 * @param {String} id The id of the dragged element
20090 * @method afterDragOver
20092 this.afterDragOver(target, e, id);
20098 * An empty function by default, but provided so that you can perform a custom action
20099 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20100 * @param {Roo.dd.DragDrop} target The drop target
20101 * @param {Event} e The event object
20102 * @param {String} id The id of the dragged element
20103 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20105 beforeDragOver : function(target, e, id){
20110 onDragOut : function(e, id){
20111 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20112 if(this.beforeDragOut(target, e, id) !== false){
20113 if(target.isNotifyTarget){
20114 target.notifyOut(this, e, this.dragData);
20116 this.proxy.reset();
20117 if(this.afterDragOut){
20119 * An empty function by default, but provided so that you can perform a custom action
20120 * after the dragged item is dragged out of the target without dropping.
20121 * @param {Roo.dd.DragDrop} target The drop target
20122 * @param {Event} e The event object
20123 * @param {String} id The id of the dragged element
20124 * @method afterDragOut
20126 this.afterDragOut(target, e, id);
20129 this.cachedTarget = null;
20133 * An empty function by default, but provided so that you can perform a custom action before the dragged
20134 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20135 * @param {Roo.dd.DragDrop} target The drop target
20136 * @param {Event} e The event object
20137 * @param {String} id The id of the dragged element
20138 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20140 beforeDragOut : function(target, e, id){
20145 onDragDrop : function(e, id){
20146 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20147 if(this.beforeDragDrop(target, e, id) !== false){
20148 if(target.isNotifyTarget){
20149 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20150 this.onValidDrop(target, e, id);
20152 this.onInvalidDrop(target, e, id);
20155 this.onValidDrop(target, e, id);
20158 if(this.afterDragDrop){
20160 * An empty function by default, but provided so that you can perform a custom action
20161 * after a valid drag drop has occurred by providing an implementation.
20162 * @param {Roo.dd.DragDrop} target The drop target
20163 * @param {Event} e The event object
20164 * @param {String} id The id of the dropped element
20165 * @method afterDragDrop
20167 this.afterDragDrop(target, e, id);
20170 delete this.cachedTarget;
20174 * An empty function by default, but provided so that you can perform a custom action before the dragged
20175 * item is dropped onto the target and optionally cancel the onDragDrop.
20176 * @param {Roo.dd.DragDrop} target The drop target
20177 * @param {Event} e The event object
20178 * @param {String} id The id of the dragged element
20179 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20181 beforeDragDrop : function(target, e, id){
20186 onValidDrop : function(target, e, id){
20188 if(this.afterValidDrop){
20190 * An empty function by default, but provided so that you can perform a custom action
20191 * after a valid drop has occurred by providing an implementation.
20192 * @param {Object} target The target DD
20193 * @param {Event} e The event object
20194 * @param {String} id The id of the dropped element
20195 * @method afterInvalidDrop
20197 this.afterValidDrop(target, e, id);
20202 getRepairXY : function(e, data){
20203 return this.el.getXY();
20207 onInvalidDrop : function(target, e, id){
20208 this.beforeInvalidDrop(target, e, id);
20209 if(this.cachedTarget){
20210 if(this.cachedTarget.isNotifyTarget){
20211 this.cachedTarget.notifyOut(this, e, this.dragData);
20213 this.cacheTarget = null;
20215 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20217 if(this.afterInvalidDrop){
20219 * An empty function by default, but provided so that you can perform a custom action
20220 * after an invalid drop has occurred by providing an implementation.
20221 * @param {Event} e The event object
20222 * @param {String} id The id of the dropped element
20223 * @method afterInvalidDrop
20225 this.afterInvalidDrop(e, id);
20230 afterRepair : function(){
20232 this.el.highlight(this.hlColor || "c3daf9");
20234 this.dragging = false;
20238 * An empty function by default, but provided so that you can perform a custom action after an invalid
20239 * drop has occurred.
20240 * @param {Roo.dd.DragDrop} target The drop target
20241 * @param {Event} e The event object
20242 * @param {String} id The id of the dragged element
20243 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20245 beforeInvalidDrop : function(target, e, id){
20250 handleMouseDown : function(e){
20251 if(this.dragging) {
20254 var data = this.getDragData(e);
20255 if(data && this.onBeforeDrag(data, e) !== false){
20256 this.dragData = data;
20258 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20263 * An empty function by default, but provided so that you can perform a custom action before the initial
20264 * drag event begins and optionally cancel it.
20265 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20266 * @param {Event} e The event object
20267 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20269 onBeforeDrag : function(data, e){
20274 * An empty function by default, but provided so that you can perform a custom action once the initial
20275 * drag event has begun. The drag cannot be canceled from this function.
20276 * @param {Number} x The x position of the click on the dragged object
20277 * @param {Number} y The y position of the click on the dragged object
20279 onStartDrag : Roo.emptyFn,
20281 // private - YUI override
20282 startDrag : function(x, y){
20283 this.proxy.reset();
20284 this.dragging = true;
20285 this.proxy.update("");
20286 this.onInitDrag(x, y);
20291 onInitDrag : function(x, y){
20292 var clone = this.el.dom.cloneNode(true);
20293 clone.id = Roo.id(); // prevent duplicate ids
20294 this.proxy.update(clone);
20295 this.onStartDrag(x, y);
20300 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20301 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20303 getProxy : function(){
20308 * Hides the drag source's {@link Roo.dd.StatusProxy}
20310 hideProxy : function(){
20312 this.proxy.reset(true);
20313 this.dragging = false;
20317 triggerCacheRefresh : function(){
20318 Roo.dd.DDM.refreshCache(this.groups);
20321 // private - override to prevent hiding
20322 b4EndDrag: function(e) {
20325 // private - override to prevent moving
20326 endDrag : function(e){
20327 this.onEndDrag(this.dragData, e);
20331 onEndDrag : function(data, e){
20334 // private - pin to cursor
20335 autoOffset : function(x, y) {
20336 this.setDelta(-12, -20);
20340 * Ext JS Library 1.1.1
20341 * Copyright(c) 2006-2007, Ext JS, LLC.
20343 * Originally Released Under LGPL - original licence link has changed is not relivant.
20346 * <script type="text/javascript">
20351 * @class Roo.dd.DropTarget
20352 * @extends Roo.dd.DDTarget
20353 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20354 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20356 * @param {String/HTMLElement/Element} el The container element
20357 * @param {Object} config
20359 Roo.dd.DropTarget = function(el, config){
20360 this.el = Roo.get(el);
20362 var listeners = false; ;
20363 if (config && config.listeners) {
20364 listeners= config.listeners;
20365 delete config.listeners;
20367 Roo.apply(this, config);
20369 if(this.containerScroll){
20370 Roo.dd.ScrollManager.register(this.el);
20374 * @scope Roo.dd.DropTarget
20379 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20380 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20381 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20383 * IMPORTANT : it should set this.overClass and this.dropAllowed
20385 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20386 * @param {Event} e The event
20387 * @param {Object} data An object containing arbitrary data supplied by the drag source
20393 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20394 * This method will be called on every mouse movement while the drag source is over the drop target.
20395 * This default implementation simply returns the dropAllowed config value.
20397 * IMPORTANT : it should set this.dropAllowed
20399 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20400 * @param {Event} e The event
20401 * @param {Object} data An object containing arbitrary data supplied by the drag source
20407 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20408 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20409 * overClass (if any) from the drop element.
20411 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20412 * @param {Event} e The event
20413 * @param {Object} data An object containing arbitrary data supplied by the drag source
20419 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20420 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20421 * implementation that does something to process the drop event and returns true so that the drag source's
20422 * repair action does not run.
20424 * IMPORTANT : it should set this.success
20426 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20427 * @param {Event} e The event
20428 * @param {Object} data An object containing arbitrary data supplied by the drag source
20434 Roo.dd.DropTarget.superclass.constructor.call( this,
20436 this.ddGroup || this.group,
20439 listeners : listeners || {}
20447 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20449 * @cfg {String} overClass
20450 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20453 * @cfg {String} ddGroup
20454 * The drag drop group to handle drop events for
20458 * @cfg {String} dropAllowed
20459 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20461 dropAllowed : "x-dd-drop-ok",
20463 * @cfg {String} dropNotAllowed
20464 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20466 dropNotAllowed : "x-dd-drop-nodrop",
20468 * @cfg {boolean} success
20469 * set this after drop listener..
20473 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20474 * if the drop point is valid for over/enter..
20481 isNotifyTarget : true,
20486 notifyEnter : function(dd, e, data)
20489 this.fireEvent('enter', dd, e, data);
20490 if(this.overClass){
20491 this.el.addClass(this.overClass);
20493 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20494 this.valid ? this.dropAllowed : this.dropNotAllowed
20501 notifyOver : function(dd, e, data)
20504 this.fireEvent('over', dd, e, data);
20505 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20506 this.valid ? this.dropAllowed : this.dropNotAllowed
20513 notifyOut : function(dd, e, data)
20515 this.fireEvent('out', dd, e, data);
20516 if(this.overClass){
20517 this.el.removeClass(this.overClass);
20524 notifyDrop : function(dd, e, data)
20526 this.success = false;
20527 this.fireEvent('drop', dd, e, data);
20528 return this.success;
20532 * Ext JS Library 1.1.1
20533 * Copyright(c) 2006-2007, Ext JS, LLC.
20535 * Originally Released Under LGPL - original licence link has changed is not relivant.
20538 * <script type="text/javascript">
20543 * @class Roo.dd.DragZone
20544 * @extends Roo.dd.DragSource
20545 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20546 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20548 * @param {String/HTMLElement/Element} el The container element
20549 * @param {Object} config
20551 Roo.dd.DragZone = function(el, config){
20552 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20553 if(this.containerScroll){
20554 Roo.dd.ScrollManager.register(this.el);
20558 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20560 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20561 * for auto scrolling during drag operations.
20564 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20565 * method after a failed drop (defaults to "c3daf9" - light blue)
20569 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20570 * for a valid target to drag based on the mouse down. Override this method
20571 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20572 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20573 * @param {EventObject} e The mouse down event
20574 * @return {Object} The dragData
20576 getDragData : function(e){
20577 return Roo.dd.Registry.getHandleFromEvent(e);
20581 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20582 * this.dragData.ddel
20583 * @param {Number} x The x position of the click on the dragged object
20584 * @param {Number} y The y position of the click on the dragged object
20585 * @return {Boolean} true to continue the drag, false to cancel
20587 onInitDrag : function(x, y){
20588 this.proxy.update(this.dragData.ddel.cloneNode(true));
20589 this.onStartDrag(x, y);
20594 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20596 afterRepair : function(){
20598 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20600 this.dragging = false;
20604 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20605 * the XY of this.dragData.ddel
20606 * @param {EventObject} e The mouse up event
20607 * @return {Array} The xy location (e.g. [100, 200])
20609 getRepairXY : function(e){
20610 return Roo.Element.fly(this.dragData.ddel).getXY();
20614 * Ext JS Library 1.1.1
20615 * Copyright(c) 2006-2007, Ext JS, LLC.
20617 * Originally Released Under LGPL - original licence link has changed is not relivant.
20620 * <script type="text/javascript">
20623 * @class Roo.dd.DropZone
20624 * @extends Roo.dd.DropTarget
20625 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20626 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20628 * @param {String/HTMLElement/Element} el The container element
20629 * @param {Object} config
20631 Roo.dd.DropZone = function(el, config){
20632 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20635 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20637 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20638 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20639 * provide your own custom lookup.
20640 * @param {Event} e The event
20641 * @return {Object} data The custom data
20643 getTargetFromEvent : function(e){
20644 return Roo.dd.Registry.getTargetFromEvent(e);
20648 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20649 * that it has registered. This method has no default implementation and should be overridden to provide
20650 * node-specific processing if necessary.
20651 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20652 * {@link #getTargetFromEvent} for this node)
20653 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20654 * @param {Event} e The event
20655 * @param {Object} data An object containing arbitrary data supplied by the drag source
20657 onNodeEnter : function(n, dd, e, data){
20662 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20663 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20664 * overridden to provide the proper feedback.
20665 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20666 * {@link #getTargetFromEvent} for this node)
20667 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20668 * @param {Event} e The event
20669 * @param {Object} data An object containing arbitrary data supplied by the drag source
20670 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20671 * underlying {@link Roo.dd.StatusProxy} can be updated
20673 onNodeOver : function(n, dd, e, data){
20674 return this.dropAllowed;
20678 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20679 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20680 * node-specific processing if necessary.
20681 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20682 * {@link #getTargetFromEvent} for this node)
20683 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20684 * @param {Event} e The event
20685 * @param {Object} data An object containing arbitrary data supplied by the drag source
20687 onNodeOut : function(n, dd, e, data){
20692 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20693 * the drop node. The default implementation returns false, so it should be overridden to provide the
20694 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20695 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20696 * {@link #getTargetFromEvent} for this node)
20697 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20698 * @param {Event} e The event
20699 * @param {Object} data An object containing arbitrary data supplied by the drag source
20700 * @return {Boolean} True if the drop was valid, else false
20702 onNodeDrop : function(n, dd, e, data){
20707 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20708 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20709 * it should be overridden to provide the proper feedback if necessary.
20710 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20711 * @param {Event} e The event
20712 * @param {Object} data An object containing arbitrary data supplied by the drag source
20713 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20714 * underlying {@link Roo.dd.StatusProxy} can be updated
20716 onContainerOver : function(dd, e, data){
20717 return this.dropNotAllowed;
20721 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20722 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20723 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20724 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20725 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20726 * @param {Event} e The event
20727 * @param {Object} data An object containing arbitrary data supplied by the drag source
20728 * @return {Boolean} True if the drop was valid, else false
20730 onContainerDrop : function(dd, e, data){
20735 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20736 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20737 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20738 * you should override this method and provide a custom implementation.
20739 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20740 * @param {Event} e The event
20741 * @param {Object} data An object containing arbitrary data supplied by the drag source
20742 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20743 * underlying {@link Roo.dd.StatusProxy} can be updated
20745 notifyEnter : function(dd, e, data){
20746 return this.dropNotAllowed;
20750 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20751 * This method will be called on every mouse movement while the drag source is over the drop zone.
20752 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20753 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20754 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20755 * registered node, it will call {@link #onContainerOver}.
20756 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20757 * @param {Event} e The event
20758 * @param {Object} data An object containing arbitrary data supplied by the drag source
20759 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20760 * underlying {@link Roo.dd.StatusProxy} can be updated
20762 notifyOver : function(dd, e, data){
20763 var n = this.getTargetFromEvent(e);
20764 if(!n){ // not over valid drop target
20765 if(this.lastOverNode){
20766 this.onNodeOut(this.lastOverNode, dd, e, data);
20767 this.lastOverNode = null;
20769 return this.onContainerOver(dd, e, data);
20771 if(this.lastOverNode != n){
20772 if(this.lastOverNode){
20773 this.onNodeOut(this.lastOverNode, dd, e, data);
20775 this.onNodeEnter(n, dd, e, data);
20776 this.lastOverNode = n;
20778 return this.onNodeOver(n, dd, e, data);
20782 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20783 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20784 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20785 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20786 * @param {Event} e The event
20787 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20789 notifyOut : function(dd, e, data){
20790 if(this.lastOverNode){
20791 this.onNodeOut(this.lastOverNode, dd, e, data);
20792 this.lastOverNode = null;
20797 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20798 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20799 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20800 * otherwise it will call {@link #onContainerDrop}.
20801 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20802 * @param {Event} e The event
20803 * @param {Object} data An object containing arbitrary data supplied by the drag source
20804 * @return {Boolean} True if the drop was valid, else false
20806 notifyDrop : function(dd, e, data){
20807 if(this.lastOverNode){
20808 this.onNodeOut(this.lastOverNode, dd, e, data);
20809 this.lastOverNode = null;
20811 var n = this.getTargetFromEvent(e);
20813 this.onNodeDrop(n, dd, e, data) :
20814 this.onContainerDrop(dd, e, data);
20818 triggerCacheRefresh : function(){
20819 Roo.dd.DDM.refreshCache(this.groups);
20823 * Ext JS Library 1.1.1
20824 * Copyright(c) 2006-2007, Ext JS, LLC.
20826 * Originally Released Under LGPL - original licence link has changed is not relivant.
20829 * <script type="text/javascript">
20834 * @class Roo.data.SortTypes
20836 * Defines the default sorting (casting?) comparison functions used when sorting data.
20838 Roo.data.SortTypes = {
20840 * Default sort that does nothing
20841 * @param {Mixed} s The value being converted
20842 * @return {Mixed} The comparison value
20844 none : function(s){
20849 * The regular expression used to strip tags
20853 stripTagsRE : /<\/?[^>]+>/gi,
20856 * Strips all HTML tags to sort on text only
20857 * @param {Mixed} s The value being converted
20858 * @return {String} The comparison value
20860 asText : function(s){
20861 return String(s).replace(this.stripTagsRE, "");
20865 * Strips all HTML tags to sort on text only - Case insensitive
20866 * @param {Mixed} s The value being converted
20867 * @return {String} The comparison value
20869 asUCText : function(s){
20870 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20874 * Case insensitive string
20875 * @param {Mixed} s The value being converted
20876 * @return {String} The comparison value
20878 asUCString : function(s) {
20879 return String(s).toUpperCase();
20884 * @param {Mixed} s The value being converted
20885 * @return {Number} The comparison value
20887 asDate : function(s) {
20891 if(s instanceof Date){
20892 return s.getTime();
20894 return Date.parse(String(s));
20899 * @param {Mixed} s The value being converted
20900 * @return {Float} The comparison value
20902 asFloat : function(s) {
20903 var val = parseFloat(String(s).replace(/,/g, ""));
20904 if(isNaN(val)) val = 0;
20910 * @param {Mixed} s The value being converted
20911 * @return {Number} The comparison value
20913 asInt : function(s) {
20914 var val = parseInt(String(s).replace(/,/g, ""));
20915 if(isNaN(val)) val = 0;
20920 * Ext JS Library 1.1.1
20921 * Copyright(c) 2006-2007, Ext JS, LLC.
20923 * Originally Released Under LGPL - original licence link has changed is not relivant.
20926 * <script type="text/javascript">
20930 * @class Roo.data.Record
20931 * Instances of this class encapsulate both record <em>definition</em> information, and record
20932 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20933 * to access Records cached in an {@link Roo.data.Store} object.<br>
20935 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20936 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20939 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20941 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20942 * {@link #create}. The parameters are the same.
20943 * @param {Array} data An associative Array of data values keyed by the field name.
20944 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20945 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20946 * not specified an integer id is generated.
20948 Roo.data.Record = function(data, id){
20949 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20954 * Generate a constructor for a specific record layout.
20955 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20956 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20957 * Each field definition object may contain the following properties: <ul>
20958 * <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,
20959 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20960 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20961 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20962 * is being used, then this is a string containing the javascript expression to reference the data relative to
20963 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20964 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20965 * this may be omitted.</p></li>
20966 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20967 * <ul><li>auto (Default, implies no conversion)</li>
20972 * <li>date</li></ul></p></li>
20973 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20974 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20975 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20976 * by the Reader into an object that will be stored in the Record. It is passed the
20977 * following parameters:<ul>
20978 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20980 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20982 * <br>usage:<br><pre><code>
20983 var TopicRecord = Roo.data.Record.create(
20984 {name: 'title', mapping: 'topic_title'},
20985 {name: 'author', mapping: 'username'},
20986 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20987 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20988 {name: 'lastPoster', mapping: 'user2'},
20989 {name: 'excerpt', mapping: 'post_text'}
20992 var myNewRecord = new TopicRecord({
20993 title: 'Do my job please',
20996 lastPost: new Date(),
20997 lastPoster: 'Animal',
20998 excerpt: 'No way dude!'
21000 myStore.add(myNewRecord);
21005 Roo.data.Record.create = function(o){
21006 var f = function(){
21007 f.superclass.constructor.apply(this, arguments);
21009 Roo.extend(f, Roo.data.Record);
21010 var p = f.prototype;
21011 p.fields = new Roo.util.MixedCollection(false, function(field){
21014 for(var i = 0, len = o.length; i < len; i++){
21015 p.fields.add(new Roo.data.Field(o[i]));
21017 f.getField = function(name){
21018 return p.fields.get(name);
21023 Roo.data.Record.AUTO_ID = 1000;
21024 Roo.data.Record.EDIT = 'edit';
21025 Roo.data.Record.REJECT = 'reject';
21026 Roo.data.Record.COMMIT = 'commit';
21028 Roo.data.Record.prototype = {
21030 * Readonly flag - true if this record has been modified.
21039 join : function(store){
21040 this.store = store;
21044 * Set the named field to the specified value.
21045 * @param {String} name The name of the field to set.
21046 * @param {Object} value The value to set the field to.
21048 set : function(name, value){
21049 if(this.data[name] == value){
21053 if(!this.modified){
21054 this.modified = {};
21056 if(typeof this.modified[name] == 'undefined'){
21057 this.modified[name] = this.data[name];
21059 this.data[name] = value;
21060 if(!this.editing && this.store){
21061 this.store.afterEdit(this);
21066 * Get the value of the named field.
21067 * @param {String} name The name of the field to get the value of.
21068 * @return {Object} The value of the field.
21070 get : function(name){
21071 return this.data[name];
21075 beginEdit : function(){
21076 this.editing = true;
21077 this.modified = {};
21081 cancelEdit : function(){
21082 this.editing = false;
21083 delete this.modified;
21087 endEdit : function(){
21088 this.editing = false;
21089 if(this.dirty && this.store){
21090 this.store.afterEdit(this);
21095 * Usually called by the {@link Roo.data.Store} which owns the Record.
21096 * Rejects all changes made to the Record since either creation, or the last commit operation.
21097 * Modified fields are reverted to their original values.
21099 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21100 * of reject operations.
21102 reject : function(){
21103 var m = this.modified;
21105 if(typeof m[n] != "function"){
21106 this.data[n] = m[n];
21109 this.dirty = false;
21110 delete this.modified;
21111 this.editing = false;
21113 this.store.afterReject(this);
21118 * Usually called by the {@link Roo.data.Store} which owns the Record.
21119 * Commits all changes made to the Record since either creation, or the last commit operation.
21121 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21122 * of commit operations.
21124 commit : function(){
21125 this.dirty = false;
21126 delete this.modified;
21127 this.editing = false;
21129 this.store.afterCommit(this);
21134 hasError : function(){
21135 return this.error != null;
21139 clearError : function(){
21144 * Creates a copy of this record.
21145 * @param {String} id (optional) A new record id if you don't want to use this record's id
21148 copy : function(newId) {
21149 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21153 * Ext JS Library 1.1.1
21154 * Copyright(c) 2006-2007, Ext JS, LLC.
21156 * Originally Released Under LGPL - original licence link has changed is not relivant.
21159 * <script type="text/javascript">
21165 * @class Roo.data.Store
21166 * @extends Roo.util.Observable
21167 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21168 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21170 * 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
21171 * has no knowledge of the format of the data returned by the Proxy.<br>
21173 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21174 * instances from the data object. These records are cached and made available through accessor functions.
21176 * Creates a new Store.
21177 * @param {Object} config A config object containing the objects needed for the Store to access data,
21178 * and read the data into Records.
21180 Roo.data.Store = function(config){
21181 this.data = new Roo.util.MixedCollection(false);
21182 this.data.getKey = function(o){
21185 this.baseParams = {};
21187 this.paramNames = {
21192 "multisort" : "_multisort"
21195 if(config && config.data){
21196 this.inlineData = config.data;
21197 delete config.data;
21200 Roo.apply(this, config);
21202 if(this.reader){ // reader passed
21203 this.reader = Roo.factory(this.reader, Roo.data);
21204 this.reader.xmodule = this.xmodule || false;
21205 if(!this.recordType){
21206 this.recordType = this.reader.recordType;
21208 if(this.reader.onMetaChange){
21209 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21213 if(this.recordType){
21214 this.fields = this.recordType.prototype.fields;
21216 this.modified = [];
21220 * @event datachanged
21221 * Fires when the data cache has changed, and a widget which is using this Store
21222 * as a Record cache should refresh its view.
21223 * @param {Store} this
21225 datachanged : true,
21227 * @event metachange
21228 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21229 * @param {Store} this
21230 * @param {Object} meta The JSON metadata
21235 * Fires when Records have been added to the Store
21236 * @param {Store} this
21237 * @param {Roo.data.Record[]} records The array of Records added
21238 * @param {Number} index The index at which the record(s) were added
21243 * Fires when a Record has been removed from the Store
21244 * @param {Store} this
21245 * @param {Roo.data.Record} record The Record that was removed
21246 * @param {Number} index The index at which the record was removed
21251 * Fires when a Record has been updated
21252 * @param {Store} this
21253 * @param {Roo.data.Record} record The Record that was updated
21254 * @param {String} operation The update operation being performed. Value may be one of:
21256 Roo.data.Record.EDIT
21257 Roo.data.Record.REJECT
21258 Roo.data.Record.COMMIT
21264 * Fires when the data cache has been cleared.
21265 * @param {Store} this
21269 * @event beforeload
21270 * Fires before a request is made for a new data object. If the beforeload handler returns false
21271 * the load action will be canceled.
21272 * @param {Store} this
21273 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21277 * @event beforeloadadd
21278 * Fires after a new set of Records has been loaded.
21279 * @param {Store} this
21280 * @param {Roo.data.Record[]} records The Records that were loaded
21281 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21283 beforeloadadd : true,
21286 * Fires after a new set of Records has been loaded, before they are added to the store.
21287 * @param {Store} this
21288 * @param {Roo.data.Record[]} records The Records that were loaded
21289 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21290 * @params {Object} return from reader
21294 * @event loadexception
21295 * Fires if an exception occurs in the Proxy during loading.
21296 * Called with the signature of the Proxy's "loadexception" event.
21297 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21300 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21301 * @param {Object} load options
21302 * @param {Object} jsonData from your request (normally this contains the Exception)
21304 loadexception : true
21308 this.proxy = Roo.factory(this.proxy, Roo.data);
21309 this.proxy.xmodule = this.xmodule || false;
21310 this.relayEvents(this.proxy, ["loadexception"]);
21312 this.sortToggle = {};
21313 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21315 Roo.data.Store.superclass.constructor.call(this);
21317 if(this.inlineData){
21318 this.loadData(this.inlineData);
21319 delete this.inlineData;
21323 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21325 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21326 * without a remote query - used by combo/forms at present.
21330 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21333 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21336 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21337 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21340 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21341 * on any HTTP request
21344 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21347 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21351 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21352 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21354 remoteSort : false,
21357 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21358 * loaded or when a record is removed. (defaults to false).
21360 pruneModifiedRecords : false,
21363 lastOptions : null,
21366 * Add Records to the Store and fires the add event.
21367 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21369 add : function(records){
21370 records = [].concat(records);
21371 for(var i = 0, len = records.length; i < len; i++){
21372 records[i].join(this);
21374 var index = this.data.length;
21375 this.data.addAll(records);
21376 this.fireEvent("add", this, records, index);
21380 * Remove a Record from the Store and fires the remove event.
21381 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21383 remove : function(record){
21384 var index = this.data.indexOf(record);
21385 this.data.removeAt(index);
21386 if(this.pruneModifiedRecords){
21387 this.modified.remove(record);
21389 this.fireEvent("remove", this, record, index);
21393 * Remove all Records from the Store and fires the clear event.
21395 removeAll : function(){
21397 if(this.pruneModifiedRecords){
21398 this.modified = [];
21400 this.fireEvent("clear", this);
21404 * Inserts Records to the Store at the given index and fires the add event.
21405 * @param {Number} index The start index at which to insert the passed Records.
21406 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21408 insert : function(index, records){
21409 records = [].concat(records);
21410 for(var i = 0, len = records.length; i < len; i++){
21411 this.data.insert(index, records[i]);
21412 records[i].join(this);
21414 this.fireEvent("add", this, records, index);
21418 * Get the index within the cache of the passed Record.
21419 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21420 * @return {Number} The index of the passed Record. Returns -1 if not found.
21422 indexOf : function(record){
21423 return this.data.indexOf(record);
21427 * Get the index within the cache of the Record with the passed id.
21428 * @param {String} id The id of the Record to find.
21429 * @return {Number} The index of the Record. Returns -1 if not found.
21431 indexOfId : function(id){
21432 return this.data.indexOfKey(id);
21436 * Get the Record with the specified id.
21437 * @param {String} id The id of the Record to find.
21438 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21440 getById : function(id){
21441 return this.data.key(id);
21445 * Get the Record at the specified index.
21446 * @param {Number} index The index of the Record to find.
21447 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21449 getAt : function(index){
21450 return this.data.itemAt(index);
21454 * Returns a range of Records between specified indices.
21455 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21456 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21457 * @return {Roo.data.Record[]} An array of Records
21459 getRange : function(start, end){
21460 return this.data.getRange(start, end);
21464 storeOptions : function(o){
21465 o = Roo.apply({}, o);
21468 this.lastOptions = o;
21472 * Loads the Record cache from the configured Proxy using the configured Reader.
21474 * If using remote paging, then the first load call must specify the <em>start</em>
21475 * and <em>limit</em> properties in the options.params property to establish the initial
21476 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21478 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21479 * and this call will return before the new data has been loaded. Perform any post-processing
21480 * in a callback function, or in a "load" event handler.</strong>
21482 * @param {Object} options An object containing properties which control loading options:<ul>
21483 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21484 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21485 * passed the following arguments:<ul>
21486 * <li>r : Roo.data.Record[]</li>
21487 * <li>options: Options object from the load call</li>
21488 * <li>success: Boolean success indicator</li></ul></li>
21489 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21490 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21493 load : function(options){
21494 options = options || {};
21495 if(this.fireEvent("beforeload", this, options) !== false){
21496 this.storeOptions(options);
21497 var p = Roo.apply(options.params || {}, this.baseParams);
21498 // if meta was not loaded from remote source.. try requesting it.
21499 if (!this.reader.metaFromRemote) {
21500 p._requestMeta = 1;
21502 if(this.sortInfo && this.remoteSort){
21503 var pn = this.paramNames;
21504 p[pn["sort"]] = this.sortInfo.field;
21505 p[pn["dir"]] = this.sortInfo.direction;
21507 if (this.multiSort) {
21508 var pn = this.paramNames;
21509 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21512 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21517 * Reloads the Record cache from the configured Proxy using the configured Reader and
21518 * the options from the last load operation performed.
21519 * @param {Object} options (optional) An object containing properties which may override the options
21520 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21521 * the most recently used options are reused).
21523 reload : function(options){
21524 this.load(Roo.applyIf(options||{}, this.lastOptions));
21528 // Called as a callback by the Reader during a load operation.
21529 loadRecords : function(o, options, success){
21530 if(!o || success === false){
21531 if(success !== false){
21532 this.fireEvent("load", this, [], options, o);
21534 if(options.callback){
21535 options.callback.call(options.scope || this, [], options, false);
21539 // if data returned failure - throw an exception.
21540 if (o.success === false) {
21541 // show a message if no listener is registered.
21542 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21543 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21545 // loadmask wil be hooked into this..
21546 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21549 var r = o.records, t = o.totalRecords || r.length;
21551 this.fireEvent("beforeloadadd", this, r, options, o);
21553 if(!options || options.add !== true){
21554 if(this.pruneModifiedRecords){
21555 this.modified = [];
21557 for(var i = 0, len = r.length; i < len; i++){
21561 this.data = this.snapshot;
21562 delete this.snapshot;
21565 this.data.addAll(r);
21566 this.totalLength = t;
21568 this.fireEvent("datachanged", this);
21570 this.totalLength = Math.max(t, this.data.length+r.length);
21573 this.fireEvent("load", this, r, options, o);
21574 if(options.callback){
21575 options.callback.call(options.scope || this, r, options, true);
21581 * Loads data from a passed data block. A Reader which understands the format of the data
21582 * must have been configured in the constructor.
21583 * @param {Object} data The data block from which to read the Records. The format of the data expected
21584 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21585 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21587 loadData : function(o, append){
21588 var r = this.reader.readRecords(o);
21589 this.loadRecords(r, {add: append}, true);
21593 * Gets the number of cached records.
21595 * <em>If using paging, this may not be the total size of the dataset. If the data object
21596 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21597 * the data set size</em>
21599 getCount : function(){
21600 return this.data.length || 0;
21604 * Gets the total number of records in the dataset as returned by the server.
21606 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21607 * the dataset size</em>
21609 getTotalCount : function(){
21610 return this.totalLength || 0;
21614 * Returns the sort state of the Store as an object with two properties:
21616 field {String} The name of the field by which the Records are sorted
21617 direction {String} The sort order, "ASC" or "DESC"
21620 getSortState : function(){
21621 return this.sortInfo;
21625 applySort : function(){
21626 if(this.sortInfo && !this.remoteSort){
21627 var s = this.sortInfo, f = s.field;
21628 var st = this.fields.get(f).sortType;
21629 var fn = function(r1, r2){
21630 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21631 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21633 this.data.sort(s.direction, fn);
21634 if(this.snapshot && this.snapshot != this.data){
21635 this.snapshot.sort(s.direction, fn);
21641 * Sets the default sort column and order to be used by the next load operation.
21642 * @param {String} fieldName The name of the field to sort by.
21643 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21645 setDefaultSort : function(field, dir){
21646 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21650 * Sort the Records.
21651 * If remote sorting is used, the sort is performed on the server, and the cache is
21652 * reloaded. If local sorting is used, the cache is sorted internally.
21653 * @param {String} fieldName The name of the field to sort by.
21654 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21656 sort : function(fieldName, dir){
21657 var f = this.fields.get(fieldName);
21659 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21661 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21662 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21667 this.sortToggle[f.name] = dir;
21668 this.sortInfo = {field: f.name, direction: dir};
21669 if(!this.remoteSort){
21671 this.fireEvent("datachanged", this);
21673 this.load(this.lastOptions);
21678 * Calls the specified function for each of the Records in the cache.
21679 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21680 * Returning <em>false</em> aborts and exits the iteration.
21681 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21683 each : function(fn, scope){
21684 this.data.each(fn, scope);
21688 * Gets all records modified since the last commit. Modified records are persisted across load operations
21689 * (e.g., during paging).
21690 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21692 getModifiedRecords : function(){
21693 return this.modified;
21697 createFilterFn : function(property, value, anyMatch){
21698 if(!value.exec){ // not a regex
21699 value = String(value);
21700 if(value.length == 0){
21703 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21705 return function(r){
21706 return value.test(r.data[property]);
21711 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21712 * @param {String} property A field on your records
21713 * @param {Number} start The record index to start at (defaults to 0)
21714 * @param {Number} end The last record index to include (defaults to length - 1)
21715 * @return {Number} The sum
21717 sum : function(property, start, end){
21718 var rs = this.data.items, v = 0;
21719 start = start || 0;
21720 end = (end || end === 0) ? end : rs.length-1;
21722 for(var i = start; i <= end; i++){
21723 v += (rs[i].data[property] || 0);
21729 * Filter the records by a specified property.
21730 * @param {String} field A field on your records
21731 * @param {String/RegExp} value Either a string that the field
21732 * should start with or a RegExp to test against the field
21733 * @param {Boolean} anyMatch True to match any part not just the beginning
21735 filter : function(property, value, anyMatch){
21736 var fn = this.createFilterFn(property, value, anyMatch);
21737 return fn ? this.filterBy(fn) : this.clearFilter();
21741 * Filter by a function. The specified function will be called with each
21742 * record in this data source. If the function returns true the record is included,
21743 * otherwise it is filtered.
21744 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21745 * @param {Object} scope (optional) The scope of the function (defaults to this)
21747 filterBy : function(fn, scope){
21748 this.snapshot = this.snapshot || this.data;
21749 this.data = this.queryBy(fn, scope||this);
21750 this.fireEvent("datachanged", this);
21754 * Query the records by a specified property.
21755 * @param {String} field A field on your records
21756 * @param {String/RegExp} value Either a string that the field
21757 * should start with or a RegExp to test against the field
21758 * @param {Boolean} anyMatch True to match any part not just the beginning
21759 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21761 query : function(property, value, anyMatch){
21762 var fn = this.createFilterFn(property, value, anyMatch);
21763 return fn ? this.queryBy(fn) : this.data.clone();
21767 * Query by a function. The specified function will be called with each
21768 * record in this data source. If the function returns true the record is included
21770 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21771 * @param {Object} scope (optional) The scope of the function (defaults to this)
21772 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21774 queryBy : function(fn, scope){
21775 var data = this.snapshot || this.data;
21776 return data.filterBy(fn, scope||this);
21780 * Collects unique values for a particular dataIndex from this store.
21781 * @param {String} dataIndex The property to collect
21782 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21783 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21784 * @return {Array} An array of the unique values
21786 collect : function(dataIndex, allowNull, bypassFilter){
21787 var d = (bypassFilter === true && this.snapshot) ?
21788 this.snapshot.items : this.data.items;
21789 var v, sv, r = [], l = {};
21790 for(var i = 0, len = d.length; i < len; i++){
21791 v = d[i].data[dataIndex];
21793 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21802 * Revert to a view of the Record cache with no filtering applied.
21803 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21805 clearFilter : function(suppressEvent){
21806 if(this.snapshot && this.snapshot != this.data){
21807 this.data = this.snapshot;
21808 delete this.snapshot;
21809 if(suppressEvent !== true){
21810 this.fireEvent("datachanged", this);
21816 afterEdit : function(record){
21817 if(this.modified.indexOf(record) == -1){
21818 this.modified.push(record);
21820 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21824 afterReject : function(record){
21825 this.modified.remove(record);
21826 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21830 afterCommit : function(record){
21831 this.modified.remove(record);
21832 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21836 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21837 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21839 commitChanges : function(){
21840 var m = this.modified.slice(0);
21841 this.modified = [];
21842 for(var i = 0, len = m.length; i < len; i++){
21848 * Cancel outstanding changes on all changed records.
21850 rejectChanges : function(){
21851 var m = this.modified.slice(0);
21852 this.modified = [];
21853 for(var i = 0, len = m.length; i < len; i++){
21858 onMetaChange : function(meta, rtype, o){
21859 this.recordType = rtype;
21860 this.fields = rtype.prototype.fields;
21861 delete this.snapshot;
21862 this.sortInfo = meta.sortInfo || this.sortInfo;
21863 this.modified = [];
21864 this.fireEvent('metachange', this, this.reader.meta);
21867 moveIndex : function(data, type)
21869 var index = this.indexOf(data);
21871 var newIndex = index + type;
21875 this.insert(newIndex, data);
21880 * Ext JS Library 1.1.1
21881 * Copyright(c) 2006-2007, Ext JS, LLC.
21883 * Originally Released Under LGPL - original licence link has changed is not relivant.
21886 * <script type="text/javascript">
21890 * @class Roo.data.SimpleStore
21891 * @extends Roo.data.Store
21892 * Small helper class to make creating Stores from Array data easier.
21893 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21894 * @cfg {Array} fields An array of field definition objects, or field name strings.
21895 * @cfg {Array} data The multi-dimensional array of data
21897 * @param {Object} config
21899 Roo.data.SimpleStore = function(config){
21900 Roo.data.SimpleStore.superclass.constructor.call(this, {
21902 reader: new Roo.data.ArrayReader({
21905 Roo.data.Record.create(config.fields)
21907 proxy : new Roo.data.MemoryProxy(config.data)
21911 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21913 * Ext JS Library 1.1.1
21914 * Copyright(c) 2006-2007, Ext JS, LLC.
21916 * Originally Released Under LGPL - original licence link has changed is not relivant.
21919 * <script type="text/javascript">
21924 * @extends Roo.data.Store
21925 * @class Roo.data.JsonStore
21926 * Small helper class to make creating Stores for JSON data easier. <br/>
21928 var store = new Roo.data.JsonStore({
21929 url: 'get-images.php',
21931 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21934 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21935 * JsonReader and HttpProxy (unless inline data is provided).</b>
21936 * @cfg {Array} fields An array of field definition objects, or field name strings.
21938 * @param {Object} config
21940 Roo.data.JsonStore = function(c){
21941 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21942 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21943 reader: new Roo.data.JsonReader(c, c.fields)
21946 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21948 * Ext JS Library 1.1.1
21949 * Copyright(c) 2006-2007, Ext JS, LLC.
21951 * Originally Released Under LGPL - original licence link has changed is not relivant.
21954 * <script type="text/javascript">
21958 Roo.data.Field = function(config){
21959 if(typeof config == "string"){
21960 config = {name: config};
21962 Roo.apply(this, config);
21965 this.type = "auto";
21968 var st = Roo.data.SortTypes;
21969 // named sortTypes are supported, here we look them up
21970 if(typeof this.sortType == "string"){
21971 this.sortType = st[this.sortType];
21974 // set default sortType for strings and dates
21975 if(!this.sortType){
21978 this.sortType = st.asUCString;
21981 this.sortType = st.asDate;
21984 this.sortType = st.none;
21989 var stripRe = /[\$,%]/g;
21991 // prebuilt conversion function for this field, instead of
21992 // switching every time we're reading a value
21994 var cv, dateFormat = this.dateFormat;
21999 cv = function(v){ return v; };
22002 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22006 return v !== undefined && v !== null && v !== '' ?
22007 parseInt(String(v).replace(stripRe, ""), 10) : '';
22012 return v !== undefined && v !== null && v !== '' ?
22013 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22018 cv = function(v){ return v === true || v === "true" || v == 1; };
22025 if(v instanceof Date){
22029 if(dateFormat == "timestamp"){
22030 return new Date(v*1000);
22032 return Date.parseDate(v, dateFormat);
22034 var parsed = Date.parse(v);
22035 return parsed ? new Date(parsed) : null;
22044 Roo.data.Field.prototype = {
22052 * Ext JS Library 1.1.1
22053 * Copyright(c) 2006-2007, Ext JS, LLC.
22055 * Originally Released Under LGPL - original licence link has changed is not relivant.
22058 * <script type="text/javascript">
22061 // Base class for reading structured data from a data source. This class is intended to be
22062 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22065 * @class Roo.data.DataReader
22066 * Base class for reading structured data from a data source. This class is intended to be
22067 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22070 Roo.data.DataReader = function(meta, recordType){
22074 this.recordType = recordType instanceof Array ?
22075 Roo.data.Record.create(recordType) : recordType;
22078 Roo.data.DataReader.prototype = {
22080 * Create an empty record
22081 * @param {Object} data (optional) - overlay some values
22082 * @return {Roo.data.Record} record created.
22084 newRow : function(d) {
22086 this.recordType.prototype.fields.each(function(c) {
22088 case 'int' : da[c.name] = 0; break;
22089 case 'date' : da[c.name] = new Date(); break;
22090 case 'float' : da[c.name] = 0.0; break;
22091 case 'boolean' : da[c.name] = false; break;
22092 default : da[c.name] = ""; break;
22096 return new this.recordType(Roo.apply(da, d));
22101 * Ext JS Library 1.1.1
22102 * Copyright(c) 2006-2007, Ext JS, LLC.
22104 * Originally Released Under LGPL - original licence link has changed is not relivant.
22107 * <script type="text/javascript">
22111 * @class Roo.data.DataProxy
22112 * @extends Roo.data.Observable
22113 * This class is an abstract base class for implementations which provide retrieval of
22114 * unformatted data objects.<br>
22116 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22117 * (of the appropriate type which knows how to parse the data object) to provide a block of
22118 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22120 * Custom implementations must implement the load method as described in
22121 * {@link Roo.data.HttpProxy#load}.
22123 Roo.data.DataProxy = function(){
22126 * @event beforeload
22127 * Fires before a network request is made to retrieve a data object.
22128 * @param {Object} This DataProxy object.
22129 * @param {Object} params The params parameter to the load function.
22134 * Fires before the load method's callback is called.
22135 * @param {Object} This DataProxy object.
22136 * @param {Object} o The data object.
22137 * @param {Object} arg The callback argument object passed to the load function.
22141 * @event loadexception
22142 * Fires if an Exception occurs during data retrieval.
22143 * @param {Object} This DataProxy object.
22144 * @param {Object} o The data object.
22145 * @param {Object} arg The callback argument object passed to the load function.
22146 * @param {Object} e The Exception.
22148 loadexception : true
22150 Roo.data.DataProxy.superclass.constructor.call(this);
22153 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22156 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22160 * Ext JS Library 1.1.1
22161 * Copyright(c) 2006-2007, Ext JS, LLC.
22163 * Originally Released Under LGPL - original licence link has changed is not relivant.
22166 * <script type="text/javascript">
22169 * @class Roo.data.MemoryProxy
22170 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22171 * to the Reader when its load method is called.
22173 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22175 Roo.data.MemoryProxy = function(data){
22179 Roo.data.MemoryProxy.superclass.constructor.call(this);
22183 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22185 * Load data from the requested source (in this case an in-memory
22186 * data object passed to the constructor), read the data object into
22187 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22188 * process that block using the passed callback.
22189 * @param {Object} params This parameter is not used by the MemoryProxy class.
22190 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22191 * object into a block of Roo.data.Records.
22192 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22193 * The function must be passed <ul>
22194 * <li>The Record block object</li>
22195 * <li>The "arg" argument from the load function</li>
22196 * <li>A boolean success indicator</li>
22198 * @param {Object} scope The scope in which to call the callback
22199 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22201 load : function(params, reader, callback, scope, arg){
22202 params = params || {};
22205 result = reader.readRecords(this.data);
22207 this.fireEvent("loadexception", this, arg, null, e);
22208 callback.call(scope, null, arg, false);
22211 callback.call(scope, result, arg, true);
22215 update : function(params, records){
22220 * Ext JS Library 1.1.1
22221 * Copyright(c) 2006-2007, Ext JS, LLC.
22223 * Originally Released Under LGPL - original licence link has changed is not relivant.
22226 * <script type="text/javascript">
22229 * @class Roo.data.HttpProxy
22230 * @extends Roo.data.DataProxy
22231 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22232 * configured to reference a certain URL.<br><br>
22234 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22235 * from which the running page was served.<br><br>
22237 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22239 * Be aware that to enable the browser to parse an XML document, the server must set
22240 * the Content-Type header in the HTTP response to "text/xml".
22242 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22243 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22244 * will be used to make the request.
22246 Roo.data.HttpProxy = function(conn){
22247 Roo.data.HttpProxy.superclass.constructor.call(this);
22248 // is conn a conn config or a real conn?
22250 this.useAjax = !conn || !conn.events;
22254 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22255 // thse are take from connection...
22258 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22261 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22262 * extra parameters to each request made by this object. (defaults to undefined)
22265 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22266 * to each request made by this object. (defaults to undefined)
22269 * @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)
22272 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22275 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22281 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22285 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22286 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22287 * a finer-grained basis than the DataProxy events.
22289 getConnection : function(){
22290 return this.useAjax ? Roo.Ajax : this.conn;
22294 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22295 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22296 * process that block using the passed callback.
22297 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22298 * for the request to the remote server.
22299 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22300 * object into a block of Roo.data.Records.
22301 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22302 * The function must be passed <ul>
22303 * <li>The Record block object</li>
22304 * <li>The "arg" argument from the load function</li>
22305 * <li>A boolean success indicator</li>
22307 * @param {Object} scope The scope in which to call the callback
22308 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22310 load : function(params, reader, callback, scope, arg){
22311 if(this.fireEvent("beforeload", this, params) !== false){
22313 params : params || {},
22315 callback : callback,
22320 callback : this.loadResponse,
22324 Roo.applyIf(o, this.conn);
22325 if(this.activeRequest){
22326 Roo.Ajax.abort(this.activeRequest);
22328 this.activeRequest = Roo.Ajax.request(o);
22330 this.conn.request(o);
22333 callback.call(scope||this, null, arg, false);
22338 loadResponse : function(o, success, response){
22339 delete this.activeRequest;
22341 this.fireEvent("loadexception", this, o, response);
22342 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22347 result = o.reader.read(response);
22349 this.fireEvent("loadexception", this, o, response, e);
22350 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22354 this.fireEvent("load", this, o, o.request.arg);
22355 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22359 update : function(dataSet){
22364 updateResponse : function(dataSet){
22369 * Ext JS Library 1.1.1
22370 * Copyright(c) 2006-2007, Ext JS, LLC.
22372 * Originally Released Under LGPL - original licence link has changed is not relivant.
22375 * <script type="text/javascript">
22379 * @class Roo.data.ScriptTagProxy
22380 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22381 * other than the originating domain of the running page.<br><br>
22383 * <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
22384 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22386 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22387 * source code that is used as the source inside a <script> tag.<br><br>
22389 * In order for the browser to process the returned data, the server must wrap the data object
22390 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22391 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22392 * depending on whether the callback name was passed:
22395 boolean scriptTag = false;
22396 String cb = request.getParameter("callback");
22399 response.setContentType("text/javascript");
22401 response.setContentType("application/x-json");
22403 Writer out = response.getWriter();
22405 out.write(cb + "(");
22407 out.print(dataBlock.toJsonString());
22414 * @param {Object} config A configuration object.
22416 Roo.data.ScriptTagProxy = function(config){
22417 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22418 Roo.apply(this, config);
22419 this.head = document.getElementsByTagName("head")[0];
22422 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22424 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22426 * @cfg {String} url The URL from which to request the data object.
22429 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22433 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22434 * the server the name of the callback function set up by the load call to process the returned data object.
22435 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22436 * javascript output which calls this named function passing the data object as its only parameter.
22438 callbackParam : "callback",
22440 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22441 * name to the request.
22446 * Load data from the configured URL, read the data object into
22447 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22448 * process that block using the passed callback.
22449 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22450 * for the request to the remote server.
22451 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22452 * object into a block of Roo.data.Records.
22453 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22454 * The function must be passed <ul>
22455 * <li>The Record block object</li>
22456 * <li>The "arg" argument from the load function</li>
22457 * <li>A boolean success indicator</li>
22459 * @param {Object} scope The scope in which to call the callback
22460 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22462 load : function(params, reader, callback, scope, arg){
22463 if(this.fireEvent("beforeload", this, params) !== false){
22465 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22467 var url = this.url;
22468 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22470 url += "&_dc=" + (new Date().getTime());
22472 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22475 cb : "stcCallback"+transId,
22476 scriptId : "stcScript"+transId,
22480 callback : callback,
22486 window[trans.cb] = function(o){
22487 conn.handleResponse(o, trans);
22490 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22492 if(this.autoAbort !== false){
22496 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22498 var script = document.createElement("script");
22499 script.setAttribute("src", url);
22500 script.setAttribute("type", "text/javascript");
22501 script.setAttribute("id", trans.scriptId);
22502 this.head.appendChild(script);
22504 this.trans = trans;
22506 callback.call(scope||this, null, arg, false);
22511 isLoading : function(){
22512 return this.trans ? true : false;
22516 * Abort the current server request.
22518 abort : function(){
22519 if(this.isLoading()){
22520 this.destroyTrans(this.trans);
22525 destroyTrans : function(trans, isLoaded){
22526 this.head.removeChild(document.getElementById(trans.scriptId));
22527 clearTimeout(trans.timeoutId);
22529 window[trans.cb] = undefined;
22531 delete window[trans.cb];
22534 // if hasn't been loaded, wait for load to remove it to prevent script error
22535 window[trans.cb] = function(){
22536 window[trans.cb] = undefined;
22538 delete window[trans.cb];
22545 handleResponse : function(o, trans){
22546 this.trans = false;
22547 this.destroyTrans(trans, true);
22550 result = trans.reader.readRecords(o);
22552 this.fireEvent("loadexception", this, o, trans.arg, e);
22553 trans.callback.call(trans.scope||window, null, trans.arg, false);
22556 this.fireEvent("load", this, o, trans.arg);
22557 trans.callback.call(trans.scope||window, result, trans.arg, true);
22561 handleFailure : function(trans){
22562 this.trans = false;
22563 this.destroyTrans(trans, false);
22564 this.fireEvent("loadexception", this, null, trans.arg);
22565 trans.callback.call(trans.scope||window, null, trans.arg, false);
22569 * Ext JS Library 1.1.1
22570 * Copyright(c) 2006-2007, Ext JS, LLC.
22572 * Originally Released Under LGPL - original licence link has changed is not relivant.
22575 * <script type="text/javascript">
22579 * @class Roo.data.JsonReader
22580 * @extends Roo.data.DataReader
22581 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22582 * based on mappings in a provided Roo.data.Record constructor.
22584 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22585 * in the reply previously.
22590 var RecordDef = Roo.data.Record.create([
22591 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22592 {name: 'occupation'} // This field will use "occupation" as the mapping.
22594 var myReader = new Roo.data.JsonReader({
22595 totalProperty: "results", // The property which contains the total dataset size (optional)
22596 root: "rows", // The property which contains an Array of row objects
22597 id: "id" // The property within each row object that provides an ID for the record (optional)
22601 * This would consume a JSON file like this:
22603 { 'results': 2, 'rows': [
22604 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22605 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22608 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22609 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22610 * paged from the remote server.
22611 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22612 * @cfg {String} root name of the property which contains the Array of row objects.
22613 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22615 * Create a new JsonReader
22616 * @param {Object} meta Metadata configuration options
22617 * @param {Object} recordType Either an Array of field definition objects,
22618 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22620 Roo.data.JsonReader = function(meta, recordType){
22623 // set some defaults:
22624 Roo.applyIf(meta, {
22625 totalProperty: 'total',
22626 successProperty : 'success',
22631 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22633 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22636 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22637 * Used by Store query builder to append _requestMeta to params.
22640 metaFromRemote : false,
22642 * This method is only used by a DataProxy which has retrieved data from a remote server.
22643 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22644 * @return {Object} data A data block which is used by an Roo.data.Store object as
22645 * a cache of Roo.data.Records.
22647 read : function(response){
22648 var json = response.responseText;
22650 var o = /* eval:var:o */ eval("("+json+")");
22652 throw {message: "JsonReader.read: Json object not found"};
22658 this.metaFromRemote = true;
22659 this.meta = o.metaData;
22660 this.recordType = Roo.data.Record.create(o.metaData.fields);
22661 this.onMetaChange(this.meta, this.recordType, o);
22663 return this.readRecords(o);
22666 // private function a store will implement
22667 onMetaChange : function(meta, recordType, o){
22674 simpleAccess: function(obj, subsc) {
22681 getJsonAccessor: function(){
22683 return function(expr) {
22685 return(re.test(expr))
22686 ? new Function("obj", "return obj." + expr)
22691 return Roo.emptyFn;
22696 * Create a data block containing Roo.data.Records from an XML document.
22697 * @param {Object} o An object which contains an Array of row objects in the property specified
22698 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22699 * which contains the total size of the dataset.
22700 * @return {Object} data A data block which is used by an Roo.data.Store object as
22701 * a cache of Roo.data.Records.
22703 readRecords : function(o){
22705 * After any data loads, the raw JSON data is available for further custom processing.
22709 var s = this.meta, Record = this.recordType,
22710 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22712 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22714 if(s.totalProperty) {
22715 this.getTotal = this.getJsonAccessor(s.totalProperty);
22717 if(s.successProperty) {
22718 this.getSuccess = this.getJsonAccessor(s.successProperty);
22720 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22722 var g = this.getJsonAccessor(s.id);
22723 this.getId = function(rec) {
22725 return (r === undefined || r === "") ? null : r;
22728 this.getId = function(){return null;};
22731 for(var jj = 0; jj < fl; jj++){
22733 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22734 this.ef[jj] = this.getJsonAccessor(map);
22738 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22739 if(s.totalProperty){
22740 var vt = parseInt(this.getTotal(o), 10);
22745 if(s.successProperty){
22746 var vs = this.getSuccess(o);
22747 if(vs === false || vs === 'false'){
22752 for(var i = 0; i < c; i++){
22755 var id = this.getId(n);
22756 for(var j = 0; j < fl; j++){
22758 var v = this.ef[j](n);
22760 Roo.log('missing convert for ' + f.name);
22764 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22766 var record = new Record(values, id);
22768 records[i] = record;
22774 totalRecords : totalRecords
22779 * Ext JS Library 1.1.1
22780 * Copyright(c) 2006-2007, Ext JS, LLC.
22782 * Originally Released Under LGPL - original licence link has changed is not relivant.
22785 * <script type="text/javascript">
22789 * @class Roo.data.XmlReader
22790 * @extends Roo.data.DataReader
22791 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22792 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22794 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22795 * header in the HTTP response must be set to "text/xml".</em>
22799 var RecordDef = Roo.data.Record.create([
22800 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22801 {name: 'occupation'} // This field will use "occupation" as the mapping.
22803 var myReader = new Roo.data.XmlReader({
22804 totalRecords: "results", // The element which contains the total dataset size (optional)
22805 record: "row", // The repeated element which contains row information
22806 id: "id" // The element within the row that provides an ID for the record (optional)
22810 * This would consume an XML file like this:
22814 <results>2</results>
22817 <name>Bill</name>
22818 <occupation>Gardener</occupation>
22822 <name>Ben</name>
22823 <occupation>Horticulturalist</occupation>
22827 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22828 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22829 * paged from the remote server.
22830 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22831 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22832 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22833 * a record identifier value.
22835 * Create a new XmlReader
22836 * @param {Object} meta Metadata configuration options
22837 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22838 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22839 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22841 Roo.data.XmlReader = function(meta, recordType){
22843 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22845 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22847 * This method is only used by a DataProxy which has retrieved data from a remote server.
22848 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22849 * to contain a method called 'responseXML' that returns an XML document object.
22850 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22851 * a cache of Roo.data.Records.
22853 read : function(response){
22854 var doc = response.responseXML;
22856 throw {message: "XmlReader.read: XML Document not available"};
22858 return this.readRecords(doc);
22862 * Create a data block containing Roo.data.Records from an XML document.
22863 * @param {Object} doc A parsed XML document.
22864 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22865 * a cache of Roo.data.Records.
22867 readRecords : function(doc){
22869 * After any data loads/reads, the raw XML Document is available for further custom processing.
22870 * @type XMLDocument
22872 this.xmlData = doc;
22873 var root = doc.documentElement || doc;
22874 var q = Roo.DomQuery;
22875 var recordType = this.recordType, fields = recordType.prototype.fields;
22876 var sid = this.meta.id;
22877 var totalRecords = 0, success = true;
22878 if(this.meta.totalRecords){
22879 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22882 if(this.meta.success){
22883 var sv = q.selectValue(this.meta.success, root, true);
22884 success = sv !== false && sv !== 'false';
22887 var ns = q.select(this.meta.record, root);
22888 for(var i = 0, len = ns.length; i < len; i++) {
22891 var id = sid ? q.selectValue(sid, n) : undefined;
22892 for(var j = 0, jlen = fields.length; j < jlen; j++){
22893 var f = fields.items[j];
22894 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22896 values[f.name] = v;
22898 var record = new recordType(values, id);
22900 records[records.length] = record;
22906 totalRecords : totalRecords || records.length
22911 * Ext JS Library 1.1.1
22912 * Copyright(c) 2006-2007, Ext JS, LLC.
22914 * Originally Released Under LGPL - original licence link has changed is not relivant.
22917 * <script type="text/javascript">
22921 * @class Roo.data.ArrayReader
22922 * @extends Roo.data.DataReader
22923 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22924 * Each element of that Array represents a row of data fields. The
22925 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22926 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22930 var RecordDef = Roo.data.Record.create([
22931 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22932 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22934 var myReader = new Roo.data.ArrayReader({
22935 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22939 * This would consume an Array like this:
22941 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22943 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22945 * Create a new JsonReader
22946 * @param {Object} meta Metadata configuration options.
22947 * @param {Object} recordType Either an Array of field definition objects
22948 * as specified to {@link Roo.data.Record#create},
22949 * or an {@link Roo.data.Record} object
22950 * created using {@link Roo.data.Record#create}.
22952 Roo.data.ArrayReader = function(meta, recordType){
22953 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22956 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22958 * Create a data block containing Roo.data.Records from an XML document.
22959 * @param {Object} o An Array of row objects which represents the dataset.
22960 * @return {Object} data A data block which is used by an Roo.data.Store object as
22961 * a cache of Roo.data.Records.
22963 readRecords : function(o){
22964 var sid = this.meta ? this.meta.id : null;
22965 var recordType = this.recordType, fields = recordType.prototype.fields;
22968 for(var i = 0; i < root.length; i++){
22971 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22972 for(var j = 0, jlen = fields.length; j < jlen; j++){
22973 var f = fields.items[j];
22974 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22975 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22977 values[f.name] = v;
22979 var record = new recordType(values, id);
22981 records[records.length] = record;
22985 totalRecords : records.length
22990 * Ext JS Library 1.1.1
22991 * Copyright(c) 2006-2007, Ext JS, LLC.
22993 * Originally Released Under LGPL - original licence link has changed is not relivant.
22996 * <script type="text/javascript">
23001 * @class Roo.data.Tree
23002 * @extends Roo.util.Observable
23003 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23004 * in the tree have most standard DOM functionality.
23006 * @param {Node} root (optional) The root node
23008 Roo.data.Tree = function(root){
23009 this.nodeHash = {};
23011 * The root node for this tree
23016 this.setRootNode(root);
23021 * Fires when a new child node is appended to a node in this tree.
23022 * @param {Tree} tree The owner tree
23023 * @param {Node} parent The parent node
23024 * @param {Node} node The newly appended node
23025 * @param {Number} index The index of the newly appended node
23030 * Fires when a child node is removed from a node in this tree.
23031 * @param {Tree} tree The owner tree
23032 * @param {Node} parent The parent node
23033 * @param {Node} node The child node removed
23038 * Fires when a node is moved to a new location in the tree
23039 * @param {Tree} tree The owner tree
23040 * @param {Node} node The node moved
23041 * @param {Node} oldParent The old parent of this node
23042 * @param {Node} newParent The new parent of this node
23043 * @param {Number} index The index it was moved to
23048 * Fires when a new child node is inserted in a node in this tree.
23049 * @param {Tree} tree The owner tree
23050 * @param {Node} parent The parent node
23051 * @param {Node} node The child node inserted
23052 * @param {Node} refNode The child node the node was inserted before
23056 * @event beforeappend
23057 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23058 * @param {Tree} tree The owner tree
23059 * @param {Node} parent The parent node
23060 * @param {Node} node The child node to be appended
23062 "beforeappend" : true,
23064 * @event beforeremove
23065 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23066 * @param {Tree} tree The owner tree
23067 * @param {Node} parent The parent node
23068 * @param {Node} node The child node to be removed
23070 "beforeremove" : true,
23072 * @event beforemove
23073 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23074 * @param {Tree} tree The owner tree
23075 * @param {Node} node The node being moved
23076 * @param {Node} oldParent The parent of the node
23077 * @param {Node} newParent The new parent the node is moving to
23078 * @param {Number} index The index it is being moved to
23080 "beforemove" : true,
23082 * @event beforeinsert
23083 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23084 * @param {Tree} tree The owner tree
23085 * @param {Node} parent The parent node
23086 * @param {Node} node The child node to be inserted
23087 * @param {Node} refNode The child node the node is being inserted before
23089 "beforeinsert" : true
23092 Roo.data.Tree.superclass.constructor.call(this);
23095 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23096 pathSeparator: "/",
23098 proxyNodeEvent : function(){
23099 return this.fireEvent.apply(this, arguments);
23103 * Returns the root node for this tree.
23106 getRootNode : function(){
23111 * Sets the root node for this tree.
23112 * @param {Node} node
23115 setRootNode : function(node){
23117 node.ownerTree = this;
23118 node.isRoot = true;
23119 this.registerNode(node);
23124 * Gets a node in this tree by its id.
23125 * @param {String} id
23128 getNodeById : function(id){
23129 return this.nodeHash[id];
23132 registerNode : function(node){
23133 this.nodeHash[node.id] = node;
23136 unregisterNode : function(node){
23137 delete this.nodeHash[node.id];
23140 toString : function(){
23141 return "[Tree"+(this.id?" "+this.id:"")+"]";
23146 * @class Roo.data.Node
23147 * @extends Roo.util.Observable
23148 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23149 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23151 * @param {Object} attributes The attributes/config for the node
23153 Roo.data.Node = function(attributes){
23155 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23158 this.attributes = attributes || {};
23159 this.leaf = this.attributes.leaf;
23161 * The node id. @type String
23163 this.id = this.attributes.id;
23165 this.id = Roo.id(null, "ynode-");
23166 this.attributes.id = this.id;
23171 * All child nodes of this node. @type Array
23173 this.childNodes = [];
23174 if(!this.childNodes.indexOf){ // indexOf is a must
23175 this.childNodes.indexOf = function(o){
23176 for(var i = 0, len = this.length; i < len; i++){
23185 * The parent node for this node. @type Node
23187 this.parentNode = null;
23189 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23191 this.firstChild = null;
23193 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23195 this.lastChild = null;
23197 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23199 this.previousSibling = null;
23201 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23203 this.nextSibling = null;
23208 * Fires when a new child node is appended
23209 * @param {Tree} tree The owner tree
23210 * @param {Node} this This node
23211 * @param {Node} node The newly appended node
23212 * @param {Number} index The index of the newly appended node
23217 * Fires when a child node is removed
23218 * @param {Tree} tree The owner tree
23219 * @param {Node} this This node
23220 * @param {Node} node The removed node
23225 * Fires when this node is moved to a new location in the tree
23226 * @param {Tree} tree The owner tree
23227 * @param {Node} this This node
23228 * @param {Node} oldParent The old parent of this node
23229 * @param {Node} newParent The new parent of this node
23230 * @param {Number} index The index it was moved to
23235 * Fires when a new child node is inserted.
23236 * @param {Tree} tree The owner tree
23237 * @param {Node} this This node
23238 * @param {Node} node The child node inserted
23239 * @param {Node} refNode The child node the node was inserted before
23243 * @event beforeappend
23244 * Fires before a new child is appended, return false to cancel the append.
23245 * @param {Tree} tree The owner tree
23246 * @param {Node} this This node
23247 * @param {Node} node The child node to be appended
23249 "beforeappend" : true,
23251 * @event beforeremove
23252 * Fires before a child is removed, return false to cancel the remove.
23253 * @param {Tree} tree The owner tree
23254 * @param {Node} this This node
23255 * @param {Node} node The child node to be removed
23257 "beforeremove" : true,
23259 * @event beforemove
23260 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23261 * @param {Tree} tree The owner tree
23262 * @param {Node} this This node
23263 * @param {Node} oldParent The parent of this node
23264 * @param {Node} newParent The new parent this node is moving to
23265 * @param {Number} index The index it is being moved to
23267 "beforemove" : true,
23269 * @event beforeinsert
23270 * Fires before a new child is inserted, return false to cancel the insert.
23271 * @param {Tree} tree The owner tree
23272 * @param {Node} this This node
23273 * @param {Node} node The child node to be inserted
23274 * @param {Node} refNode The child node the node is being inserted before
23276 "beforeinsert" : true
23278 this.listeners = this.attributes.listeners;
23279 Roo.data.Node.superclass.constructor.call(this);
23282 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23283 fireEvent : function(evtName){
23284 // first do standard event for this node
23285 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23288 // then bubble it up to the tree if the event wasn't cancelled
23289 var ot = this.getOwnerTree();
23291 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23299 * Returns true if this node is a leaf
23300 * @return {Boolean}
23302 isLeaf : function(){
23303 return this.leaf === true;
23307 setFirstChild : function(node){
23308 this.firstChild = node;
23312 setLastChild : function(node){
23313 this.lastChild = node;
23318 * Returns true if this node is the last child of its parent
23319 * @return {Boolean}
23321 isLast : function(){
23322 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23326 * Returns true if this node is the first child of its parent
23327 * @return {Boolean}
23329 isFirst : function(){
23330 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23333 hasChildNodes : function(){
23334 return !this.isLeaf() && this.childNodes.length > 0;
23338 * Insert node(s) as the last child node of this node.
23339 * @param {Node/Array} node The node or Array of nodes to append
23340 * @return {Node} The appended node if single append, or null if an array was passed
23342 appendChild : function(node){
23344 if(node instanceof Array){
23346 }else if(arguments.length > 1){
23349 // if passed an array or multiple args do them one by one
23351 for(var i = 0, len = multi.length; i < len; i++) {
23352 this.appendChild(multi[i]);
23355 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23358 var index = this.childNodes.length;
23359 var oldParent = node.parentNode;
23360 // it's a move, make sure we move it cleanly
23362 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23365 oldParent.removeChild(node);
23367 index = this.childNodes.length;
23369 this.setFirstChild(node);
23371 this.childNodes.push(node);
23372 node.parentNode = this;
23373 var ps = this.childNodes[index-1];
23375 node.previousSibling = ps;
23376 ps.nextSibling = node;
23378 node.previousSibling = null;
23380 node.nextSibling = null;
23381 this.setLastChild(node);
23382 node.setOwnerTree(this.getOwnerTree());
23383 this.fireEvent("append", this.ownerTree, this, node, index);
23385 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23392 * Removes a child node from this node.
23393 * @param {Node} node The node to remove
23394 * @return {Node} The removed node
23396 removeChild : function(node){
23397 var index = this.childNodes.indexOf(node);
23401 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23405 // remove it from childNodes collection
23406 this.childNodes.splice(index, 1);
23409 if(node.previousSibling){
23410 node.previousSibling.nextSibling = node.nextSibling;
23412 if(node.nextSibling){
23413 node.nextSibling.previousSibling = node.previousSibling;
23416 // update child refs
23417 if(this.firstChild == node){
23418 this.setFirstChild(node.nextSibling);
23420 if(this.lastChild == node){
23421 this.setLastChild(node.previousSibling);
23424 node.setOwnerTree(null);
23425 // clear any references from the node
23426 node.parentNode = null;
23427 node.previousSibling = null;
23428 node.nextSibling = null;
23429 this.fireEvent("remove", this.ownerTree, this, node);
23434 * Inserts the first node before the second node in this nodes childNodes collection.
23435 * @param {Node} node The node to insert
23436 * @param {Node} refNode The node to insert before (if null the node is appended)
23437 * @return {Node} The inserted node
23439 insertBefore : function(node, refNode){
23440 if(!refNode){ // like standard Dom, refNode can be null for append
23441 return this.appendChild(node);
23444 if(node == refNode){
23448 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23451 var index = this.childNodes.indexOf(refNode);
23452 var oldParent = node.parentNode;
23453 var refIndex = index;
23455 // when moving internally, indexes will change after remove
23456 if(oldParent == this && this.childNodes.indexOf(node) < index){
23460 // it's a move, make sure we move it cleanly
23462 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23465 oldParent.removeChild(node);
23468 this.setFirstChild(node);
23470 this.childNodes.splice(refIndex, 0, node);
23471 node.parentNode = this;
23472 var ps = this.childNodes[refIndex-1];
23474 node.previousSibling = ps;
23475 ps.nextSibling = node;
23477 node.previousSibling = null;
23479 node.nextSibling = refNode;
23480 refNode.previousSibling = node;
23481 node.setOwnerTree(this.getOwnerTree());
23482 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23484 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23490 * Returns the child node at the specified index.
23491 * @param {Number} index
23494 item : function(index){
23495 return this.childNodes[index];
23499 * Replaces one child node in this node with another.
23500 * @param {Node} newChild The replacement node
23501 * @param {Node} oldChild The node to replace
23502 * @return {Node} The replaced node
23504 replaceChild : function(newChild, oldChild){
23505 this.insertBefore(newChild, oldChild);
23506 this.removeChild(oldChild);
23511 * Returns the index of a child node
23512 * @param {Node} node
23513 * @return {Number} The index of the node or -1 if it was not found
23515 indexOf : function(child){
23516 return this.childNodes.indexOf(child);
23520 * Returns the tree this node is in.
23523 getOwnerTree : function(){
23524 // if it doesn't have one, look for one
23525 if(!this.ownerTree){
23529 this.ownerTree = p.ownerTree;
23535 return this.ownerTree;
23539 * Returns depth of this node (the root node has a depth of 0)
23542 getDepth : function(){
23545 while(p.parentNode){
23553 setOwnerTree : function(tree){
23554 // if it's move, we need to update everyone
23555 if(tree != this.ownerTree){
23556 if(this.ownerTree){
23557 this.ownerTree.unregisterNode(this);
23559 this.ownerTree = tree;
23560 var cs = this.childNodes;
23561 for(var i = 0, len = cs.length; i < len; i++) {
23562 cs[i].setOwnerTree(tree);
23565 tree.registerNode(this);
23571 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23572 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23573 * @return {String} The path
23575 getPath : function(attr){
23576 attr = attr || "id";
23577 var p = this.parentNode;
23578 var b = [this.attributes[attr]];
23580 b.unshift(p.attributes[attr]);
23583 var sep = this.getOwnerTree().pathSeparator;
23584 return sep + b.join(sep);
23588 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23589 * function call will be the scope provided or the current node. The arguments to the function
23590 * will be the args provided or the current node. If the function returns false at any point,
23591 * the bubble is stopped.
23592 * @param {Function} fn The function to call
23593 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23594 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23596 bubble : function(fn, scope, args){
23599 if(fn.call(scope || p, args || p) === false){
23607 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23608 * function call will be the scope provided or the current node. The arguments to the function
23609 * will be the args provided or the current node. If the function returns false at any point,
23610 * the cascade is stopped on that branch.
23611 * @param {Function} fn The function to call
23612 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23613 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23615 cascade : function(fn, scope, args){
23616 if(fn.call(scope || this, args || this) !== false){
23617 var cs = this.childNodes;
23618 for(var i = 0, len = cs.length; i < len; i++) {
23619 cs[i].cascade(fn, scope, args);
23625 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23626 * function call will be the scope provided or the current node. The arguments to the function
23627 * will be the args provided or the current node. If the function returns false at any point,
23628 * the iteration stops.
23629 * @param {Function} fn The function to call
23630 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23631 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23633 eachChild : function(fn, scope, args){
23634 var cs = this.childNodes;
23635 for(var i = 0, len = cs.length; i < len; i++) {
23636 if(fn.call(scope || this, args || cs[i]) === false){
23643 * Finds the first child that has the attribute with the specified value.
23644 * @param {String} attribute The attribute name
23645 * @param {Mixed} value The value to search for
23646 * @return {Node} The found child or null if none was found
23648 findChild : function(attribute, value){
23649 var cs = this.childNodes;
23650 for(var i = 0, len = cs.length; i < len; i++) {
23651 if(cs[i].attributes[attribute] == value){
23659 * Finds the first child by a custom function. The child matches if the function passed
23661 * @param {Function} fn
23662 * @param {Object} scope (optional)
23663 * @return {Node} The found child or null if none was found
23665 findChildBy : function(fn, scope){
23666 var cs = this.childNodes;
23667 for(var i = 0, len = cs.length; i < len; i++) {
23668 if(fn.call(scope||cs[i], cs[i]) === true){
23676 * Sorts this nodes children using the supplied sort function
23677 * @param {Function} fn
23678 * @param {Object} scope (optional)
23680 sort : function(fn, scope){
23681 var cs = this.childNodes;
23682 var len = cs.length;
23684 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23686 for(var i = 0; i < len; i++){
23688 n.previousSibling = cs[i-1];
23689 n.nextSibling = cs[i+1];
23691 this.setFirstChild(n);
23694 this.setLastChild(n);
23701 * Returns true if this node is an ancestor (at any point) of the passed node.
23702 * @param {Node} node
23703 * @return {Boolean}
23705 contains : function(node){
23706 return node.isAncestor(this);
23710 * Returns true if the passed node is an ancestor (at any point) of this node.
23711 * @param {Node} node
23712 * @return {Boolean}
23714 isAncestor : function(node){
23715 var p = this.parentNode;
23725 toString : function(){
23726 return "[Node"+(this.id?" "+this.id:"")+"]";
23730 * Ext JS Library 1.1.1
23731 * Copyright(c) 2006-2007, Ext JS, LLC.
23733 * Originally Released Under LGPL - original licence link has changed is not relivant.
23736 * <script type="text/javascript">
23741 * @extends Roo.Element
23742 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23743 * automatic maintaining of shadow/shim positions.
23744 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23745 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23746 * you can pass a string with a CSS class name. False turns off the shadow.
23747 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23748 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23749 * @cfg {String} cls CSS class to add to the element
23750 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23751 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23753 * @param {Object} config An object with config options.
23754 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23757 Roo.Layer = function(config, existingEl){
23758 config = config || {};
23759 var dh = Roo.DomHelper;
23760 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23762 this.dom = Roo.getDom(existingEl);
23765 var o = config.dh || {tag: "div", cls: "x-layer"};
23766 this.dom = dh.append(pel, o);
23769 this.addClass(config.cls);
23771 this.constrain = config.constrain !== false;
23772 this.visibilityMode = Roo.Element.VISIBILITY;
23774 this.id = this.dom.id = config.id;
23776 this.id = Roo.id(this.dom);
23778 this.zindex = config.zindex || this.getZIndex();
23779 this.position("absolute", this.zindex);
23781 this.shadowOffset = config.shadowOffset || 4;
23782 this.shadow = new Roo.Shadow({
23783 offset : this.shadowOffset,
23784 mode : config.shadow
23787 this.shadowOffset = 0;
23789 this.useShim = config.shim !== false && Roo.useShims;
23790 this.useDisplay = config.useDisplay;
23794 var supr = Roo.Element.prototype;
23796 // shims are shared among layer to keep from having 100 iframes
23799 Roo.extend(Roo.Layer, Roo.Element, {
23801 getZIndex : function(){
23802 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23805 getShim : function(){
23812 var shim = shims.shift();
23814 shim = this.createShim();
23815 shim.enableDisplayMode('block');
23816 shim.dom.style.display = 'none';
23817 shim.dom.style.visibility = 'visible';
23819 var pn = this.dom.parentNode;
23820 if(shim.dom.parentNode != pn){
23821 pn.insertBefore(shim.dom, this.dom);
23823 shim.setStyle('z-index', this.getZIndex()-2);
23828 hideShim : function(){
23830 this.shim.setDisplayed(false);
23831 shims.push(this.shim);
23836 disableShadow : function(){
23838 this.shadowDisabled = true;
23839 this.shadow.hide();
23840 this.lastShadowOffset = this.shadowOffset;
23841 this.shadowOffset = 0;
23845 enableShadow : function(show){
23847 this.shadowDisabled = false;
23848 this.shadowOffset = this.lastShadowOffset;
23849 delete this.lastShadowOffset;
23857 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23858 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23859 sync : function(doShow){
23860 var sw = this.shadow;
23861 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23862 var sh = this.getShim();
23864 var w = this.getWidth(),
23865 h = this.getHeight();
23867 var l = this.getLeft(true),
23868 t = this.getTop(true);
23870 if(sw && !this.shadowDisabled){
23871 if(doShow && !sw.isVisible()){
23874 sw.realign(l, t, w, h);
23880 // fit the shim behind the shadow, so it is shimmed too
23881 var a = sw.adjusts, s = sh.dom.style;
23882 s.left = (Math.min(l, l+a.l))+"px";
23883 s.top = (Math.min(t, t+a.t))+"px";
23884 s.width = (w+a.w)+"px";
23885 s.height = (h+a.h)+"px";
23892 sh.setLeftTop(l, t);
23899 destroy : function(){
23902 this.shadow.hide();
23904 this.removeAllListeners();
23905 var pn = this.dom.parentNode;
23907 pn.removeChild(this.dom);
23909 Roo.Element.uncache(this.id);
23912 remove : function(){
23917 beginUpdate : function(){
23918 this.updating = true;
23922 endUpdate : function(){
23923 this.updating = false;
23928 hideUnders : function(negOffset){
23930 this.shadow.hide();
23936 constrainXY : function(){
23937 if(this.constrain){
23938 var vw = Roo.lib.Dom.getViewWidth(),
23939 vh = Roo.lib.Dom.getViewHeight();
23940 var s = Roo.get(document).getScroll();
23942 var xy = this.getXY();
23943 var x = xy[0], y = xy[1];
23944 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23945 // only move it if it needs it
23947 // first validate right/bottom
23948 if((x + w) > vw+s.left){
23949 x = vw - w - this.shadowOffset;
23952 if((y + h) > vh+s.top){
23953 y = vh - h - this.shadowOffset;
23956 // then make sure top/left isn't negative
23967 var ay = this.avoidY;
23968 if(y <= ay && (y+h) >= ay){
23974 supr.setXY.call(this, xy);
23980 isVisible : function(){
23981 return this.visible;
23985 showAction : function(){
23986 this.visible = true; // track visibility to prevent getStyle calls
23987 if(this.useDisplay === true){
23988 this.setDisplayed("");
23989 }else if(this.lastXY){
23990 supr.setXY.call(this, this.lastXY);
23991 }else if(this.lastLT){
23992 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23997 hideAction : function(){
23998 this.visible = false;
23999 if(this.useDisplay === true){
24000 this.setDisplayed(false);
24002 this.setLeftTop(-10000,-10000);
24006 // overridden Element method
24007 setVisible : function(v, a, d, c, e){
24012 var cb = function(){
24017 }.createDelegate(this);
24018 supr.setVisible.call(this, true, true, d, cb, e);
24021 this.hideUnders(true);
24030 }.createDelegate(this);
24032 supr.setVisible.call(this, v, a, d, cb, e);
24041 storeXY : function(xy){
24042 delete this.lastLT;
24046 storeLeftTop : function(left, top){
24047 delete this.lastXY;
24048 this.lastLT = [left, top];
24052 beforeFx : function(){
24053 this.beforeAction();
24054 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24058 afterFx : function(){
24059 Roo.Layer.superclass.afterFx.apply(this, arguments);
24060 this.sync(this.isVisible());
24064 beforeAction : function(){
24065 if(!this.updating && this.shadow){
24066 this.shadow.hide();
24070 // overridden Element method
24071 setLeft : function(left){
24072 this.storeLeftTop(left, this.getTop(true));
24073 supr.setLeft.apply(this, arguments);
24077 setTop : function(top){
24078 this.storeLeftTop(this.getLeft(true), top);
24079 supr.setTop.apply(this, arguments);
24083 setLeftTop : function(left, top){
24084 this.storeLeftTop(left, top);
24085 supr.setLeftTop.apply(this, arguments);
24089 setXY : function(xy, a, d, c, e){
24091 this.beforeAction();
24093 var cb = this.createCB(c);
24094 supr.setXY.call(this, xy, a, d, cb, e);
24101 createCB : function(c){
24112 // overridden Element method
24113 setX : function(x, a, d, c, e){
24114 this.setXY([x, this.getY()], a, d, c, e);
24117 // overridden Element method
24118 setY : function(y, a, d, c, e){
24119 this.setXY([this.getX(), y], a, d, c, e);
24122 // overridden Element method
24123 setSize : function(w, h, a, d, c, e){
24124 this.beforeAction();
24125 var cb = this.createCB(c);
24126 supr.setSize.call(this, w, h, a, d, cb, e);
24132 // overridden Element method
24133 setWidth : function(w, a, d, c, e){
24134 this.beforeAction();
24135 var cb = this.createCB(c);
24136 supr.setWidth.call(this, w, a, d, cb, e);
24142 // overridden Element method
24143 setHeight : function(h, a, d, c, e){
24144 this.beforeAction();
24145 var cb = this.createCB(c);
24146 supr.setHeight.call(this, h, a, d, cb, e);
24152 // overridden Element method
24153 setBounds : function(x, y, w, h, a, d, c, e){
24154 this.beforeAction();
24155 var cb = this.createCB(c);
24157 this.storeXY([x, y]);
24158 supr.setXY.call(this, [x, y]);
24159 supr.setSize.call(this, w, h, a, d, cb, e);
24162 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24168 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24169 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24170 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24171 * @param {Number} zindex The new z-index to set
24172 * @return {this} The Layer
24174 setZIndex : function(zindex){
24175 this.zindex = zindex;
24176 this.setStyle("z-index", zindex + 2);
24178 this.shadow.setZIndex(zindex + 1);
24181 this.shim.setStyle("z-index", zindex);
24187 * Ext JS Library 1.1.1
24188 * Copyright(c) 2006-2007, Ext JS, LLC.
24190 * Originally Released Under LGPL - original licence link has changed is not relivant.
24193 * <script type="text/javascript">
24198 * @class Roo.Shadow
24199 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24200 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24201 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24203 * Create a new Shadow
24204 * @param {Object} config The config object
24206 Roo.Shadow = function(config){
24207 Roo.apply(this, config);
24208 if(typeof this.mode != "string"){
24209 this.mode = this.defaultMode;
24211 var o = this.offset, a = {h: 0};
24212 var rad = Math.floor(this.offset/2);
24213 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24219 a.l -= this.offset + rad;
24220 a.t -= this.offset + rad;
24231 a.l -= (this.offset - rad);
24232 a.t -= this.offset + rad;
24234 a.w -= (this.offset - rad)*2;
24245 a.l -= (this.offset - rad);
24246 a.t -= (this.offset - rad);
24248 a.w -= (this.offset + rad + 1);
24249 a.h -= (this.offset + rad);
24258 Roo.Shadow.prototype = {
24260 * @cfg {String} mode
24261 * The shadow display mode. Supports the following options:<br />
24262 * sides: Shadow displays on both sides and bottom only<br />
24263 * frame: Shadow displays equally on all four sides<br />
24264 * drop: Traditional bottom-right drop shadow (default)
24267 * @cfg {String} offset
24268 * The number of pixels to offset the shadow from the element (defaults to 4)
24273 defaultMode: "drop",
24276 * Displays the shadow under the target element
24277 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24279 show : function(target){
24280 target = Roo.get(target);
24282 this.el = Roo.Shadow.Pool.pull();
24283 if(this.el.dom.nextSibling != target.dom){
24284 this.el.insertBefore(target);
24287 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24289 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24292 target.getLeft(true),
24293 target.getTop(true),
24297 this.el.dom.style.display = "block";
24301 * Returns true if the shadow is visible, else false
24303 isVisible : function(){
24304 return this.el ? true : false;
24308 * Direct alignment when values are already available. Show must be called at least once before
24309 * calling this method to ensure it is initialized.
24310 * @param {Number} left The target element left position
24311 * @param {Number} top The target element top position
24312 * @param {Number} width The target element width
24313 * @param {Number} height The target element height
24315 realign : function(l, t, w, h){
24319 var a = this.adjusts, d = this.el.dom, s = d.style;
24321 s.left = (l+a.l)+"px";
24322 s.top = (t+a.t)+"px";
24323 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24325 if(s.width != sws || s.height != shs){
24329 var cn = d.childNodes;
24330 var sww = Math.max(0, (sw-12))+"px";
24331 cn[0].childNodes[1].style.width = sww;
24332 cn[1].childNodes[1].style.width = sww;
24333 cn[2].childNodes[1].style.width = sww;
24334 cn[1].style.height = Math.max(0, (sh-12))+"px";
24340 * Hides this shadow
24344 this.el.dom.style.display = "none";
24345 Roo.Shadow.Pool.push(this.el);
24351 * Adjust the z-index of this shadow
24352 * @param {Number} zindex The new z-index
24354 setZIndex : function(z){
24357 this.el.setStyle("z-index", z);
24362 // Private utility class that manages the internal Shadow cache
24363 Roo.Shadow.Pool = function(){
24365 var markup = Roo.isIE ?
24366 '<div class="x-ie-shadow"></div>' :
24367 '<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>';
24370 var sh = p.shift();
24372 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24373 sh.autoBoxAdjust = false;
24378 push : function(sh){
24384 * Ext JS Library 1.1.1
24385 * Copyright(c) 2006-2007, Ext JS, LLC.
24387 * Originally Released Under LGPL - original licence link has changed is not relivant.
24390 * <script type="text/javascript">
24395 * @class Roo.SplitBar
24396 * @extends Roo.util.Observable
24397 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24401 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24402 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24403 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24404 split.minSize = 100;
24405 split.maxSize = 600;
24406 split.animate = true;
24407 split.on('moved', splitterMoved);
24410 * Create a new SplitBar
24411 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24412 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24413 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24414 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24415 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24416 position of the SplitBar).
24418 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24421 this.el = Roo.get(dragElement, true);
24422 this.el.dom.unselectable = "on";
24424 this.resizingEl = Roo.get(resizingElement, true);
24428 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24429 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24432 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24435 * The minimum size of the resizing element. (Defaults to 0)
24441 * The maximum size of the resizing element. (Defaults to 2000)
24444 this.maxSize = 2000;
24447 * Whether to animate the transition to the new size
24450 this.animate = false;
24453 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24456 this.useShim = false;
24461 if(!existingProxy){
24463 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24465 this.proxy = Roo.get(existingProxy).dom;
24468 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24471 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24474 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24477 this.dragSpecs = {};
24480 * @private The adapter to use to positon and resize elements
24482 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24483 this.adapter.init(this);
24485 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24487 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24488 this.el.addClass("x-splitbar-h");
24491 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24492 this.el.addClass("x-splitbar-v");
24498 * Fires when the splitter is moved (alias for {@link #event-moved})
24499 * @param {Roo.SplitBar} this
24500 * @param {Number} newSize the new width or height
24505 * Fires when the splitter is moved
24506 * @param {Roo.SplitBar} this
24507 * @param {Number} newSize the new width or height
24511 * @event beforeresize
24512 * Fires before the splitter is dragged
24513 * @param {Roo.SplitBar} this
24515 "beforeresize" : true,
24517 "beforeapply" : true
24520 Roo.util.Observable.call(this);
24523 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24524 onStartProxyDrag : function(x, y){
24525 this.fireEvent("beforeresize", this);
24527 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24529 o.enableDisplayMode("block");
24530 // all splitbars share the same overlay
24531 Roo.SplitBar.prototype.overlay = o;
24533 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24534 this.overlay.show();
24535 Roo.get(this.proxy).setDisplayed("block");
24536 var size = this.adapter.getElementSize(this);
24537 this.activeMinSize = this.getMinimumSize();;
24538 this.activeMaxSize = this.getMaximumSize();;
24539 var c1 = size - this.activeMinSize;
24540 var c2 = Math.max(this.activeMaxSize - size, 0);
24541 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24542 this.dd.resetConstraints();
24543 this.dd.setXConstraint(
24544 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24545 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24547 this.dd.setYConstraint(0, 0);
24549 this.dd.resetConstraints();
24550 this.dd.setXConstraint(0, 0);
24551 this.dd.setYConstraint(
24552 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24553 this.placement == Roo.SplitBar.TOP ? c2 : c1
24556 this.dragSpecs.startSize = size;
24557 this.dragSpecs.startPoint = [x, y];
24558 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24562 * @private Called after the drag operation by the DDProxy
24564 onEndProxyDrag : function(e){
24565 Roo.get(this.proxy).setDisplayed(false);
24566 var endPoint = Roo.lib.Event.getXY(e);
24568 this.overlay.hide();
24571 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24572 newSize = this.dragSpecs.startSize +
24573 (this.placement == Roo.SplitBar.LEFT ?
24574 endPoint[0] - this.dragSpecs.startPoint[0] :
24575 this.dragSpecs.startPoint[0] - endPoint[0]
24578 newSize = this.dragSpecs.startSize +
24579 (this.placement == Roo.SplitBar.TOP ?
24580 endPoint[1] - this.dragSpecs.startPoint[1] :
24581 this.dragSpecs.startPoint[1] - endPoint[1]
24584 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24585 if(newSize != this.dragSpecs.startSize){
24586 if(this.fireEvent('beforeapply', this, newSize) !== false){
24587 this.adapter.setElementSize(this, newSize);
24588 this.fireEvent("moved", this, newSize);
24589 this.fireEvent("resize", this, newSize);
24595 * Get the adapter this SplitBar uses
24596 * @return The adapter object
24598 getAdapter : function(){
24599 return this.adapter;
24603 * Set the adapter this SplitBar uses
24604 * @param {Object} adapter A SplitBar adapter object
24606 setAdapter : function(adapter){
24607 this.adapter = adapter;
24608 this.adapter.init(this);
24612 * Gets the minimum size for the resizing element
24613 * @return {Number} The minimum size
24615 getMinimumSize : function(){
24616 return this.minSize;
24620 * Sets the minimum size for the resizing element
24621 * @param {Number} minSize The minimum size
24623 setMinimumSize : function(minSize){
24624 this.minSize = minSize;
24628 * Gets the maximum size for the resizing element
24629 * @return {Number} The maximum size
24631 getMaximumSize : function(){
24632 return this.maxSize;
24636 * Sets the maximum size for the resizing element
24637 * @param {Number} maxSize The maximum size
24639 setMaximumSize : function(maxSize){
24640 this.maxSize = maxSize;
24644 * Sets the initialize size for the resizing element
24645 * @param {Number} size The initial size
24647 setCurrentSize : function(size){
24648 var oldAnimate = this.animate;
24649 this.animate = false;
24650 this.adapter.setElementSize(this, size);
24651 this.animate = oldAnimate;
24655 * Destroy this splitbar.
24656 * @param {Boolean} removeEl True to remove the element
24658 destroy : function(removeEl){
24660 this.shim.remove();
24663 this.proxy.parentNode.removeChild(this.proxy);
24671 * @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.
24673 Roo.SplitBar.createProxy = function(dir){
24674 var proxy = new Roo.Element(document.createElement("div"));
24675 proxy.unselectable();
24676 var cls = 'x-splitbar-proxy';
24677 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24678 document.body.appendChild(proxy.dom);
24683 * @class Roo.SplitBar.BasicLayoutAdapter
24684 * Default Adapter. It assumes the splitter and resizing element are not positioned
24685 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24687 Roo.SplitBar.BasicLayoutAdapter = function(){
24690 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24691 // do nothing for now
24692 init : function(s){
24696 * Called before drag operations to get the current size of the resizing element.
24697 * @param {Roo.SplitBar} s The SplitBar using this adapter
24699 getElementSize : function(s){
24700 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24701 return s.resizingEl.getWidth();
24703 return s.resizingEl.getHeight();
24708 * Called after drag operations to set the size of the resizing element.
24709 * @param {Roo.SplitBar} s The SplitBar using this adapter
24710 * @param {Number} newSize The new size to set
24711 * @param {Function} onComplete A function to be invoked when resizing is complete
24713 setElementSize : function(s, newSize, onComplete){
24714 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24716 s.resizingEl.setWidth(newSize);
24718 onComplete(s, newSize);
24721 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24726 s.resizingEl.setHeight(newSize);
24728 onComplete(s, newSize);
24731 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24738 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24739 * @extends Roo.SplitBar.BasicLayoutAdapter
24740 * Adapter that moves the splitter element to align with the resized sizing element.
24741 * Used with an absolute positioned SplitBar.
24742 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24743 * document.body, make sure you assign an id to the body element.
24745 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24746 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24747 this.container = Roo.get(container);
24750 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24751 init : function(s){
24752 this.basic.init(s);
24755 getElementSize : function(s){
24756 return this.basic.getElementSize(s);
24759 setElementSize : function(s, newSize, onComplete){
24760 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24763 moveSplitter : function(s){
24764 var yes = Roo.SplitBar;
24765 switch(s.placement){
24767 s.el.setX(s.resizingEl.getRight());
24770 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24773 s.el.setY(s.resizingEl.getBottom());
24776 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24783 * Orientation constant - Create a vertical SplitBar
24787 Roo.SplitBar.VERTICAL = 1;
24790 * Orientation constant - Create a horizontal SplitBar
24794 Roo.SplitBar.HORIZONTAL = 2;
24797 * Placement constant - The resizing element is to the left of the splitter element
24801 Roo.SplitBar.LEFT = 1;
24804 * Placement constant - The resizing element is to the right of the splitter element
24808 Roo.SplitBar.RIGHT = 2;
24811 * Placement constant - The resizing element is positioned above the splitter element
24815 Roo.SplitBar.TOP = 3;
24818 * Placement constant - The resizing element is positioned under splitter element
24822 Roo.SplitBar.BOTTOM = 4;
24825 * Ext JS Library 1.1.1
24826 * Copyright(c) 2006-2007, Ext JS, LLC.
24828 * Originally Released Under LGPL - original licence link has changed is not relivant.
24831 * <script type="text/javascript">
24836 * @extends Roo.util.Observable
24837 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24838 * This class also supports single and multi selection modes. <br>
24839 * Create a data model bound view:
24841 var store = new Roo.data.Store(...);
24843 var view = new Roo.View({
24845 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24847 singleSelect: true,
24848 selectedClass: "ydataview-selected",
24852 // listen for node click?
24853 view.on("click", function(vw, index, node, e){
24854 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24858 dataModel.load("foobar.xml");
24860 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24862 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24863 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24865 * Note: old style constructor is still suported (container, template, config)
24868 * Create a new View
24869 * @param {Object} config The config object
24872 Roo.View = function(config, depreciated_tpl, depreciated_config){
24874 this.parent = false;
24876 if (typeof(depreciated_tpl) == 'undefined') {
24877 // new way.. - universal constructor.
24878 Roo.apply(this, config);
24879 this.el = Roo.get(this.el);
24882 this.el = Roo.get(config);
24883 this.tpl = depreciated_tpl;
24884 Roo.apply(this, depreciated_config);
24886 this.wrapEl = this.el.wrap().wrap();
24887 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24890 if(typeof(this.tpl) == "string"){
24891 this.tpl = new Roo.Template(this.tpl);
24893 // support xtype ctors..
24894 this.tpl = new Roo.factory(this.tpl, Roo);
24898 this.tpl.compile();
24903 * @event beforeclick
24904 * Fires before a click is processed. Returns false to cancel the default action.
24905 * @param {Roo.View} this
24906 * @param {Number} index The index of the target node
24907 * @param {HTMLElement} node The target node
24908 * @param {Roo.EventObject} e The raw event object
24910 "beforeclick" : true,
24913 * Fires when a template node is clicked.
24914 * @param {Roo.View} this
24915 * @param {Number} index The index of the target node
24916 * @param {HTMLElement} node The target node
24917 * @param {Roo.EventObject} e The raw event object
24922 * Fires when a template node is double clicked.
24923 * @param {Roo.View} this
24924 * @param {Number} index The index of the target node
24925 * @param {HTMLElement} node The target node
24926 * @param {Roo.EventObject} e The raw event object
24930 * @event contextmenu
24931 * Fires when a template node is right clicked.
24932 * @param {Roo.View} this
24933 * @param {Number} index The index of the target node
24934 * @param {HTMLElement} node The target node
24935 * @param {Roo.EventObject} e The raw event object
24937 "contextmenu" : true,
24939 * @event selectionchange
24940 * Fires when the selected nodes change.
24941 * @param {Roo.View} this
24942 * @param {Array} selections Array of the selected nodes
24944 "selectionchange" : true,
24947 * @event beforeselect
24948 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24949 * @param {Roo.View} this
24950 * @param {HTMLElement} node The node to be selected
24951 * @param {Array} selections Array of currently selected nodes
24953 "beforeselect" : true,
24955 * @event preparedata
24956 * Fires on every row to render, to allow you to change the data.
24957 * @param {Roo.View} this
24958 * @param {Object} data to be rendered (change this)
24960 "preparedata" : true
24968 "click": this.onClick,
24969 "dblclick": this.onDblClick,
24970 "contextmenu": this.onContextMenu,
24974 this.selections = [];
24976 this.cmp = new Roo.CompositeElementLite([]);
24978 this.store = Roo.factory(this.store, Roo.data);
24979 this.setStore(this.store, true);
24982 if ( this.footer && this.footer.xtype) {
24984 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24986 this.footer.dataSource = this.store
24987 this.footer.container = fctr;
24988 this.footer = Roo.factory(this.footer, Roo);
24989 fctr.insertFirst(this.el);
24991 // this is a bit insane - as the paging toolbar seems to detach the el..
24992 // dom.parentNode.parentNode.parentNode
24993 // they get detached?
24997 Roo.View.superclass.constructor.call(this);
25002 Roo.extend(Roo.View, Roo.util.Observable, {
25005 * @cfg {Roo.data.Store} store Data store to load data from.
25010 * @cfg {String|Roo.Element} el The container element.
25015 * @cfg {String|Roo.Template} tpl The template used by this View
25019 * @cfg {String} dataName the named area of the template to use as the data area
25020 * Works with domtemplates roo-name="name"
25024 * @cfg {String} selectedClass The css class to add to selected nodes
25026 selectedClass : "x-view-selected",
25028 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25033 * @cfg {String} text to display on mask (default Loading)
25037 * @cfg {Boolean} multiSelect Allow multiple selection
25039 multiSelect : false,
25041 * @cfg {Boolean} singleSelect Allow single selection
25043 singleSelect: false,
25046 * @cfg {Boolean} toggleSelect - selecting
25048 toggleSelect : false,
25051 * @cfg {Boolean} tickable - selecting
25056 * Returns the element this view is bound to.
25057 * @return {Roo.Element}
25059 getEl : function(){
25060 return this.wrapEl;
25066 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25068 refresh : function(){
25069 //Roo.log('refresh');
25072 // if we are using something like 'domtemplate', then
25073 // the what gets used is:
25074 // t.applySubtemplate(NAME, data, wrapping data..)
25075 // the outer template then get' applied with
25076 // the store 'extra data'
25077 // and the body get's added to the
25078 // roo-name="data" node?
25079 // <span class='roo-tpl-{name}'></span> ?????
25083 this.clearSelections();
25084 this.el.update("");
25086 var records = this.store.getRange();
25087 if(records.length < 1) {
25089 // is this valid?? = should it render a template??
25091 this.el.update(this.emptyText);
25095 if (this.dataName) {
25096 this.el.update(t.apply(this.store.meta)); //????
25097 el = this.el.child('.roo-tpl-' + this.dataName);
25100 for(var i = 0, len = records.length; i < len; i++){
25101 var data = this.prepareData(records[i].data, i, records[i]);
25102 this.fireEvent("preparedata", this, data, i, records[i]);
25104 var d = Roo.apply({}, data);
25107 Roo.apply(d, {'roo-id' : Roo.id()});
25111 Roo.each(this.parent.item, function(item){
25112 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25115 Roo.apply(d, {'roo-data-checked' : 'checked'});
25119 html[html.length] = Roo.util.Format.trim(
25121 t.applySubtemplate(this.dataName, d, this.store.meta) :
25128 el.update(html.join(""));
25129 this.nodes = el.dom.childNodes;
25130 this.updateIndexes(0);
25135 * Function to override to reformat the data that is sent to
25136 * the template for each node.
25137 * DEPRICATED - use the preparedata event handler.
25138 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25139 * a JSON object for an UpdateManager bound view).
25141 prepareData : function(data, index, record)
25143 this.fireEvent("preparedata", this, data, index, record);
25147 onUpdate : function(ds, record){
25148 // Roo.log('on update');
25149 this.clearSelections();
25150 var index = this.store.indexOf(record);
25151 var n = this.nodes[index];
25152 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25153 n.parentNode.removeChild(n);
25154 this.updateIndexes(index, index);
25160 onAdd : function(ds, records, index)
25162 //Roo.log(['on Add', ds, records, index] );
25163 this.clearSelections();
25164 if(this.nodes.length == 0){
25168 var n = this.nodes[index];
25169 for(var i = 0, len = records.length; i < len; i++){
25170 var d = this.prepareData(records[i].data, i, records[i]);
25172 this.tpl.insertBefore(n, d);
25175 this.tpl.append(this.el, d);
25178 this.updateIndexes(index);
25181 onRemove : function(ds, record, index){
25182 // Roo.log('onRemove');
25183 this.clearSelections();
25184 var el = this.dataName ?
25185 this.el.child('.roo-tpl-' + this.dataName) :
25188 el.dom.removeChild(this.nodes[index]);
25189 this.updateIndexes(index);
25193 * Refresh an individual node.
25194 * @param {Number} index
25196 refreshNode : function(index){
25197 this.onUpdate(this.store, this.store.getAt(index));
25200 updateIndexes : function(startIndex, endIndex){
25201 var ns = this.nodes;
25202 startIndex = startIndex || 0;
25203 endIndex = endIndex || ns.length - 1;
25204 for(var i = startIndex; i <= endIndex; i++){
25205 ns[i].nodeIndex = i;
25210 * Changes the data store this view uses and refresh the view.
25211 * @param {Store} store
25213 setStore : function(store, initial){
25214 if(!initial && this.store){
25215 this.store.un("datachanged", this.refresh);
25216 this.store.un("add", this.onAdd);
25217 this.store.un("remove", this.onRemove);
25218 this.store.un("update", this.onUpdate);
25219 this.store.un("clear", this.refresh);
25220 this.store.un("beforeload", this.onBeforeLoad);
25221 this.store.un("load", this.onLoad);
25222 this.store.un("loadexception", this.onLoad);
25226 store.on("datachanged", this.refresh, this);
25227 store.on("add", this.onAdd, this);
25228 store.on("remove", this.onRemove, this);
25229 store.on("update", this.onUpdate, this);
25230 store.on("clear", this.refresh, this);
25231 store.on("beforeload", this.onBeforeLoad, this);
25232 store.on("load", this.onLoad, this);
25233 store.on("loadexception", this.onLoad, this);
25241 * onbeforeLoad - masks the loading area.
25244 onBeforeLoad : function(store,opts)
25246 //Roo.log('onBeforeLoad');
25248 this.el.update("");
25250 this.el.mask(this.mask ? this.mask : "Loading" );
25252 onLoad : function ()
25259 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25260 * @param {HTMLElement} node
25261 * @return {HTMLElement} The template node
25263 findItemFromChild : function(node){
25264 var el = this.dataName ?
25265 this.el.child('.roo-tpl-' + this.dataName,true) :
25268 if(!node || node.parentNode == el){
25271 var p = node.parentNode;
25272 while(p && p != el){
25273 if(p.parentNode == el){
25282 onClick : function(e){
25283 var item = this.findItemFromChild(e.getTarget());
25285 var index = this.indexOf(item);
25286 if(this.onItemClick(item, index, e) !== false){
25287 this.fireEvent("click", this, index, item, e);
25290 this.clearSelections();
25295 onContextMenu : function(e){
25296 var item = this.findItemFromChild(e.getTarget());
25298 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25303 onDblClick : function(e){
25304 var item = this.findItemFromChild(e.getTarget());
25306 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25310 onItemClick : function(item, index, e)
25312 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25315 if (this.toggleSelect) {
25316 var m = this.isSelected(item) ? 'unselect' : 'select';
25319 _t[m](item, true, false);
25322 if(this.multiSelect || this.singleSelect){
25323 if(this.multiSelect && e.shiftKey && this.lastSelection){
25324 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25326 this.select(item, this.multiSelect && e.ctrlKey);
25327 this.lastSelection = item;
25330 if(!this.tickable){
25331 e.preventDefault();
25339 * Get the number of selected nodes.
25342 getSelectionCount : function(){
25343 return this.selections.length;
25347 * Get the currently selected nodes.
25348 * @return {Array} An array of HTMLElements
25350 getSelectedNodes : function(){
25351 return this.selections;
25355 * Get the indexes of the selected nodes.
25358 getSelectedIndexes : function(){
25359 var indexes = [], s = this.selections;
25360 for(var i = 0, len = s.length; i < len; i++){
25361 indexes.push(s[i].nodeIndex);
25367 * Clear all selections
25368 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25370 clearSelections : function(suppressEvent){
25371 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25372 this.cmp.elements = this.selections;
25373 this.cmp.removeClass(this.selectedClass);
25374 this.selections = [];
25375 if(!suppressEvent){
25376 this.fireEvent("selectionchange", this, this.selections);
25382 * Returns true if the passed node is selected
25383 * @param {HTMLElement/Number} node The node or node index
25384 * @return {Boolean}
25386 isSelected : function(node){
25387 var s = this.selections;
25391 node = this.getNode(node);
25392 return s.indexOf(node) !== -1;
25397 * @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
25398 * @param {Boolean} keepExisting (optional) true to keep existing selections
25399 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25401 select : function(nodeInfo, keepExisting, suppressEvent){
25402 if(nodeInfo instanceof Array){
25404 this.clearSelections(true);
25406 for(var i = 0, len = nodeInfo.length; i < len; i++){
25407 this.select(nodeInfo[i], true, true);
25411 var node = this.getNode(nodeInfo);
25412 if(!node || this.isSelected(node)){
25413 return; // already selected.
25416 this.clearSelections(true);
25419 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25420 Roo.fly(node).addClass(this.selectedClass);
25421 this.selections.push(node);
25422 if(!suppressEvent){
25423 this.fireEvent("selectionchange", this, this.selections);
25431 * @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
25432 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25433 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25435 unselect : function(nodeInfo, keepExisting, suppressEvent)
25437 if(nodeInfo instanceof Array){
25438 Roo.each(this.selections, function(s) {
25439 this.unselect(s, nodeInfo);
25443 var node = this.getNode(nodeInfo);
25444 if(!node || !this.isSelected(node)){
25445 //Roo.log("not selected");
25446 return; // not selected.
25450 Roo.each(this.selections, function(s) {
25452 Roo.fly(node).removeClass(this.selectedClass);
25459 this.selections= ns;
25460 this.fireEvent("selectionchange", this, this.selections);
25464 * Gets a template node.
25465 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25466 * @return {HTMLElement} The node or null if it wasn't found
25468 getNode : function(nodeInfo){
25469 if(typeof nodeInfo == "string"){
25470 return document.getElementById(nodeInfo);
25471 }else if(typeof nodeInfo == "number"){
25472 return this.nodes[nodeInfo];
25478 * Gets a range template nodes.
25479 * @param {Number} startIndex
25480 * @param {Number} endIndex
25481 * @return {Array} An array of nodes
25483 getNodes : function(start, end){
25484 var ns = this.nodes;
25485 start = start || 0;
25486 end = typeof end == "undefined" ? ns.length - 1 : end;
25489 for(var i = start; i <= end; i++){
25493 for(var i = start; i >= end; i--){
25501 * Finds the index of the passed node
25502 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25503 * @return {Number} The index of the node or -1
25505 indexOf : function(node){
25506 node = this.getNode(node);
25507 if(typeof node.nodeIndex == "number"){
25508 return node.nodeIndex;
25510 var ns = this.nodes;
25511 for(var i = 0, len = ns.length; i < len; i++){
25521 * Ext JS Library 1.1.1
25522 * Copyright(c) 2006-2007, Ext JS, LLC.
25524 * Originally Released Under LGPL - original licence link has changed is not relivant.
25527 * <script type="text/javascript">
25531 * @class Roo.JsonView
25532 * @extends Roo.View
25533 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25535 var view = new Roo.JsonView({
25536 container: "my-element",
25537 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25542 // listen for node click?
25543 view.on("click", function(vw, index, node, e){
25544 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25547 // direct load of JSON data
25548 view.load("foobar.php");
25550 // Example from my blog list
25551 var tpl = new Roo.Template(
25552 '<div class="entry">' +
25553 '<a class="entry-title" href="{link}">{title}</a>' +
25554 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25555 "</div><hr />"
25558 var moreView = new Roo.JsonView({
25559 container : "entry-list",
25563 moreView.on("beforerender", this.sortEntries, this);
25565 url: "/blog/get-posts.php",
25566 params: "allposts=true",
25567 text: "Loading Blog Entries..."
25571 * Note: old code is supported with arguments : (container, template, config)
25575 * Create a new JsonView
25577 * @param {Object} config The config object
25580 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25583 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25585 var um = this.el.getUpdateManager();
25586 um.setRenderer(this);
25587 um.on("update", this.onLoad, this);
25588 um.on("failure", this.onLoadException, this);
25591 * @event beforerender
25592 * Fires before rendering of the downloaded JSON data.
25593 * @param {Roo.JsonView} this
25594 * @param {Object} data The JSON data loaded
25598 * Fires when data is loaded.
25599 * @param {Roo.JsonView} this
25600 * @param {Object} data The JSON data loaded
25601 * @param {Object} response The raw Connect response object
25604 * @event loadexception
25605 * Fires when loading fails.
25606 * @param {Roo.JsonView} this
25607 * @param {Object} response The raw Connect response object
25610 'beforerender' : true,
25612 'loadexception' : true
25615 Roo.extend(Roo.JsonView, Roo.View, {
25617 * @type {String} The root property in the loaded JSON object that contains the data
25622 * Refreshes the view.
25624 refresh : function(){
25625 this.clearSelections();
25626 this.el.update("");
25628 var o = this.jsonData;
25629 if(o && o.length > 0){
25630 for(var i = 0, len = o.length; i < len; i++){
25631 var data = this.prepareData(o[i], i, o);
25632 html[html.length] = this.tpl.apply(data);
25635 html.push(this.emptyText);
25637 this.el.update(html.join(""));
25638 this.nodes = this.el.dom.childNodes;
25639 this.updateIndexes(0);
25643 * 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.
25644 * @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:
25647 url: "your-url.php",
25648 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25649 callback: yourFunction,
25650 scope: yourObject, //(optional scope)
25653 text: "Loading...",
25658 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25659 * 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.
25660 * @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}
25661 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25662 * @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.
25665 var um = this.el.getUpdateManager();
25666 um.update.apply(um, arguments);
25669 render : function(el, response){
25670 this.clearSelections();
25671 this.el.update("");
25674 o = Roo.util.JSON.decode(response.responseText);
25677 o = o[this.jsonRoot];
25682 * The current JSON data or null
25685 this.beforeRender();
25690 * Get the number of records in the current JSON dataset
25693 getCount : function(){
25694 return this.jsonData ? this.jsonData.length : 0;
25698 * Returns the JSON object for the specified node(s)
25699 * @param {HTMLElement/Array} node The node or an array of nodes
25700 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25701 * you get the JSON object for the node
25703 getNodeData : function(node){
25704 if(node instanceof Array){
25706 for(var i = 0, len = node.length; i < len; i++){
25707 data.push(this.getNodeData(node[i]));
25711 return this.jsonData[this.indexOf(node)] || null;
25714 beforeRender : function(){
25715 this.snapshot = this.jsonData;
25717 this.sort.apply(this, this.sortInfo);
25719 this.fireEvent("beforerender", this, this.jsonData);
25722 onLoad : function(el, o){
25723 this.fireEvent("load", this, this.jsonData, o);
25726 onLoadException : function(el, o){
25727 this.fireEvent("loadexception", this, o);
25731 * Filter the data by a specific property.
25732 * @param {String} property A property on your JSON objects
25733 * @param {String/RegExp} value Either string that the property values
25734 * should start with, or a RegExp to test against the property
25736 filter : function(property, value){
25739 var ss = this.snapshot;
25740 if(typeof value == "string"){
25741 var vlen = value.length;
25743 this.clearFilter();
25746 value = value.toLowerCase();
25747 for(var i = 0, len = ss.length; i < len; i++){
25749 if(o[property].substr(0, vlen).toLowerCase() == value){
25753 } else if(value.exec){ // regex?
25754 for(var i = 0, len = ss.length; i < len; i++){
25756 if(value.test(o[property])){
25763 this.jsonData = data;
25769 * Filter by a function. The passed function will be called with each
25770 * object in the current dataset. If the function returns true the value is kept,
25771 * otherwise it is filtered.
25772 * @param {Function} fn
25773 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25775 filterBy : function(fn, scope){
25778 var ss = this.snapshot;
25779 for(var i = 0, len = ss.length; i < len; i++){
25781 if(fn.call(scope || this, o)){
25785 this.jsonData = data;
25791 * Clears the current filter.
25793 clearFilter : function(){
25794 if(this.snapshot && this.jsonData != this.snapshot){
25795 this.jsonData = this.snapshot;
25802 * Sorts the data for this view and refreshes it.
25803 * @param {String} property A property on your JSON objects to sort on
25804 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25805 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25807 sort : function(property, dir, sortType){
25808 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25811 var dsc = dir && dir.toLowerCase() == "desc";
25812 var f = function(o1, o2){
25813 var v1 = sortType ? sortType(o1[p]) : o1[p];
25814 var v2 = sortType ? sortType(o2[p]) : o2[p];
25817 return dsc ? +1 : -1;
25818 } else if(v1 > v2){
25819 return dsc ? -1 : +1;
25824 this.jsonData.sort(f);
25826 if(this.jsonData != this.snapshot){
25827 this.snapshot.sort(f);
25833 * Ext JS Library 1.1.1
25834 * Copyright(c) 2006-2007, Ext JS, LLC.
25836 * Originally Released Under LGPL - original licence link has changed is not relivant.
25839 * <script type="text/javascript">
25844 * @class Roo.ColorPalette
25845 * @extends Roo.Component
25846 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25847 * Here's an example of typical usage:
25849 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25850 cp.render('my-div');
25852 cp.on('select', function(palette, selColor){
25853 // do something with selColor
25857 * Create a new ColorPalette
25858 * @param {Object} config The config object
25860 Roo.ColorPalette = function(config){
25861 Roo.ColorPalette.superclass.constructor.call(this, config);
25865 * Fires when a color is selected
25866 * @param {ColorPalette} this
25867 * @param {String} color The 6-digit color hex code (without the # symbol)
25873 this.on("select", this.handler, this.scope, true);
25876 Roo.extend(Roo.ColorPalette, Roo.Component, {
25878 * @cfg {String} itemCls
25879 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25881 itemCls : "x-color-palette",
25883 * @cfg {String} value
25884 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25885 * the hex codes are case-sensitive.
25888 clickEvent:'click',
25890 ctype: "Roo.ColorPalette",
25893 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25895 allowReselect : false,
25898 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25899 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25900 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25901 * of colors with the width setting until the box is symmetrical.</p>
25902 * <p>You can override individual colors if needed:</p>
25904 var cp = new Roo.ColorPalette();
25905 cp.colors[0] = "FF0000"; // change the first box to red
25908 Or you can provide a custom array of your own for complete control:
25910 var cp = new Roo.ColorPalette();
25911 cp.colors = ["000000", "993300", "333300"];
25916 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25917 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25918 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25919 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25920 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25924 onRender : function(container, position){
25925 var t = new Roo.MasterTemplate(
25926 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25928 var c = this.colors;
25929 for(var i = 0, len = c.length; i < len; i++){
25932 var el = document.createElement("div");
25933 el.className = this.itemCls;
25935 container.dom.insertBefore(el, position);
25936 this.el = Roo.get(el);
25937 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25938 if(this.clickEvent != 'click'){
25939 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25944 afterRender : function(){
25945 Roo.ColorPalette.superclass.afterRender.call(this);
25947 var s = this.value;
25954 handleClick : function(e, t){
25955 e.preventDefault();
25956 if(!this.disabled){
25957 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25958 this.select(c.toUpperCase());
25963 * Selects the specified color in the palette (fires the select event)
25964 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25966 select : function(color){
25967 color = color.replace("#", "");
25968 if(color != this.value || this.allowReselect){
25971 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25973 el.child("a.color-"+color).addClass("x-color-palette-sel");
25974 this.value = color;
25975 this.fireEvent("select", this, color);
25980 * Ext JS Library 1.1.1
25981 * Copyright(c) 2006-2007, Ext JS, LLC.
25983 * Originally Released Under LGPL - original licence link has changed is not relivant.
25986 * <script type="text/javascript">
25990 * @class Roo.DatePicker
25991 * @extends Roo.Component
25992 * Simple date picker class.
25994 * Create a new DatePicker
25995 * @param {Object} config The config object
25997 Roo.DatePicker = function(config){
25998 Roo.DatePicker.superclass.constructor.call(this, config);
26000 this.value = config && config.value ?
26001 config.value.clearTime() : new Date().clearTime();
26006 * Fires when a date is selected
26007 * @param {DatePicker} this
26008 * @param {Date} date The selected date
26012 * @event monthchange
26013 * Fires when the displayed month changes
26014 * @param {DatePicker} this
26015 * @param {Date} date The selected month
26017 'monthchange': true
26021 this.on("select", this.handler, this.scope || this);
26023 // build the disabledDatesRE
26024 if(!this.disabledDatesRE && this.disabledDates){
26025 var dd = this.disabledDates;
26027 for(var i = 0; i < dd.length; i++){
26029 if(i != dd.length-1) re += "|";
26031 this.disabledDatesRE = new RegExp(re + ")");
26035 Roo.extend(Roo.DatePicker, Roo.Component, {
26037 * @cfg {String} todayText
26038 * The text to display on the button that selects the current date (defaults to "Today")
26040 todayText : "Today",
26042 * @cfg {String} okText
26043 * The text to display on the ok button
26045 okText : " OK ", //   to give the user extra clicking room
26047 * @cfg {String} cancelText
26048 * The text to display on the cancel button
26050 cancelText : "Cancel",
26052 * @cfg {String} todayTip
26053 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26055 todayTip : "{0} (Spacebar)",
26057 * @cfg {Date} minDate
26058 * Minimum allowable date (JavaScript date object, defaults to null)
26062 * @cfg {Date} maxDate
26063 * Maximum allowable date (JavaScript date object, defaults to null)
26067 * @cfg {String} minText
26068 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26070 minText : "This date is before the minimum date",
26072 * @cfg {String} maxText
26073 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26075 maxText : "This date is after the maximum date",
26077 * @cfg {String} format
26078 * The default date format string which can be overriden for localization support. The format must be
26079 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26083 * @cfg {Array} disabledDays
26084 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26086 disabledDays : null,
26088 * @cfg {String} disabledDaysText
26089 * The tooltip to display when the date falls on a disabled day (defaults to "")
26091 disabledDaysText : "",
26093 * @cfg {RegExp} disabledDatesRE
26094 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26096 disabledDatesRE : null,
26098 * @cfg {String} disabledDatesText
26099 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26101 disabledDatesText : "",
26103 * @cfg {Boolean} constrainToViewport
26104 * True to constrain the date picker to the viewport (defaults to true)
26106 constrainToViewport : true,
26108 * @cfg {Array} monthNames
26109 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26111 monthNames : Date.monthNames,
26113 * @cfg {Array} dayNames
26114 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26116 dayNames : Date.dayNames,
26118 * @cfg {String} nextText
26119 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26121 nextText: 'Next Month (Control+Right)',
26123 * @cfg {String} prevText
26124 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26126 prevText: 'Previous Month (Control+Left)',
26128 * @cfg {String} monthYearText
26129 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26131 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26133 * @cfg {Number} startDay
26134 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26138 * @cfg {Bool} showClear
26139 * Show a clear button (usefull for date form elements that can be blank.)
26145 * Sets the value of the date field
26146 * @param {Date} value The date to set
26148 setValue : function(value){
26149 var old = this.value;
26151 if (typeof(value) == 'string') {
26153 value = Date.parseDate(value, this.format);
26156 value = new Date();
26159 this.value = value.clearTime(true);
26161 this.update(this.value);
26166 * Gets the current selected value of the date field
26167 * @return {Date} The selected date
26169 getValue : function(){
26174 focus : function(){
26176 this.update(this.activeDate);
26181 onRender : function(container, position){
26184 '<table cellspacing="0">',
26185 '<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>',
26186 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26187 var dn = this.dayNames;
26188 for(var i = 0; i < 7; i++){
26189 var d = this.startDay+i;
26193 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26195 m[m.length] = "</tr></thead><tbody><tr>";
26196 for(var i = 0; i < 42; i++) {
26197 if(i % 7 == 0 && i != 0){
26198 m[m.length] = "</tr><tr>";
26200 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26202 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26203 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26205 var el = document.createElement("div");
26206 el.className = "x-date-picker";
26207 el.innerHTML = m.join("");
26209 container.dom.insertBefore(el, position);
26211 this.el = Roo.get(el);
26212 this.eventEl = Roo.get(el.firstChild);
26214 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26215 handler: this.showPrevMonth,
26217 preventDefault:true,
26221 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26222 handler: this.showNextMonth,
26224 preventDefault:true,
26228 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26230 this.monthPicker = this.el.down('div.x-date-mp');
26231 this.monthPicker.enableDisplayMode('block');
26233 var kn = new Roo.KeyNav(this.eventEl, {
26234 "left" : function(e){
26236 this.showPrevMonth() :
26237 this.update(this.activeDate.add("d", -1));
26240 "right" : function(e){
26242 this.showNextMonth() :
26243 this.update(this.activeDate.add("d", 1));
26246 "up" : function(e){
26248 this.showNextYear() :
26249 this.update(this.activeDate.add("d", -7));
26252 "down" : function(e){
26254 this.showPrevYear() :
26255 this.update(this.activeDate.add("d", 7));
26258 "pageUp" : function(e){
26259 this.showNextMonth();
26262 "pageDown" : function(e){
26263 this.showPrevMonth();
26266 "enter" : function(e){
26267 e.stopPropagation();
26274 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26276 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26278 this.el.unselectable();
26280 this.cells = this.el.select("table.x-date-inner tbody td");
26281 this.textNodes = this.el.query("table.x-date-inner tbody span");
26283 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26285 tooltip: this.monthYearText
26288 this.mbtn.on('click', this.showMonthPicker, this);
26289 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26292 var today = (new Date()).dateFormat(this.format);
26294 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26295 if (this.showClear) {
26296 baseTb.add( new Roo.Toolbar.Fill());
26299 text: String.format(this.todayText, today),
26300 tooltip: String.format(this.todayTip, today),
26301 handler: this.selectToday,
26305 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26308 if (this.showClear) {
26310 baseTb.add( new Roo.Toolbar.Fill());
26313 cls: 'x-btn-icon x-btn-clear',
26314 handler: function() {
26316 this.fireEvent("select", this, '');
26326 this.update(this.value);
26329 createMonthPicker : function(){
26330 if(!this.monthPicker.dom.firstChild){
26331 var buf = ['<table border="0" cellspacing="0">'];
26332 for(var i = 0; i < 6; i++){
26334 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26335 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26337 '<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>' :
26338 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26342 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26344 '</button><button type="button" class="x-date-mp-cancel">',
26346 '</button></td></tr>',
26349 this.monthPicker.update(buf.join(''));
26350 this.monthPicker.on('click', this.onMonthClick, this);
26351 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26353 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26354 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26356 this.mpMonths.each(function(m, a, i){
26359 m.dom.xmonth = 5 + Math.round(i * .5);
26361 m.dom.xmonth = Math.round((i-1) * .5);
26367 showMonthPicker : function(){
26368 this.createMonthPicker();
26369 var size = this.el.getSize();
26370 this.monthPicker.setSize(size);
26371 this.monthPicker.child('table').setSize(size);
26373 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26374 this.updateMPMonth(this.mpSelMonth);
26375 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26376 this.updateMPYear(this.mpSelYear);
26378 this.monthPicker.slideIn('t', {duration:.2});
26381 updateMPYear : function(y){
26383 var ys = this.mpYears.elements;
26384 for(var i = 1; i <= 10; i++){
26385 var td = ys[i-1], y2;
26387 y2 = y + Math.round(i * .5);
26388 td.firstChild.innerHTML = y2;
26391 y2 = y - (5-Math.round(i * .5));
26392 td.firstChild.innerHTML = y2;
26395 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26399 updateMPMonth : function(sm){
26400 this.mpMonths.each(function(m, a, i){
26401 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26405 selectMPMonth: function(m){
26409 onMonthClick : function(e, t){
26411 var el = new Roo.Element(t), pn;
26412 if(el.is('button.x-date-mp-cancel')){
26413 this.hideMonthPicker();
26415 else if(el.is('button.x-date-mp-ok')){
26416 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26417 this.hideMonthPicker();
26419 else if(pn = el.up('td.x-date-mp-month', 2)){
26420 this.mpMonths.removeClass('x-date-mp-sel');
26421 pn.addClass('x-date-mp-sel');
26422 this.mpSelMonth = pn.dom.xmonth;
26424 else if(pn = el.up('td.x-date-mp-year', 2)){
26425 this.mpYears.removeClass('x-date-mp-sel');
26426 pn.addClass('x-date-mp-sel');
26427 this.mpSelYear = pn.dom.xyear;
26429 else if(el.is('a.x-date-mp-prev')){
26430 this.updateMPYear(this.mpyear-10);
26432 else if(el.is('a.x-date-mp-next')){
26433 this.updateMPYear(this.mpyear+10);
26437 onMonthDblClick : function(e, t){
26439 var el = new Roo.Element(t), pn;
26440 if(pn = el.up('td.x-date-mp-month', 2)){
26441 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26442 this.hideMonthPicker();
26444 else if(pn = el.up('td.x-date-mp-year', 2)){
26445 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26446 this.hideMonthPicker();
26450 hideMonthPicker : function(disableAnim){
26451 if(this.monthPicker){
26452 if(disableAnim === true){
26453 this.monthPicker.hide();
26455 this.monthPicker.slideOut('t', {duration:.2});
26461 showPrevMonth : function(e){
26462 this.update(this.activeDate.add("mo", -1));
26466 showNextMonth : function(e){
26467 this.update(this.activeDate.add("mo", 1));
26471 showPrevYear : function(){
26472 this.update(this.activeDate.add("y", -1));
26476 showNextYear : function(){
26477 this.update(this.activeDate.add("y", 1));
26481 handleMouseWheel : function(e){
26482 var delta = e.getWheelDelta();
26484 this.showPrevMonth();
26486 } else if(delta < 0){
26487 this.showNextMonth();
26493 handleDateClick : function(e, t){
26495 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26496 this.setValue(new Date(t.dateValue));
26497 this.fireEvent("select", this, this.value);
26502 selectToday : function(){
26503 this.setValue(new Date().clearTime());
26504 this.fireEvent("select", this, this.value);
26508 update : function(date)
26510 var vd = this.activeDate;
26511 this.activeDate = date;
26513 var t = date.getTime();
26514 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26515 this.cells.removeClass("x-date-selected");
26516 this.cells.each(function(c){
26517 if(c.dom.firstChild.dateValue == t){
26518 c.addClass("x-date-selected");
26519 setTimeout(function(){
26520 try{c.dom.firstChild.focus();}catch(e){}
26529 var days = date.getDaysInMonth();
26530 var firstOfMonth = date.getFirstDateOfMonth();
26531 var startingPos = firstOfMonth.getDay()-this.startDay;
26533 if(startingPos <= this.startDay){
26537 var pm = date.add("mo", -1);
26538 var prevStart = pm.getDaysInMonth()-startingPos;
26540 var cells = this.cells.elements;
26541 var textEls = this.textNodes;
26542 days += startingPos;
26544 // convert everything to numbers so it's fast
26545 var day = 86400000;
26546 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26547 var today = new Date().clearTime().getTime();
26548 var sel = date.clearTime().getTime();
26549 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26550 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26551 var ddMatch = this.disabledDatesRE;
26552 var ddText = this.disabledDatesText;
26553 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26554 var ddaysText = this.disabledDaysText;
26555 var format = this.format;
26557 var setCellClass = function(cal, cell){
26559 var t = d.getTime();
26560 cell.firstChild.dateValue = t;
26562 cell.className += " x-date-today";
26563 cell.title = cal.todayText;
26566 cell.className += " x-date-selected";
26567 setTimeout(function(){
26568 try{cell.firstChild.focus();}catch(e){}
26573 cell.className = " x-date-disabled";
26574 cell.title = cal.minText;
26578 cell.className = " x-date-disabled";
26579 cell.title = cal.maxText;
26583 if(ddays.indexOf(d.getDay()) != -1){
26584 cell.title = ddaysText;
26585 cell.className = " x-date-disabled";
26588 if(ddMatch && format){
26589 var fvalue = d.dateFormat(format);
26590 if(ddMatch.test(fvalue)){
26591 cell.title = ddText.replace("%0", fvalue);
26592 cell.className = " x-date-disabled";
26598 for(; i < startingPos; i++) {
26599 textEls[i].innerHTML = (++prevStart);
26600 d.setDate(d.getDate()+1);
26601 cells[i].className = "x-date-prevday";
26602 setCellClass(this, cells[i]);
26604 for(; i < days; i++){
26605 intDay = i - startingPos + 1;
26606 textEls[i].innerHTML = (intDay);
26607 d.setDate(d.getDate()+1);
26608 cells[i].className = "x-date-active";
26609 setCellClass(this, cells[i]);
26612 for(; i < 42; i++) {
26613 textEls[i].innerHTML = (++extraDays);
26614 d.setDate(d.getDate()+1);
26615 cells[i].className = "x-date-nextday";
26616 setCellClass(this, cells[i]);
26619 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26620 this.fireEvent('monthchange', this, date);
26622 if(!this.internalRender){
26623 var main = this.el.dom.firstChild;
26624 var w = main.offsetWidth;
26625 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26626 Roo.fly(main).setWidth(w);
26627 this.internalRender = true;
26628 // opera does not respect the auto grow header center column
26629 // then, after it gets a width opera refuses to recalculate
26630 // without a second pass
26631 if(Roo.isOpera && !this.secondPass){
26632 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26633 this.secondPass = true;
26634 this.update.defer(10, this, [date]);
26642 * Ext JS Library 1.1.1
26643 * Copyright(c) 2006-2007, Ext JS, LLC.
26645 * Originally Released Under LGPL - original licence link has changed is not relivant.
26648 * <script type="text/javascript">
26651 * @class Roo.TabPanel
26652 * @extends Roo.util.Observable
26653 * A lightweight tab container.
26657 // basic tabs 1, built from existing content
26658 var tabs = new Roo.TabPanel("tabs1");
26659 tabs.addTab("script", "View Script");
26660 tabs.addTab("markup", "View Markup");
26661 tabs.activate("script");
26663 // more advanced tabs, built from javascript
26664 var jtabs = new Roo.TabPanel("jtabs");
26665 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26667 // set up the UpdateManager
26668 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26669 var updater = tab2.getUpdateManager();
26670 updater.setDefaultUrl("ajax1.htm");
26671 tab2.on('activate', updater.refresh, updater, true);
26673 // Use setUrl for Ajax loading
26674 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26675 tab3.setUrl("ajax2.htm", null, true);
26678 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26681 jtabs.activate("jtabs-1");
26684 * Create a new TabPanel.
26685 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26686 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26688 Roo.TabPanel = function(container, config){
26690 * The container element for this TabPanel.
26691 * @type Roo.Element
26693 this.el = Roo.get(container, true);
26695 if(typeof config == "boolean"){
26696 this.tabPosition = config ? "bottom" : "top";
26698 Roo.apply(this, config);
26701 if(this.tabPosition == "bottom"){
26702 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26703 this.el.addClass("x-tabs-bottom");
26705 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26706 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26707 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26709 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26711 if(this.tabPosition != "bottom"){
26712 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26713 * @type Roo.Element
26715 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26716 this.el.addClass("x-tabs-top");
26720 this.bodyEl.setStyle("position", "relative");
26722 this.active = null;
26723 this.activateDelegate = this.activate.createDelegate(this);
26728 * Fires when the active tab changes
26729 * @param {Roo.TabPanel} this
26730 * @param {Roo.TabPanelItem} activePanel The new active tab
26734 * @event beforetabchange
26735 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26736 * @param {Roo.TabPanel} this
26737 * @param {Object} e Set cancel to true on this object to cancel the tab change
26738 * @param {Roo.TabPanelItem} tab The tab being changed to
26740 "beforetabchange" : true
26743 Roo.EventManager.onWindowResize(this.onResize, this);
26744 this.cpad = this.el.getPadding("lr");
26745 this.hiddenCount = 0;
26748 // toolbar on the tabbar support...
26749 if (this.toolbar) {
26750 var tcfg = this.toolbar;
26751 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26752 this.toolbar = new Roo.Toolbar(tcfg);
26753 if (Roo.isSafari) {
26754 var tbl = tcfg.container.child('table', true);
26755 tbl.setAttribute('width', '100%');
26762 Roo.TabPanel.superclass.constructor.call(this);
26765 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26767 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26769 tabPosition : "top",
26771 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26773 currentTabWidth : 0,
26775 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26779 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26783 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26785 preferredTabWidth : 175,
26787 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26789 resizeTabs : false,
26791 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26793 monitorResize : true,
26795 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26800 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26801 * @param {String} id The id of the div to use <b>or create</b>
26802 * @param {String} text The text for the tab
26803 * @param {String} content (optional) Content to put in the TabPanelItem body
26804 * @param {Boolean} closable (optional) True to create a close icon on the tab
26805 * @return {Roo.TabPanelItem} The created TabPanelItem
26807 addTab : function(id, text, content, closable){
26808 var item = new Roo.TabPanelItem(this, id, text, closable);
26809 this.addTabItem(item);
26811 item.setContent(content);
26817 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26818 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26819 * @return {Roo.TabPanelItem}
26821 getTab : function(id){
26822 return this.items[id];
26826 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26827 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26829 hideTab : function(id){
26830 var t = this.items[id];
26833 this.hiddenCount++;
26834 this.autoSizeTabs();
26839 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26840 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26842 unhideTab : function(id){
26843 var t = this.items[id];
26845 t.setHidden(false);
26846 this.hiddenCount--;
26847 this.autoSizeTabs();
26852 * Adds an existing {@link Roo.TabPanelItem}.
26853 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26855 addTabItem : function(item){
26856 this.items[item.id] = item;
26857 this.items.push(item);
26858 if(this.resizeTabs){
26859 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26860 this.autoSizeTabs();
26867 * Removes a {@link Roo.TabPanelItem}.
26868 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26870 removeTab : function(id){
26871 var items = this.items;
26872 var tab = items[id];
26873 if(!tab) { return; }
26874 var index = items.indexOf(tab);
26875 if(this.active == tab && items.length > 1){
26876 var newTab = this.getNextAvailable(index);
26881 this.stripEl.dom.removeChild(tab.pnode.dom);
26882 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26883 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26885 items.splice(index, 1);
26886 delete this.items[tab.id];
26887 tab.fireEvent("close", tab);
26888 tab.purgeListeners();
26889 this.autoSizeTabs();
26892 getNextAvailable : function(start){
26893 var items = this.items;
26895 // look for a next tab that will slide over to
26896 // replace the one being removed
26897 while(index < items.length){
26898 var item = items[++index];
26899 if(item && !item.isHidden()){
26903 // if one isn't found select the previous tab (on the left)
26906 var item = items[--index];
26907 if(item && !item.isHidden()){
26915 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26916 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26918 disableTab : function(id){
26919 var tab = this.items[id];
26920 if(tab && this.active != tab){
26926 * Enables a {@link Roo.TabPanelItem} that is disabled.
26927 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26929 enableTab : function(id){
26930 var tab = this.items[id];
26935 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26936 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26937 * @return {Roo.TabPanelItem} The TabPanelItem.
26939 activate : function(id){
26940 var tab = this.items[id];
26944 if(tab == this.active || tab.disabled){
26948 this.fireEvent("beforetabchange", this, e, tab);
26949 if(e.cancel !== true && !tab.disabled){
26951 this.active.hide();
26953 this.active = this.items[id];
26954 this.active.show();
26955 this.fireEvent("tabchange", this, this.active);
26961 * Gets the active {@link Roo.TabPanelItem}.
26962 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26964 getActiveTab : function(){
26965 return this.active;
26969 * Updates the tab body element to fit the height of the container element
26970 * for overflow scrolling
26971 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26973 syncHeight : function(targetHeight){
26974 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26975 var bm = this.bodyEl.getMargins();
26976 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26977 this.bodyEl.setHeight(newHeight);
26981 onResize : function(){
26982 if(this.monitorResize){
26983 this.autoSizeTabs();
26988 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26990 beginUpdate : function(){
26991 this.updating = true;
26995 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26997 endUpdate : function(){
26998 this.updating = false;
26999 this.autoSizeTabs();
27003 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27005 autoSizeTabs : function(){
27006 var count = this.items.length;
27007 var vcount = count - this.hiddenCount;
27008 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27009 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27010 var availWidth = Math.floor(w / vcount);
27011 var b = this.stripBody;
27012 if(b.getWidth() > w){
27013 var tabs = this.items;
27014 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27015 if(availWidth < this.minTabWidth){
27016 /*if(!this.sleft){ // incomplete scrolling code
27017 this.createScrollButtons();
27020 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27023 if(this.currentTabWidth < this.preferredTabWidth){
27024 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27030 * Returns the number of tabs in this TabPanel.
27033 getCount : function(){
27034 return this.items.length;
27038 * Resizes all the tabs to the passed width
27039 * @param {Number} The new width
27041 setTabWidth : function(width){
27042 this.currentTabWidth = width;
27043 for(var i = 0, len = this.items.length; i < len; i++) {
27044 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27049 * Destroys this TabPanel
27050 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27052 destroy : function(removeEl){
27053 Roo.EventManager.removeResizeListener(this.onResize, this);
27054 for(var i = 0, len = this.items.length; i < len; i++){
27055 this.items[i].purgeListeners();
27057 if(removeEl === true){
27058 this.el.update("");
27065 * @class Roo.TabPanelItem
27066 * @extends Roo.util.Observable
27067 * Represents an individual item (tab plus body) in a TabPanel.
27068 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27069 * @param {String} id The id of this TabPanelItem
27070 * @param {String} text The text for the tab of this TabPanelItem
27071 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27073 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27075 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27076 * @type Roo.TabPanel
27078 this.tabPanel = tabPanel;
27080 * The id for this TabPanelItem
27085 this.disabled = false;
27089 this.loaded = false;
27090 this.closable = closable;
27093 * The body element for this TabPanelItem.
27094 * @type Roo.Element
27096 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27097 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27098 this.bodyEl.setStyle("display", "block");
27099 this.bodyEl.setStyle("zoom", "1");
27102 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27104 this.el = Roo.get(els.el, true);
27105 this.inner = Roo.get(els.inner, true);
27106 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27107 this.pnode = Roo.get(els.el.parentNode, true);
27108 this.el.on("mousedown", this.onTabMouseDown, this);
27109 this.el.on("click", this.onTabClick, this);
27112 var c = Roo.get(els.close, true);
27113 c.dom.title = this.closeText;
27114 c.addClassOnOver("close-over");
27115 c.on("click", this.closeClick, this);
27121 * Fires when this tab becomes the active tab.
27122 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27123 * @param {Roo.TabPanelItem} this
27127 * @event beforeclose
27128 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27129 * @param {Roo.TabPanelItem} this
27130 * @param {Object} e Set cancel to true on this object to cancel the close.
27132 "beforeclose": true,
27135 * Fires when this tab is closed.
27136 * @param {Roo.TabPanelItem} this
27140 * @event deactivate
27141 * Fires when this tab is no longer the active tab.
27142 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27143 * @param {Roo.TabPanelItem} this
27145 "deactivate" : true
27147 this.hidden = false;
27149 Roo.TabPanelItem.superclass.constructor.call(this);
27152 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27153 purgeListeners : function(){
27154 Roo.util.Observable.prototype.purgeListeners.call(this);
27155 this.el.removeAllListeners();
27158 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27161 this.pnode.addClass("on");
27164 this.tabPanel.stripWrap.repaint();
27166 this.fireEvent("activate", this.tabPanel, this);
27170 * Returns true if this tab is the active tab.
27171 * @return {Boolean}
27173 isActive : function(){
27174 return this.tabPanel.getActiveTab() == this;
27178 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27181 this.pnode.removeClass("on");
27183 this.fireEvent("deactivate", this.tabPanel, this);
27186 hideAction : function(){
27187 this.bodyEl.hide();
27188 this.bodyEl.setStyle("position", "absolute");
27189 this.bodyEl.setLeft("-20000px");
27190 this.bodyEl.setTop("-20000px");
27193 showAction : function(){
27194 this.bodyEl.setStyle("position", "relative");
27195 this.bodyEl.setTop("");
27196 this.bodyEl.setLeft("");
27197 this.bodyEl.show();
27201 * Set the tooltip for the tab.
27202 * @param {String} tooltip The tab's tooltip
27204 setTooltip : function(text){
27205 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27206 this.textEl.dom.qtip = text;
27207 this.textEl.dom.removeAttribute('title');
27209 this.textEl.dom.title = text;
27213 onTabClick : function(e){
27214 e.preventDefault();
27215 this.tabPanel.activate(this.id);
27218 onTabMouseDown : function(e){
27219 e.preventDefault();
27220 this.tabPanel.activate(this.id);
27223 getWidth : function(){
27224 return this.inner.getWidth();
27227 setWidth : function(width){
27228 var iwidth = width - this.pnode.getPadding("lr");
27229 this.inner.setWidth(iwidth);
27230 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27231 this.pnode.setWidth(width);
27235 * Show or hide the tab
27236 * @param {Boolean} hidden True to hide or false to show.
27238 setHidden : function(hidden){
27239 this.hidden = hidden;
27240 this.pnode.setStyle("display", hidden ? "none" : "");
27244 * Returns true if this tab is "hidden"
27245 * @return {Boolean}
27247 isHidden : function(){
27248 return this.hidden;
27252 * Returns the text for this tab
27255 getText : function(){
27259 autoSize : function(){
27260 //this.el.beginMeasure();
27261 this.textEl.setWidth(1);
27263 * #2804 [new] Tabs in Roojs
27264 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27266 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27267 //this.el.endMeasure();
27271 * Sets the text for the tab (Note: this also sets the tooltip text)
27272 * @param {String} text The tab's text and tooltip
27274 setText : function(text){
27276 this.textEl.update(text);
27277 this.setTooltip(text);
27278 if(!this.tabPanel.resizeTabs){
27283 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27285 activate : function(){
27286 this.tabPanel.activate(this.id);
27290 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27292 disable : function(){
27293 if(this.tabPanel.active != this){
27294 this.disabled = true;
27295 this.pnode.addClass("disabled");
27300 * Enables this TabPanelItem if it was previously disabled.
27302 enable : function(){
27303 this.disabled = false;
27304 this.pnode.removeClass("disabled");
27308 * Sets the content for this TabPanelItem.
27309 * @param {String} content The content
27310 * @param {Boolean} loadScripts true to look for and load scripts
27312 setContent : function(content, loadScripts){
27313 this.bodyEl.update(content, loadScripts);
27317 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27318 * @return {Roo.UpdateManager} The UpdateManager
27320 getUpdateManager : function(){
27321 return this.bodyEl.getUpdateManager();
27325 * Set a URL to be used to load the content for this TabPanelItem.
27326 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27327 * @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)
27328 * @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)
27329 * @return {Roo.UpdateManager} The UpdateManager
27331 setUrl : function(url, params, loadOnce){
27332 if(this.refreshDelegate){
27333 this.un('activate', this.refreshDelegate);
27335 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27336 this.on("activate", this.refreshDelegate);
27337 return this.bodyEl.getUpdateManager();
27341 _handleRefresh : function(url, params, loadOnce){
27342 if(!loadOnce || !this.loaded){
27343 var updater = this.bodyEl.getUpdateManager();
27344 updater.update(url, params, this._setLoaded.createDelegate(this));
27349 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27350 * Will fail silently if the setUrl method has not been called.
27351 * This does not activate the panel, just updates its content.
27353 refresh : function(){
27354 if(this.refreshDelegate){
27355 this.loaded = false;
27356 this.refreshDelegate();
27361 _setLoaded : function(){
27362 this.loaded = true;
27366 closeClick : function(e){
27369 this.fireEvent("beforeclose", this, o);
27370 if(o.cancel !== true){
27371 this.tabPanel.removeTab(this.id);
27375 * The text displayed in the tooltip for the close icon.
27378 closeText : "Close this tab"
27382 Roo.TabPanel.prototype.createStrip = function(container){
27383 var strip = document.createElement("div");
27384 strip.className = "x-tabs-wrap";
27385 container.appendChild(strip);
27389 Roo.TabPanel.prototype.createStripList = function(strip){
27390 // div wrapper for retard IE
27391 // returns the "tr" element.
27392 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27393 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27394 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27395 return strip.firstChild.firstChild.firstChild.firstChild;
27398 Roo.TabPanel.prototype.createBody = function(container){
27399 var body = document.createElement("div");
27400 Roo.id(body, "tab-body");
27401 Roo.fly(body).addClass("x-tabs-body");
27402 container.appendChild(body);
27406 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27407 var body = Roo.getDom(id);
27409 body = document.createElement("div");
27412 Roo.fly(body).addClass("x-tabs-item-body");
27413 bodyEl.insertBefore(body, bodyEl.firstChild);
27417 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27418 var td = document.createElement("td");
27419 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27420 //stripEl.appendChild(td);
27422 td.className = "x-tabs-closable";
27423 if(!this.closeTpl){
27424 this.closeTpl = new Roo.Template(
27425 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27426 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27427 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27430 var el = this.closeTpl.overwrite(td, {"text": text});
27431 var close = el.getElementsByTagName("div")[0];
27432 var inner = el.getElementsByTagName("em")[0];
27433 return {"el": el, "close": close, "inner": inner};
27436 this.tabTpl = new Roo.Template(
27437 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27438 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27441 var el = this.tabTpl.overwrite(td, {"text": text});
27442 var inner = el.getElementsByTagName("em")[0];
27443 return {"el": el, "inner": inner};
27447 * Ext JS Library 1.1.1
27448 * Copyright(c) 2006-2007, Ext JS, LLC.
27450 * Originally Released Under LGPL - original licence link has changed is not relivant.
27453 * <script type="text/javascript">
27457 * @class Roo.Button
27458 * @extends Roo.util.Observable
27459 * Simple Button class
27460 * @cfg {String} text The button text
27461 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27462 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27463 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27464 * @cfg {Object} scope The scope of the handler
27465 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27466 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27467 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27468 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27469 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27470 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27471 applies if enableToggle = true)
27472 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27473 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27474 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27476 * Create a new button
27477 * @param {Object} config The config object
27479 Roo.Button = function(renderTo, config)
27483 renderTo = config.renderTo || false;
27486 Roo.apply(this, config);
27490 * Fires when this button is clicked
27491 * @param {Button} this
27492 * @param {EventObject} e The click event
27497 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27498 * @param {Button} this
27499 * @param {Boolean} pressed
27504 * Fires when the mouse hovers over the button
27505 * @param {Button} this
27506 * @param {Event} e The event object
27508 'mouseover' : true,
27511 * Fires when the mouse exits the button
27512 * @param {Button} this
27513 * @param {Event} e The event object
27518 * Fires when the button is rendered
27519 * @param {Button} this
27524 this.menu = Roo.menu.MenuMgr.get(this.menu);
27526 // register listeners first!! - so render can be captured..
27527 Roo.util.Observable.call(this);
27529 this.render(renderTo);
27535 Roo.extend(Roo.Button, Roo.util.Observable, {
27541 * Read-only. True if this button is hidden
27546 * Read-only. True if this button is disabled
27551 * Read-only. True if this button is pressed (only if enableToggle = true)
27557 * @cfg {Number} tabIndex
27558 * The DOM tabIndex for this button (defaults to undefined)
27560 tabIndex : undefined,
27563 * @cfg {Boolean} enableToggle
27564 * True to enable pressed/not pressed toggling (defaults to false)
27566 enableToggle: false,
27568 * @cfg {Mixed} menu
27569 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27573 * @cfg {String} menuAlign
27574 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27576 menuAlign : "tl-bl?",
27579 * @cfg {String} iconCls
27580 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27582 iconCls : undefined,
27584 * @cfg {String} type
27585 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27590 menuClassTarget: 'tr',
27593 * @cfg {String} clickEvent
27594 * The type of event to map to the button's event handler (defaults to 'click')
27596 clickEvent : 'click',
27599 * @cfg {Boolean} handleMouseEvents
27600 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27602 handleMouseEvents : true,
27605 * @cfg {String} tooltipType
27606 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27608 tooltipType : 'qtip',
27611 * @cfg {String} cls
27612 * A CSS class to apply to the button's main element.
27616 * @cfg {Roo.Template} template (Optional)
27617 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27618 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27619 * require code modifications if required elements (e.g. a button) aren't present.
27623 render : function(renderTo){
27625 if(this.hideParent){
27626 this.parentEl = Roo.get(renderTo);
27628 if(!this.dhconfig){
27629 if(!this.template){
27630 if(!Roo.Button.buttonTemplate){
27631 // hideous table template
27632 Roo.Button.buttonTemplate = new Roo.Template(
27633 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27634 '<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>',
27635 "</tr></tbody></table>");
27637 this.template = Roo.Button.buttonTemplate;
27639 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27640 var btnEl = btn.child("button:first");
27641 btnEl.on('focus', this.onFocus, this);
27642 btnEl.on('blur', this.onBlur, this);
27644 btn.addClass(this.cls);
27647 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27650 btnEl.addClass(this.iconCls);
27652 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27655 if(this.tabIndex !== undefined){
27656 btnEl.dom.tabIndex = this.tabIndex;
27659 if(typeof this.tooltip == 'object'){
27660 Roo.QuickTips.tips(Roo.apply({
27664 btnEl.dom[this.tooltipType] = this.tooltip;
27668 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27672 this.el.dom.id = this.el.id = this.id;
27675 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27676 this.menu.on("show", this.onMenuShow, this);
27677 this.menu.on("hide", this.onMenuHide, this);
27679 btn.addClass("x-btn");
27680 if(Roo.isIE && !Roo.isIE7){
27681 this.autoWidth.defer(1, this);
27685 if(this.handleMouseEvents){
27686 btn.on("mouseover", this.onMouseOver, this);
27687 btn.on("mouseout", this.onMouseOut, this);
27688 btn.on("mousedown", this.onMouseDown, this);
27690 btn.on(this.clickEvent, this.onClick, this);
27691 //btn.on("mouseup", this.onMouseUp, this);
27698 Roo.ButtonToggleMgr.register(this);
27700 this.el.addClass("x-btn-pressed");
27703 var repeater = new Roo.util.ClickRepeater(btn,
27704 typeof this.repeat == "object" ? this.repeat : {}
27706 repeater.on("click", this.onClick, this);
27709 this.fireEvent('render', this);
27713 * Returns the button's underlying element
27714 * @return {Roo.Element} The element
27716 getEl : function(){
27721 * Destroys this Button and removes any listeners.
27723 destroy : function(){
27724 Roo.ButtonToggleMgr.unregister(this);
27725 this.el.removeAllListeners();
27726 this.purgeListeners();
27731 autoWidth : function(){
27733 this.el.setWidth("auto");
27734 if(Roo.isIE7 && Roo.isStrict){
27735 var ib = this.el.child('button');
27736 if(ib && ib.getWidth() > 20){
27738 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27743 this.el.beginMeasure();
27745 if(this.el.getWidth() < this.minWidth){
27746 this.el.setWidth(this.minWidth);
27749 this.el.endMeasure();
27756 * Assigns this button's click handler
27757 * @param {Function} handler The function to call when the button is clicked
27758 * @param {Object} scope (optional) Scope for the function passed in
27760 setHandler : function(handler, scope){
27761 this.handler = handler;
27762 this.scope = scope;
27766 * Sets this button's text
27767 * @param {String} text The button text
27769 setText : function(text){
27772 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27778 * Gets the text for this button
27779 * @return {String} The button text
27781 getText : function(){
27789 this.hidden = false;
27791 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27799 this.hidden = true;
27801 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27806 * Convenience function for boolean show/hide
27807 * @param {Boolean} visible True to show, false to hide
27809 setVisible: function(visible){
27818 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27819 * @param {Boolean} state (optional) Force a particular state
27821 toggle : function(state){
27822 state = state === undefined ? !this.pressed : state;
27823 if(state != this.pressed){
27825 this.el.addClass("x-btn-pressed");
27826 this.pressed = true;
27827 this.fireEvent("toggle", this, true);
27829 this.el.removeClass("x-btn-pressed");
27830 this.pressed = false;
27831 this.fireEvent("toggle", this, false);
27833 if(this.toggleHandler){
27834 this.toggleHandler.call(this.scope || this, this, state);
27842 focus : function(){
27843 this.el.child('button:first').focus();
27847 * Disable this button
27849 disable : function(){
27851 this.el.addClass("x-btn-disabled");
27853 this.disabled = true;
27857 * Enable this button
27859 enable : function(){
27861 this.el.removeClass("x-btn-disabled");
27863 this.disabled = false;
27867 * Convenience function for boolean enable/disable
27868 * @param {Boolean} enabled True to enable, false to disable
27870 setDisabled : function(v){
27871 this[v !== true ? "enable" : "disable"]();
27875 onClick : function(e)
27878 e.preventDefault();
27883 if(!this.disabled){
27884 if(this.enableToggle){
27887 if(this.menu && !this.menu.isVisible()){
27888 this.menu.show(this.el, this.menuAlign);
27890 this.fireEvent("click", this, e);
27892 this.el.removeClass("x-btn-over");
27893 this.handler.call(this.scope || this, this, e);
27898 onMouseOver : function(e){
27899 if(!this.disabled){
27900 this.el.addClass("x-btn-over");
27901 this.fireEvent('mouseover', this, e);
27905 onMouseOut : function(e){
27906 if(!e.within(this.el, true)){
27907 this.el.removeClass("x-btn-over");
27908 this.fireEvent('mouseout', this, e);
27912 onFocus : function(e){
27913 if(!this.disabled){
27914 this.el.addClass("x-btn-focus");
27918 onBlur : function(e){
27919 this.el.removeClass("x-btn-focus");
27922 onMouseDown : function(e){
27923 if(!this.disabled && e.button == 0){
27924 this.el.addClass("x-btn-click");
27925 Roo.get(document).on('mouseup', this.onMouseUp, this);
27929 onMouseUp : function(e){
27931 this.el.removeClass("x-btn-click");
27932 Roo.get(document).un('mouseup', this.onMouseUp, this);
27936 onMenuShow : function(e){
27937 this.el.addClass("x-btn-menu-active");
27940 onMenuHide : function(e){
27941 this.el.removeClass("x-btn-menu-active");
27945 // Private utility class used by Button
27946 Roo.ButtonToggleMgr = function(){
27949 function toggleGroup(btn, state){
27951 var g = groups[btn.toggleGroup];
27952 for(var i = 0, l = g.length; i < l; i++){
27954 g[i].toggle(false);
27961 register : function(btn){
27962 if(!btn.toggleGroup){
27965 var g = groups[btn.toggleGroup];
27967 g = groups[btn.toggleGroup] = [];
27970 btn.on("toggle", toggleGroup);
27973 unregister : function(btn){
27974 if(!btn.toggleGroup){
27977 var g = groups[btn.toggleGroup];
27980 btn.un("toggle", toggleGroup);
27986 * Ext JS Library 1.1.1
27987 * Copyright(c) 2006-2007, Ext JS, LLC.
27989 * Originally Released Under LGPL - original licence link has changed is not relivant.
27992 * <script type="text/javascript">
27996 * @class Roo.SplitButton
27997 * @extends Roo.Button
27998 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27999 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28000 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28001 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28002 * @cfg {String} arrowTooltip The title attribute of the arrow
28004 * Create a new menu button
28005 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28006 * @param {Object} config The config object
28008 Roo.SplitButton = function(renderTo, config){
28009 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28011 * @event arrowclick
28012 * Fires when this button's arrow is clicked
28013 * @param {SplitButton} this
28014 * @param {EventObject} e The click event
28016 this.addEvents({"arrowclick":true});
28019 Roo.extend(Roo.SplitButton, Roo.Button, {
28020 render : function(renderTo){
28021 // this is one sweet looking template!
28022 var tpl = new Roo.Template(
28023 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28024 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28025 '<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>',
28026 "</tbody></table></td><td>",
28027 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28028 '<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>',
28029 "</tbody></table></td></tr></table>"
28031 var btn = tpl.append(renderTo, [this.text, this.type], true);
28032 var btnEl = btn.child("button");
28034 btn.addClass(this.cls);
28037 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28040 btnEl.addClass(this.iconCls);
28042 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28046 if(this.handleMouseEvents){
28047 btn.on("mouseover", this.onMouseOver, this);
28048 btn.on("mouseout", this.onMouseOut, this);
28049 btn.on("mousedown", this.onMouseDown, this);
28050 btn.on("mouseup", this.onMouseUp, this);
28052 btn.on(this.clickEvent, this.onClick, this);
28054 if(typeof this.tooltip == 'object'){
28055 Roo.QuickTips.tips(Roo.apply({
28059 btnEl.dom[this.tooltipType] = this.tooltip;
28062 if(this.arrowTooltip){
28063 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28072 this.el.addClass("x-btn-pressed");
28074 if(Roo.isIE && !Roo.isIE7){
28075 this.autoWidth.defer(1, this);
28080 this.menu.on("show", this.onMenuShow, this);
28081 this.menu.on("hide", this.onMenuHide, this);
28083 this.fireEvent('render', this);
28087 autoWidth : function(){
28089 var tbl = this.el.child("table:first");
28090 var tbl2 = this.el.child("table:last");
28091 this.el.setWidth("auto");
28092 tbl.setWidth("auto");
28093 if(Roo.isIE7 && Roo.isStrict){
28094 var ib = this.el.child('button:first');
28095 if(ib && ib.getWidth() > 20){
28097 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28102 this.el.beginMeasure();
28104 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28105 tbl.setWidth(this.minWidth-tbl2.getWidth());
28108 this.el.endMeasure();
28111 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28115 * Sets this button's click handler
28116 * @param {Function} handler The function to call when the button is clicked
28117 * @param {Object} scope (optional) Scope for the function passed above
28119 setHandler : function(handler, scope){
28120 this.handler = handler;
28121 this.scope = scope;
28125 * Sets this button's arrow click handler
28126 * @param {Function} handler The function to call when the arrow is clicked
28127 * @param {Object} scope (optional) Scope for the function passed above
28129 setArrowHandler : function(handler, scope){
28130 this.arrowHandler = handler;
28131 this.scope = scope;
28137 focus : function(){
28139 this.el.child("button:first").focus();
28144 onClick : function(e){
28145 e.preventDefault();
28146 if(!this.disabled){
28147 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28148 if(this.menu && !this.menu.isVisible()){
28149 this.menu.show(this.el, this.menuAlign);
28151 this.fireEvent("arrowclick", this, e);
28152 if(this.arrowHandler){
28153 this.arrowHandler.call(this.scope || this, this, e);
28156 this.fireEvent("click", this, e);
28158 this.handler.call(this.scope || this, this, e);
28164 onMouseDown : function(e){
28165 if(!this.disabled){
28166 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28170 onMouseUp : function(e){
28171 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28176 // backwards compat
28177 Roo.MenuButton = Roo.SplitButton;/*
28179 * Ext JS Library 1.1.1
28180 * Copyright(c) 2006-2007, Ext JS, LLC.
28182 * Originally Released Under LGPL - original licence link has changed is not relivant.
28185 * <script type="text/javascript">
28189 * @class Roo.Toolbar
28190 * Basic Toolbar class.
28192 * Creates a new Toolbar
28193 * @param {Object} container The config object
28195 Roo.Toolbar = function(container, buttons, config)
28197 /// old consturctor format still supported..
28198 if(container instanceof Array){ // omit the container for later rendering
28199 buttons = container;
28203 if (typeof(container) == 'object' && container.xtype) {
28204 config = container;
28205 container = config.container;
28206 buttons = config.buttons || []; // not really - use items!!
28209 if (config && config.items) {
28210 xitems = config.items;
28211 delete config.items;
28213 Roo.apply(this, config);
28214 this.buttons = buttons;
28217 this.render(container);
28219 this.xitems = xitems;
28220 Roo.each(xitems, function(b) {
28226 Roo.Toolbar.prototype = {
28228 * @cfg {Array} items
28229 * array of button configs or elements to add (will be converted to a MixedCollection)
28233 * @cfg {String/HTMLElement/Element} container
28234 * The id or element that will contain the toolbar
28237 render : function(ct){
28238 this.el = Roo.get(ct);
28240 this.el.addClass(this.cls);
28242 // using a table allows for vertical alignment
28243 // 100% width is needed by Safari...
28244 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28245 this.tr = this.el.child("tr", true);
28247 this.items = new Roo.util.MixedCollection(false, function(o){
28248 return o.id || ("item" + (++autoId));
28251 this.add.apply(this, this.buttons);
28252 delete this.buttons;
28257 * Adds element(s) to the toolbar -- this function takes a variable number of
28258 * arguments of mixed type and adds them to the toolbar.
28259 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28261 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28262 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28263 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28264 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28265 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28266 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28267 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28268 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28269 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28271 * @param {Mixed} arg2
28272 * @param {Mixed} etc.
28275 var a = arguments, l = a.length;
28276 for(var i = 0; i < l; i++){
28281 _add : function(el) {
28284 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28287 if (el.applyTo){ // some kind of form field
28288 return this.addField(el);
28290 if (el.render){ // some kind of Toolbar.Item
28291 return this.addItem(el);
28293 if (typeof el == "string"){ // string
28294 if(el == "separator" || el == "-"){
28295 return this.addSeparator();
28298 return this.addSpacer();
28301 return this.addFill();
28303 return this.addText(el);
28306 if(el.tagName){ // element
28307 return this.addElement(el);
28309 if(typeof el == "object"){ // must be button config?
28310 return this.addButton(el);
28312 // and now what?!?!
28318 * Add an Xtype element
28319 * @param {Object} xtype Xtype Object
28320 * @return {Object} created Object
28322 addxtype : function(e){
28323 return this.add(e);
28327 * Returns the Element for this toolbar.
28328 * @return {Roo.Element}
28330 getEl : function(){
28336 * @return {Roo.Toolbar.Item} The separator item
28338 addSeparator : function(){
28339 return this.addItem(new Roo.Toolbar.Separator());
28343 * Adds a spacer element
28344 * @return {Roo.Toolbar.Spacer} The spacer item
28346 addSpacer : function(){
28347 return this.addItem(new Roo.Toolbar.Spacer());
28351 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28352 * @return {Roo.Toolbar.Fill} The fill item
28354 addFill : function(){
28355 return this.addItem(new Roo.Toolbar.Fill());
28359 * Adds any standard HTML element to the toolbar
28360 * @param {String/HTMLElement/Element} el The element or id of the element to add
28361 * @return {Roo.Toolbar.Item} The element's item
28363 addElement : function(el){
28364 return this.addItem(new Roo.Toolbar.Item(el));
28367 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28368 * @type Roo.util.MixedCollection
28373 * Adds any Toolbar.Item or subclass
28374 * @param {Roo.Toolbar.Item} item
28375 * @return {Roo.Toolbar.Item} The item
28377 addItem : function(item){
28378 var td = this.nextBlock();
28380 this.items.add(item);
28385 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28386 * @param {Object/Array} config A button config or array of configs
28387 * @return {Roo.Toolbar.Button/Array}
28389 addButton : function(config){
28390 if(config instanceof Array){
28392 for(var i = 0, len = config.length; i < len; i++) {
28393 buttons.push(this.addButton(config[i]));
28398 if(!(config instanceof Roo.Toolbar.Button)){
28400 new Roo.Toolbar.SplitButton(config) :
28401 new Roo.Toolbar.Button(config);
28403 var td = this.nextBlock();
28410 * Adds text to the toolbar
28411 * @param {String} text The text to add
28412 * @return {Roo.Toolbar.Item} The element's item
28414 addText : function(text){
28415 return this.addItem(new Roo.Toolbar.TextItem(text));
28419 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28420 * @param {Number} index The index where the item is to be inserted
28421 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28422 * @return {Roo.Toolbar.Button/Item}
28424 insertButton : function(index, item){
28425 if(item instanceof Array){
28427 for(var i = 0, len = item.length; i < len; i++) {
28428 buttons.push(this.insertButton(index + i, item[i]));
28432 if (!(item instanceof Roo.Toolbar.Button)){
28433 item = new Roo.Toolbar.Button(item);
28435 var td = document.createElement("td");
28436 this.tr.insertBefore(td, this.tr.childNodes[index]);
28438 this.items.insert(index, item);
28443 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28444 * @param {Object} config
28445 * @return {Roo.Toolbar.Item} The element's item
28447 addDom : function(config, returnEl){
28448 var td = this.nextBlock();
28449 Roo.DomHelper.overwrite(td, config);
28450 var ti = new Roo.Toolbar.Item(td.firstChild);
28452 this.items.add(ti);
28457 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28458 * @type Roo.util.MixedCollection
28463 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28464 * Note: the field should not have been rendered yet. For a field that has already been
28465 * rendered, use {@link #addElement}.
28466 * @param {Roo.form.Field} field
28467 * @return {Roo.ToolbarItem}
28471 addField : function(field) {
28472 if (!this.fields) {
28474 this.fields = new Roo.util.MixedCollection(false, function(o){
28475 return o.id || ("item" + (++autoId));
28480 var td = this.nextBlock();
28482 var ti = new Roo.Toolbar.Item(td.firstChild);
28484 this.items.add(ti);
28485 this.fields.add(field);
28496 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28497 this.el.child('div').hide();
28505 this.el.child('div').show();
28509 nextBlock : function(){
28510 var td = document.createElement("td");
28511 this.tr.appendChild(td);
28516 destroy : function(){
28517 if(this.items){ // rendered?
28518 Roo.destroy.apply(Roo, this.items.items);
28520 if(this.fields){ // rendered?
28521 Roo.destroy.apply(Roo, this.fields.items);
28523 Roo.Element.uncache(this.el, this.tr);
28528 * @class Roo.Toolbar.Item
28529 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28531 * Creates a new Item
28532 * @param {HTMLElement} el
28534 Roo.Toolbar.Item = function(el){
28536 if (typeof (el.xtype) != 'undefined') {
28541 this.el = Roo.getDom(el);
28542 this.id = Roo.id(this.el);
28543 this.hidden = false;
28548 * Fires when the button is rendered
28549 * @param {Button} this
28553 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28555 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28556 //Roo.Toolbar.Item.prototype = {
28559 * Get this item's HTML Element
28560 * @return {HTMLElement}
28562 getEl : function(){
28567 render : function(td){
28570 td.appendChild(this.el);
28572 this.fireEvent('render', this);
28576 * Removes and destroys this item.
28578 destroy : function(){
28579 this.td.parentNode.removeChild(this.td);
28586 this.hidden = false;
28587 this.td.style.display = "";
28594 this.hidden = true;
28595 this.td.style.display = "none";
28599 * Convenience function for boolean show/hide.
28600 * @param {Boolean} visible true to show/false to hide
28602 setVisible: function(visible){
28611 * Try to focus this item.
28613 focus : function(){
28614 Roo.fly(this.el).focus();
28618 * Disables this item.
28620 disable : function(){
28621 Roo.fly(this.td).addClass("x-item-disabled");
28622 this.disabled = true;
28623 this.el.disabled = true;
28627 * Enables this item.
28629 enable : function(){
28630 Roo.fly(this.td).removeClass("x-item-disabled");
28631 this.disabled = false;
28632 this.el.disabled = false;
28638 * @class Roo.Toolbar.Separator
28639 * @extends Roo.Toolbar.Item
28640 * A simple toolbar separator class
28642 * Creates a new Separator
28644 Roo.Toolbar.Separator = function(cfg){
28646 var s = document.createElement("span");
28647 s.className = "ytb-sep";
28652 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28654 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28655 enable:Roo.emptyFn,
28656 disable:Roo.emptyFn,
28661 * @class Roo.Toolbar.Spacer
28662 * @extends Roo.Toolbar.Item
28663 * A simple element that adds extra horizontal space to a toolbar.
28665 * Creates a new Spacer
28667 Roo.Toolbar.Spacer = function(cfg){
28668 var s = document.createElement("div");
28669 s.className = "ytb-spacer";
28673 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28675 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28676 enable:Roo.emptyFn,
28677 disable:Roo.emptyFn,
28682 * @class Roo.Toolbar.Fill
28683 * @extends Roo.Toolbar.Spacer
28684 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28686 * Creates a new Spacer
28688 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28690 render : function(td){
28691 td.style.width = '100%';
28692 Roo.Toolbar.Fill.superclass.render.call(this, td);
28697 * @class Roo.Toolbar.TextItem
28698 * @extends Roo.Toolbar.Item
28699 * A simple class that renders text directly into a toolbar.
28701 * Creates a new TextItem
28702 * @param {String} text
28704 Roo.Toolbar.TextItem = function(cfg){
28705 var text = cfg || "";
28706 if (typeof(cfg) == 'object') {
28707 text = cfg.text || "";
28711 var s = document.createElement("span");
28712 s.className = "ytb-text";
28713 s.innerHTML = text;
28718 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28720 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28723 enable:Roo.emptyFn,
28724 disable:Roo.emptyFn,
28729 * @class Roo.Toolbar.Button
28730 * @extends Roo.Button
28731 * A button that renders into a toolbar.
28733 * Creates a new Button
28734 * @param {Object} config A standard {@link Roo.Button} config object
28736 Roo.Toolbar.Button = function(config){
28737 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28739 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28740 render : function(td){
28742 Roo.Toolbar.Button.superclass.render.call(this, td);
28746 * Removes and destroys this button
28748 destroy : function(){
28749 Roo.Toolbar.Button.superclass.destroy.call(this);
28750 this.td.parentNode.removeChild(this.td);
28754 * Shows this button
28757 this.hidden = false;
28758 this.td.style.display = "";
28762 * Hides this button
28765 this.hidden = true;
28766 this.td.style.display = "none";
28770 * Disables this item
28772 disable : function(){
28773 Roo.fly(this.td).addClass("x-item-disabled");
28774 this.disabled = true;
28778 * Enables this item
28780 enable : function(){
28781 Roo.fly(this.td).removeClass("x-item-disabled");
28782 this.disabled = false;
28785 // backwards compat
28786 Roo.ToolbarButton = Roo.Toolbar.Button;
28789 * @class Roo.Toolbar.SplitButton
28790 * @extends Roo.SplitButton
28791 * A menu button that renders into a toolbar.
28793 * Creates a new SplitButton
28794 * @param {Object} config A standard {@link Roo.SplitButton} config object
28796 Roo.Toolbar.SplitButton = function(config){
28797 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28799 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28800 render : function(td){
28802 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28806 * Removes and destroys this button
28808 destroy : function(){
28809 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28810 this.td.parentNode.removeChild(this.td);
28814 * Shows this button
28817 this.hidden = false;
28818 this.td.style.display = "";
28822 * Hides this button
28825 this.hidden = true;
28826 this.td.style.display = "none";
28830 // backwards compat
28831 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28833 * Ext JS Library 1.1.1
28834 * Copyright(c) 2006-2007, Ext JS, LLC.
28836 * Originally Released Under LGPL - original licence link has changed is not relivant.
28839 * <script type="text/javascript">
28843 * @class Roo.PagingToolbar
28844 * @extends Roo.Toolbar
28845 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28847 * Create a new PagingToolbar
28848 * @param {Object} config The config object
28850 Roo.PagingToolbar = function(el, ds, config)
28852 // old args format still supported... - xtype is prefered..
28853 if (typeof(el) == 'object' && el.xtype) {
28854 // created from xtype...
28856 ds = el.dataSource;
28857 el = config.container;
28860 if (config.items) {
28861 items = config.items;
28865 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28868 this.renderButtons(this.el);
28871 // supprot items array.
28873 Roo.each(items, function(e) {
28874 this.add(Roo.factory(e));
28879 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28881 * @cfg {Roo.data.Store} dataSource
28882 * The underlying data store providing the paged data
28885 * @cfg {String/HTMLElement/Element} container
28886 * container The id or element that will contain the toolbar
28889 * @cfg {Boolean} displayInfo
28890 * True to display the displayMsg (defaults to false)
28893 * @cfg {Number} pageSize
28894 * The number of records to display per page (defaults to 20)
28898 * @cfg {String} displayMsg
28899 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28901 displayMsg : 'Displaying {0} - {1} of {2}',
28903 * @cfg {String} emptyMsg
28904 * The message to display when no records are found (defaults to "No data to display")
28906 emptyMsg : 'No data to display',
28908 * Customizable piece of the default paging text (defaults to "Page")
28911 beforePageText : "Page",
28913 * Customizable piece of the default paging text (defaults to "of %0")
28916 afterPageText : "of {0}",
28918 * Customizable piece of the default paging text (defaults to "First Page")
28921 firstText : "First Page",
28923 * Customizable piece of the default paging text (defaults to "Previous Page")
28926 prevText : "Previous Page",
28928 * Customizable piece of the default paging text (defaults to "Next Page")
28931 nextText : "Next Page",
28933 * Customizable piece of the default paging text (defaults to "Last Page")
28936 lastText : "Last Page",
28938 * Customizable piece of the default paging text (defaults to "Refresh")
28941 refreshText : "Refresh",
28944 renderButtons : function(el){
28945 Roo.PagingToolbar.superclass.render.call(this, el);
28946 this.first = this.addButton({
28947 tooltip: this.firstText,
28948 cls: "x-btn-icon x-grid-page-first",
28950 handler: this.onClick.createDelegate(this, ["first"])
28952 this.prev = this.addButton({
28953 tooltip: this.prevText,
28954 cls: "x-btn-icon x-grid-page-prev",
28956 handler: this.onClick.createDelegate(this, ["prev"])
28958 //this.addSeparator();
28959 this.add(this.beforePageText);
28960 this.field = Roo.get(this.addDom({
28965 cls: "x-grid-page-number"
28967 this.field.on("keydown", this.onPagingKeydown, this);
28968 this.field.on("focus", function(){this.dom.select();});
28969 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28970 this.field.setHeight(18);
28971 //this.addSeparator();
28972 this.next = this.addButton({
28973 tooltip: this.nextText,
28974 cls: "x-btn-icon x-grid-page-next",
28976 handler: this.onClick.createDelegate(this, ["next"])
28978 this.last = this.addButton({
28979 tooltip: this.lastText,
28980 cls: "x-btn-icon x-grid-page-last",
28982 handler: this.onClick.createDelegate(this, ["last"])
28984 //this.addSeparator();
28985 this.loading = this.addButton({
28986 tooltip: this.refreshText,
28987 cls: "x-btn-icon x-grid-loading",
28988 handler: this.onClick.createDelegate(this, ["refresh"])
28991 if(this.displayInfo){
28992 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28997 updateInfo : function(){
28998 if(this.displayEl){
28999 var count = this.ds.getCount();
29000 var msg = count == 0 ?
29004 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29006 this.displayEl.update(msg);
29011 onLoad : function(ds, r, o){
29012 this.cursor = o.params ? o.params.start : 0;
29013 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29015 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29016 this.field.dom.value = ap;
29017 this.first.setDisabled(ap == 1);
29018 this.prev.setDisabled(ap == 1);
29019 this.next.setDisabled(ap == ps);
29020 this.last.setDisabled(ap == ps);
29021 this.loading.enable();
29026 getPageData : function(){
29027 var total = this.ds.getTotalCount();
29030 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29031 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29036 onLoadError : function(){
29037 this.loading.enable();
29041 onPagingKeydown : function(e){
29042 var k = e.getKey();
29043 var d = this.getPageData();
29045 var v = this.field.dom.value, pageNum;
29046 if(!v || isNaN(pageNum = parseInt(v, 10))){
29047 this.field.dom.value = d.activePage;
29050 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29051 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29054 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))
29056 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29057 this.field.dom.value = pageNum;
29058 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29061 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29063 var v = this.field.dom.value, pageNum;
29064 var increment = (e.shiftKey) ? 10 : 1;
29065 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29067 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29068 this.field.dom.value = d.activePage;
29071 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29073 this.field.dom.value = parseInt(v, 10) + increment;
29074 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29075 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29082 beforeLoad : function(){
29084 this.loading.disable();
29089 onClick : function(which){
29093 ds.load({params:{start: 0, limit: this.pageSize}});
29096 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29099 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29102 var total = ds.getTotalCount();
29103 var extra = total % this.pageSize;
29104 var lastStart = extra ? (total - extra) : total-this.pageSize;
29105 ds.load({params:{start: lastStart, limit: this.pageSize}});
29108 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29114 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29115 * @param {Roo.data.Store} store The data store to unbind
29117 unbind : function(ds){
29118 ds.un("beforeload", this.beforeLoad, this);
29119 ds.un("load", this.onLoad, this);
29120 ds.un("loadexception", this.onLoadError, this);
29121 ds.un("remove", this.updateInfo, this);
29122 ds.un("add", this.updateInfo, this);
29123 this.ds = undefined;
29127 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29128 * @param {Roo.data.Store} store The data store to bind
29130 bind : function(ds){
29131 ds.on("beforeload", this.beforeLoad, this);
29132 ds.on("load", this.onLoad, this);
29133 ds.on("loadexception", this.onLoadError, this);
29134 ds.on("remove", this.updateInfo, this);
29135 ds.on("add", this.updateInfo, this);
29140 * Ext JS Library 1.1.1
29141 * Copyright(c) 2006-2007, Ext JS, LLC.
29143 * Originally Released Under LGPL - original licence link has changed is not relivant.
29146 * <script type="text/javascript">
29150 * @class Roo.Resizable
29151 * @extends Roo.util.Observable
29152 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29153 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29154 * 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
29155 * the element will be wrapped for you automatically.</p>
29156 * <p>Here is the list of valid resize handles:</p>
29159 ------ -------------------
29168 'hd' horizontal drag
29171 * <p>Here's an example showing the creation of a typical Resizable:</p>
29173 var resizer = new Roo.Resizable("element-id", {
29181 resizer.on("resize", myHandler);
29183 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29184 * resizer.east.setDisplayed(false);</p>
29185 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29186 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29187 * resize operation's new size (defaults to [0, 0])
29188 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29189 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29190 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29191 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29192 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29193 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29194 * @cfg {Number} width The width of the element in pixels (defaults to null)
29195 * @cfg {Number} height The height of the element in pixels (defaults to null)
29196 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29197 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29198 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29199 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29200 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29201 * in favor of the handles config option (defaults to false)
29202 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29203 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29204 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29205 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29206 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29207 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29208 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29209 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29210 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29211 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29212 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29214 * Create a new resizable component
29215 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29216 * @param {Object} config configuration options
29218 Roo.Resizable = function(el, config)
29220 this.el = Roo.get(el);
29222 if(config && config.wrap){
29223 config.resizeChild = this.el;
29224 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29225 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29226 this.el.setStyle("overflow", "hidden");
29227 this.el.setPositioning(config.resizeChild.getPositioning());
29228 config.resizeChild.clearPositioning();
29229 if(!config.width || !config.height){
29230 var csize = config.resizeChild.getSize();
29231 this.el.setSize(csize.width, csize.height);
29233 if(config.pinned && !config.adjustments){
29234 config.adjustments = "auto";
29238 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29239 this.proxy.unselectable();
29240 this.proxy.enableDisplayMode('block');
29242 Roo.apply(this, config);
29245 this.disableTrackOver = true;
29246 this.el.addClass("x-resizable-pinned");
29248 // if the element isn't positioned, make it relative
29249 var position = this.el.getStyle("position");
29250 if(position != "absolute" && position != "fixed"){
29251 this.el.setStyle("position", "relative");
29253 if(!this.handles){ // no handles passed, must be legacy style
29254 this.handles = 's,e,se';
29255 if(this.multiDirectional){
29256 this.handles += ',n,w';
29259 if(this.handles == "all"){
29260 this.handles = "n s e w ne nw se sw";
29262 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29263 var ps = Roo.Resizable.positions;
29264 for(var i = 0, len = hs.length; i < len; i++){
29265 if(hs[i] && ps[hs[i]]){
29266 var pos = ps[hs[i]];
29267 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29271 this.corner = this.southeast;
29273 // updateBox = the box can move..
29274 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29275 this.updateBox = true;
29278 this.activeHandle = null;
29280 if(this.resizeChild){
29281 if(typeof this.resizeChild == "boolean"){
29282 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29284 this.resizeChild = Roo.get(this.resizeChild, true);
29288 if(this.adjustments == "auto"){
29289 var rc = this.resizeChild;
29290 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29291 if(rc && (hw || hn)){
29292 rc.position("relative");
29293 rc.setLeft(hw ? hw.el.getWidth() : 0);
29294 rc.setTop(hn ? hn.el.getHeight() : 0);
29296 this.adjustments = [
29297 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29298 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29302 if(this.draggable){
29303 this.dd = this.dynamic ?
29304 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29305 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29311 * @event beforeresize
29312 * Fired before resize is allowed. Set enabled to false to cancel resize.
29313 * @param {Roo.Resizable} this
29314 * @param {Roo.EventObject} e The mousedown event
29316 "beforeresize" : true,
29319 * Fired a resizing.
29320 * @param {Roo.Resizable} this
29321 * @param {Number} x The new x position
29322 * @param {Number} y The new y position
29323 * @param {Number} w The new w width
29324 * @param {Number} h The new h hight
29325 * @param {Roo.EventObject} e The mouseup event
29330 * Fired after a resize.
29331 * @param {Roo.Resizable} this
29332 * @param {Number} width The new width
29333 * @param {Number} height The new height
29334 * @param {Roo.EventObject} e The mouseup event
29339 if(this.width !== null && this.height !== null){
29340 this.resizeTo(this.width, this.height);
29342 this.updateChildSize();
29345 this.el.dom.style.zoom = 1;
29347 Roo.Resizable.superclass.constructor.call(this);
29350 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29351 resizeChild : false,
29352 adjustments : [0, 0],
29362 multiDirectional : false,
29363 disableTrackOver : false,
29364 easing : 'easeOutStrong',
29365 widthIncrement : 0,
29366 heightIncrement : 0,
29370 preserveRatio : false,
29371 transparent: false,
29377 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29379 constrainTo: undefined,
29381 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29383 resizeRegion: undefined,
29387 * Perform a manual resize
29388 * @param {Number} width
29389 * @param {Number} height
29391 resizeTo : function(width, height){
29392 this.el.setSize(width, height);
29393 this.updateChildSize();
29394 this.fireEvent("resize", this, width, height, null);
29398 startSizing : function(e, handle){
29399 this.fireEvent("beforeresize", this, e);
29400 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29403 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29404 this.overlay.unselectable();
29405 this.overlay.enableDisplayMode("block");
29406 this.overlay.on("mousemove", this.onMouseMove, this);
29407 this.overlay.on("mouseup", this.onMouseUp, this);
29409 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29411 this.resizing = true;
29412 this.startBox = this.el.getBox();
29413 this.startPoint = e.getXY();
29414 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29415 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29417 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29418 this.overlay.show();
29420 if(this.constrainTo) {
29421 var ct = Roo.get(this.constrainTo);
29422 this.resizeRegion = ct.getRegion().adjust(
29423 ct.getFrameWidth('t'),
29424 ct.getFrameWidth('l'),
29425 -ct.getFrameWidth('b'),
29426 -ct.getFrameWidth('r')
29430 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29432 this.proxy.setBox(this.startBox);
29434 this.proxy.setStyle('visibility', 'visible');
29440 onMouseDown : function(handle, e){
29443 this.activeHandle = handle;
29444 this.startSizing(e, handle);
29449 onMouseUp : function(e){
29450 var size = this.resizeElement();
29451 this.resizing = false;
29453 this.overlay.hide();
29455 this.fireEvent("resize", this, size.width, size.height, e);
29459 updateChildSize : function(){
29461 if(this.resizeChild){
29463 var child = this.resizeChild;
29464 var adj = this.adjustments;
29465 if(el.dom.offsetWidth){
29466 var b = el.getSize(true);
29467 child.setSize(b.width+adj[0], b.height+adj[1]);
29469 // Second call here for IE
29470 // The first call enables instant resizing and
29471 // the second call corrects scroll bars if they
29474 setTimeout(function(){
29475 if(el.dom.offsetWidth){
29476 var b = el.getSize(true);
29477 child.setSize(b.width+adj[0], b.height+adj[1]);
29485 snap : function(value, inc, min){
29486 if(!inc || !value) return value;
29487 var newValue = value;
29488 var m = value % inc;
29491 newValue = value + (inc-m);
29493 newValue = value - m;
29496 return Math.max(min, newValue);
29500 resizeElement : function(){
29501 var box = this.proxy.getBox();
29502 if(this.updateBox){
29503 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29505 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29507 this.updateChildSize();
29515 constrain : function(v, diff, m, mx){
29518 }else if(v - diff > mx){
29525 onMouseMove : function(e){
29528 try{// try catch so if something goes wrong the user doesn't get hung
29530 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29534 //var curXY = this.startPoint;
29535 var curSize = this.curSize || this.startBox;
29536 var x = this.startBox.x, y = this.startBox.y;
29537 var ox = x, oy = y;
29538 var w = curSize.width, h = curSize.height;
29539 var ow = w, oh = h;
29540 var mw = this.minWidth, mh = this.minHeight;
29541 var mxw = this.maxWidth, mxh = this.maxHeight;
29542 var wi = this.widthIncrement;
29543 var hi = this.heightIncrement;
29545 var eventXY = e.getXY();
29546 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29547 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29549 var pos = this.activeHandle.position;
29554 w = Math.min(Math.max(mw, w), mxw);
29559 h = Math.min(Math.max(mh, h), mxh);
29564 w = Math.min(Math.max(mw, w), mxw);
29565 h = Math.min(Math.max(mh, h), mxh);
29568 diffY = this.constrain(h, diffY, mh, mxh);
29575 var adiffX = Math.abs(diffX);
29576 var sub = (adiffX % wi); // how much
29577 if (sub > (wi/2)) { // far enough to snap
29578 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29580 // remove difference..
29581 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29585 x = Math.max(this.minX, x);
29588 diffX = this.constrain(w, diffX, mw, mxw);
29594 w = Math.min(Math.max(mw, w), mxw);
29595 diffY = this.constrain(h, diffY, mh, mxh);
29600 diffX = this.constrain(w, diffX, mw, mxw);
29601 diffY = this.constrain(h, diffY, mh, mxh);
29608 diffX = this.constrain(w, diffX, mw, mxw);
29610 h = Math.min(Math.max(mh, h), mxh);
29616 var sw = this.snap(w, wi, mw);
29617 var sh = this.snap(h, hi, mh);
29618 if(sw != w || sh != h){
29641 if(this.preserveRatio){
29646 h = Math.min(Math.max(mh, h), mxh);
29651 w = Math.min(Math.max(mw, w), mxw);
29656 w = Math.min(Math.max(mw, w), mxw);
29662 w = Math.min(Math.max(mw, w), mxw);
29668 h = Math.min(Math.max(mh, h), mxh);
29676 h = Math.min(Math.max(mh, h), mxh);
29686 h = Math.min(Math.max(mh, h), mxh);
29694 if (pos == 'hdrag') {
29697 this.proxy.setBounds(x, y, w, h);
29699 this.resizeElement();
29703 this.fireEvent("resizing", this, x, y, w, h, e);
29707 handleOver : function(){
29709 this.el.addClass("x-resizable-over");
29714 handleOut : function(){
29715 if(!this.resizing){
29716 this.el.removeClass("x-resizable-over");
29721 * Returns the element this component is bound to.
29722 * @return {Roo.Element}
29724 getEl : function(){
29729 * Returns the resizeChild element (or null).
29730 * @return {Roo.Element}
29732 getResizeChild : function(){
29733 return this.resizeChild;
29735 groupHandler : function()
29740 * Destroys this resizable. If the element was wrapped and
29741 * removeEl is not true then the element remains.
29742 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29744 destroy : function(removeEl){
29745 this.proxy.remove();
29747 this.overlay.removeAllListeners();
29748 this.overlay.remove();
29750 var ps = Roo.Resizable.positions;
29752 if(typeof ps[k] != "function" && this[ps[k]]){
29753 var h = this[ps[k]];
29754 h.el.removeAllListeners();
29759 this.el.update("");
29766 // hash to map config positions to true positions
29767 Roo.Resizable.positions = {
29768 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29773 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29775 // only initialize the template if resizable is used
29776 var tpl = Roo.DomHelper.createTemplate(
29777 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29780 Roo.Resizable.Handle.prototype.tpl = tpl;
29782 this.position = pos;
29784 // show north drag fro topdra
29785 var handlepos = pos == 'hdrag' ? 'north' : pos;
29787 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29788 if (pos == 'hdrag') {
29789 this.el.setStyle('cursor', 'pointer');
29791 this.el.unselectable();
29793 this.el.setOpacity(0);
29795 this.el.on("mousedown", this.onMouseDown, this);
29796 if(!disableTrackOver){
29797 this.el.on("mouseover", this.onMouseOver, this);
29798 this.el.on("mouseout", this.onMouseOut, this);
29803 Roo.Resizable.Handle.prototype = {
29804 afterResize : function(rz){
29809 onMouseDown : function(e){
29810 this.rz.onMouseDown(this, e);
29813 onMouseOver : function(e){
29814 this.rz.handleOver(this, e);
29817 onMouseOut : function(e){
29818 this.rz.handleOut(this, e);
29822 * Ext JS Library 1.1.1
29823 * Copyright(c) 2006-2007, Ext JS, LLC.
29825 * Originally Released Under LGPL - original licence link has changed is not relivant.
29828 * <script type="text/javascript">
29832 * @class Roo.Editor
29833 * @extends Roo.Component
29834 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29836 * Create a new Editor
29837 * @param {Roo.form.Field} field The Field object (or descendant)
29838 * @param {Object} config The config object
29840 Roo.Editor = function(field, config){
29841 Roo.Editor.superclass.constructor.call(this, config);
29842 this.field = field;
29845 * @event beforestartedit
29846 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29847 * false from the handler of this event.
29848 * @param {Editor} this
29849 * @param {Roo.Element} boundEl The underlying element bound to this editor
29850 * @param {Mixed} value The field value being set
29852 "beforestartedit" : true,
29855 * Fires when this editor is displayed
29856 * @param {Roo.Element} boundEl The underlying element bound to this editor
29857 * @param {Mixed} value The starting field value
29859 "startedit" : true,
29861 * @event beforecomplete
29862 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29863 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29864 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29865 * event will not fire since no edit actually occurred.
29866 * @param {Editor} this
29867 * @param {Mixed} value The current field value
29868 * @param {Mixed} startValue The original field value
29870 "beforecomplete" : true,
29873 * Fires after editing is complete and any changed value has been written to the underlying field.
29874 * @param {Editor} this
29875 * @param {Mixed} value The current field value
29876 * @param {Mixed} startValue The original field value
29880 * @event specialkey
29881 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29882 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29883 * @param {Roo.form.Field} this
29884 * @param {Roo.EventObject} e The event object
29886 "specialkey" : true
29890 Roo.extend(Roo.Editor, Roo.Component, {
29892 * @cfg {Boolean/String} autosize
29893 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29894 * or "height" to adopt the height only (defaults to false)
29897 * @cfg {Boolean} revertInvalid
29898 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29899 * validation fails (defaults to true)
29902 * @cfg {Boolean} ignoreNoChange
29903 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29904 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29905 * will never be ignored.
29908 * @cfg {Boolean} hideEl
29909 * False to keep the bound element visible while the editor is displayed (defaults to true)
29912 * @cfg {Mixed} value
29913 * The data value of the underlying field (defaults to "")
29917 * @cfg {String} alignment
29918 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29922 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29923 * for bottom-right shadow (defaults to "frame")
29927 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29931 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29933 completeOnEnter : false,
29935 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29937 cancelOnEsc : false,
29939 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29944 onRender : function(ct, position){
29945 this.el = new Roo.Layer({
29946 shadow: this.shadow,
29952 constrain: this.constrain
29954 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29955 if(this.field.msgTarget != 'title'){
29956 this.field.msgTarget = 'qtip';
29958 this.field.render(this.el);
29960 this.field.el.dom.setAttribute('autocomplete', 'off');
29962 this.field.on("specialkey", this.onSpecialKey, this);
29963 if(this.swallowKeys){
29964 this.field.el.swallowEvent(['keydown','keypress']);
29967 this.field.on("blur", this.onBlur, this);
29968 if(this.field.grow){
29969 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29973 onSpecialKey : function(field, e)
29975 //Roo.log('editor onSpecialKey');
29976 if(this.completeOnEnter && e.getKey() == e.ENTER){
29978 this.completeEdit();
29981 // do not fire special key otherwise it might hide close the editor...
29982 if(e.getKey() == e.ENTER){
29985 if(this.cancelOnEsc && e.getKey() == e.ESC){
29989 this.fireEvent('specialkey', field, e);
29994 * Starts the editing process and shows the editor.
29995 * @param {String/HTMLElement/Element} el The element to edit
29996 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29997 * to the innerHTML of el.
29999 startEdit : function(el, value){
30001 this.completeEdit();
30003 this.boundEl = Roo.get(el);
30004 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30005 if(!this.rendered){
30006 this.render(this.parentEl || document.body);
30008 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30011 this.startValue = v;
30012 this.field.setValue(v);
30014 var sz = this.boundEl.getSize();
30015 switch(this.autoSize){
30017 this.setSize(sz.width, "");
30020 this.setSize("", sz.height);
30023 this.setSize(sz.width, sz.height);
30026 this.el.alignTo(this.boundEl, this.alignment);
30027 this.editing = true;
30029 Roo.QuickTips.disable();
30035 * Sets the height and width of this editor.
30036 * @param {Number} width The new width
30037 * @param {Number} height The new height
30039 setSize : function(w, h){
30040 this.field.setSize(w, h);
30047 * Realigns the editor to the bound field based on the current alignment config value.
30049 realign : function(){
30050 this.el.alignTo(this.boundEl, this.alignment);
30054 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30055 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30057 completeEdit : function(remainVisible){
30061 var v = this.getValue();
30062 if(this.revertInvalid !== false && !this.field.isValid()){
30063 v = this.startValue;
30064 this.cancelEdit(true);
30066 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30067 this.editing = false;
30071 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30072 this.editing = false;
30073 if(this.updateEl && this.boundEl){
30074 this.boundEl.update(v);
30076 if(remainVisible !== true){
30079 this.fireEvent("complete", this, v, this.startValue);
30084 onShow : function(){
30086 if(this.hideEl !== false){
30087 this.boundEl.hide();
30090 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30091 this.fixIEFocus = true;
30092 this.deferredFocus.defer(50, this);
30094 this.field.focus();
30096 this.fireEvent("startedit", this.boundEl, this.startValue);
30099 deferredFocus : function(){
30101 this.field.focus();
30106 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30107 * reverted to the original starting value.
30108 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30109 * cancel (defaults to false)
30111 cancelEdit : function(remainVisible){
30113 this.setValue(this.startValue);
30114 if(remainVisible !== true){
30121 onBlur : function(){
30122 if(this.allowBlur !== true && this.editing){
30123 this.completeEdit();
30128 onHide : function(){
30130 this.completeEdit();
30134 if(this.field.collapse){
30135 this.field.collapse();
30138 if(this.hideEl !== false){
30139 this.boundEl.show();
30142 Roo.QuickTips.enable();
30147 * Sets the data value of the editor
30148 * @param {Mixed} value Any valid value supported by the underlying field
30150 setValue : function(v){
30151 this.field.setValue(v);
30155 * Gets the data value of the editor
30156 * @return {Mixed} The data value
30158 getValue : function(){
30159 return this.field.getValue();
30163 * Ext JS Library 1.1.1
30164 * Copyright(c) 2006-2007, Ext JS, LLC.
30166 * Originally Released Under LGPL - original licence link has changed is not relivant.
30169 * <script type="text/javascript">
30173 * @class Roo.BasicDialog
30174 * @extends Roo.util.Observable
30175 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30177 var dlg = new Roo.BasicDialog("my-dlg", {
30186 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30187 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30188 dlg.addButton('Cancel', dlg.hide, dlg);
30191 <b>A Dialog should always be a direct child of the body element.</b>
30192 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30193 * @cfg {String} title Default text to display in the title bar (defaults to null)
30194 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30195 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30196 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30197 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30198 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30199 * (defaults to null with no animation)
30200 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30201 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30202 * property for valid values (defaults to 'all')
30203 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30204 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30205 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30206 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30207 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30208 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30209 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30210 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30211 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30212 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30213 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30214 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30215 * draggable = true (defaults to false)
30216 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30217 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30218 * shadow (defaults to false)
30219 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30220 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30221 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30222 * @cfg {Array} buttons Array of buttons
30223 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30225 * Create a new BasicDialog.
30226 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30227 * @param {Object} config Configuration options
30229 Roo.BasicDialog = function(el, config){
30230 this.el = Roo.get(el);
30231 var dh = Roo.DomHelper;
30232 if(!this.el && config && config.autoCreate){
30233 if(typeof config.autoCreate == "object"){
30234 if(!config.autoCreate.id){
30235 config.autoCreate.id = el;
30237 this.el = dh.append(document.body,
30238 config.autoCreate, true);
30240 this.el = dh.append(document.body,
30241 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30245 el.setDisplayed(true);
30246 el.hide = this.hideAction;
30248 el.addClass("x-dlg");
30250 Roo.apply(this, config);
30252 this.proxy = el.createProxy("x-dlg-proxy");
30253 this.proxy.hide = this.hideAction;
30254 this.proxy.setOpacity(.5);
30258 el.setWidth(config.width);
30261 el.setHeight(config.height);
30263 this.size = el.getSize();
30264 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30265 this.xy = [config.x,config.y];
30267 this.xy = el.getCenterXY(true);
30269 /** The header element @type Roo.Element */
30270 this.header = el.child("> .x-dlg-hd");
30271 /** The body element @type Roo.Element */
30272 this.body = el.child("> .x-dlg-bd");
30273 /** The footer element @type Roo.Element */
30274 this.footer = el.child("> .x-dlg-ft");
30277 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30280 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30283 this.header.unselectable();
30285 this.header.update(this.title);
30287 // this element allows the dialog to be focused for keyboard event
30288 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30289 this.focusEl.swallowEvent("click", true);
30291 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30293 // wrap the body and footer for special rendering
30294 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30296 this.bwrap.dom.appendChild(this.footer.dom);
30299 this.bg = this.el.createChild({
30300 tag: "div", cls:"x-dlg-bg",
30301 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30303 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30306 if(this.autoScroll !== false && !this.autoTabs){
30307 this.body.setStyle("overflow", "auto");
30310 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30312 if(this.closable !== false){
30313 this.el.addClass("x-dlg-closable");
30314 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30315 this.close.on("click", this.closeClick, this);
30316 this.close.addClassOnOver("x-dlg-close-over");
30318 if(this.collapsible !== false){
30319 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30320 this.collapseBtn.on("click", this.collapseClick, this);
30321 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30322 this.header.on("dblclick", this.collapseClick, this);
30324 if(this.resizable !== false){
30325 this.el.addClass("x-dlg-resizable");
30326 this.resizer = new Roo.Resizable(el, {
30327 minWidth: this.minWidth || 80,
30328 minHeight:this.minHeight || 80,
30329 handles: this.resizeHandles || "all",
30332 this.resizer.on("beforeresize", this.beforeResize, this);
30333 this.resizer.on("resize", this.onResize, this);
30335 if(this.draggable !== false){
30336 el.addClass("x-dlg-draggable");
30337 if (!this.proxyDrag) {
30338 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30341 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30343 dd.setHandleElId(this.header.id);
30344 dd.endDrag = this.endMove.createDelegate(this);
30345 dd.startDrag = this.startMove.createDelegate(this);
30346 dd.onDrag = this.onDrag.createDelegate(this);
30351 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30352 this.mask.enableDisplayMode("block");
30354 this.el.addClass("x-dlg-modal");
30357 this.shadow = new Roo.Shadow({
30358 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30359 offset : this.shadowOffset
30362 this.shadowOffset = 0;
30364 if(Roo.useShims && this.shim !== false){
30365 this.shim = this.el.createShim();
30366 this.shim.hide = this.hideAction;
30374 if (this.buttons) {
30375 var bts= this.buttons;
30377 Roo.each(bts, function(b) {
30386 * Fires when a key is pressed
30387 * @param {Roo.BasicDialog} this
30388 * @param {Roo.EventObject} e
30393 * Fires when this dialog is moved by the user.
30394 * @param {Roo.BasicDialog} this
30395 * @param {Number} x The new page X
30396 * @param {Number} y The new page Y
30401 * Fires when this dialog is resized by the user.
30402 * @param {Roo.BasicDialog} this
30403 * @param {Number} width The new width
30404 * @param {Number} height The new height
30408 * @event beforehide
30409 * Fires before this dialog is hidden.
30410 * @param {Roo.BasicDialog} this
30412 "beforehide" : true,
30415 * Fires when this dialog is hidden.
30416 * @param {Roo.BasicDialog} this
30420 * @event beforeshow
30421 * Fires before this dialog is shown.
30422 * @param {Roo.BasicDialog} this
30424 "beforeshow" : true,
30427 * Fires when this dialog is shown.
30428 * @param {Roo.BasicDialog} this
30432 el.on("keydown", this.onKeyDown, this);
30433 el.on("mousedown", this.toFront, this);
30434 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30436 Roo.DialogManager.register(this);
30437 Roo.BasicDialog.superclass.constructor.call(this);
30440 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30441 shadowOffset: Roo.isIE ? 6 : 5,
30444 minButtonWidth: 75,
30445 defaultButton: null,
30446 buttonAlign: "right",
30451 * Sets the dialog title text
30452 * @param {String} text The title text to display
30453 * @return {Roo.BasicDialog} this
30455 setTitle : function(text){
30456 this.header.update(text);
30461 closeClick : function(){
30466 collapseClick : function(){
30467 this[this.collapsed ? "expand" : "collapse"]();
30471 * Collapses the dialog to its minimized state (only the title bar is visible).
30472 * Equivalent to the user clicking the collapse dialog button.
30474 collapse : function(){
30475 if(!this.collapsed){
30476 this.collapsed = true;
30477 this.el.addClass("x-dlg-collapsed");
30478 this.restoreHeight = this.el.getHeight();
30479 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30484 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30485 * clicking the expand dialog button.
30487 expand : function(){
30488 if(this.collapsed){
30489 this.collapsed = false;
30490 this.el.removeClass("x-dlg-collapsed");
30491 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30496 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30497 * @return {Roo.TabPanel} The tabs component
30499 initTabs : function(){
30500 var tabs = this.getTabs();
30501 while(tabs.getTab(0)){
30504 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30506 tabs.addTab(Roo.id(dom), dom.title);
30514 beforeResize : function(){
30515 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30519 onResize : function(){
30520 this.refreshSize();
30521 this.syncBodyHeight();
30522 this.adjustAssets();
30524 this.fireEvent("resize", this, this.size.width, this.size.height);
30528 onKeyDown : function(e){
30529 if(this.isVisible()){
30530 this.fireEvent("keydown", this, e);
30535 * Resizes the dialog.
30536 * @param {Number} width
30537 * @param {Number} height
30538 * @return {Roo.BasicDialog} this
30540 resizeTo : function(width, height){
30541 this.el.setSize(width, height);
30542 this.size = {width: width, height: height};
30543 this.syncBodyHeight();
30544 if(this.fixedcenter){
30547 if(this.isVisible()){
30548 this.constrainXY();
30549 this.adjustAssets();
30551 this.fireEvent("resize", this, width, height);
30557 * Resizes the dialog to fit the specified content size.
30558 * @param {Number} width
30559 * @param {Number} height
30560 * @return {Roo.BasicDialog} this
30562 setContentSize : function(w, h){
30563 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30564 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30565 //if(!this.el.isBorderBox()){
30566 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30567 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30570 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30571 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30573 this.resizeTo(w, h);
30578 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30579 * executed in response to a particular key being pressed while the dialog is active.
30580 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30581 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30582 * @param {Function} fn The function to call
30583 * @param {Object} scope (optional) The scope of the function
30584 * @return {Roo.BasicDialog} this
30586 addKeyListener : function(key, fn, scope){
30587 var keyCode, shift, ctrl, alt;
30588 if(typeof key == "object" && !(key instanceof Array)){
30589 keyCode = key["key"];
30590 shift = key["shift"];
30591 ctrl = key["ctrl"];
30596 var handler = function(dlg, e){
30597 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30598 var k = e.getKey();
30599 if(keyCode instanceof Array){
30600 for(var i = 0, len = keyCode.length; i < len; i++){
30601 if(keyCode[i] == k){
30602 fn.call(scope || window, dlg, k, e);
30608 fn.call(scope || window, dlg, k, e);
30613 this.on("keydown", handler);
30618 * Returns the TabPanel component (creates it if it doesn't exist).
30619 * Note: If you wish to simply check for the existence of tabs without creating them,
30620 * check for a null 'tabs' property.
30621 * @return {Roo.TabPanel} The tabs component
30623 getTabs : function(){
30625 this.el.addClass("x-dlg-auto-tabs");
30626 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30627 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30633 * Adds a button to the footer section of the dialog.
30634 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30635 * object or a valid Roo.DomHelper element config
30636 * @param {Function} handler The function called when the button is clicked
30637 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30638 * @return {Roo.Button} The new button
30640 addButton : function(config, handler, scope){
30641 var dh = Roo.DomHelper;
30643 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30645 if(!this.btnContainer){
30646 var tb = this.footer.createChild({
30648 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30649 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30651 this.btnContainer = tb.firstChild.firstChild.firstChild;
30656 minWidth: this.minButtonWidth,
30659 if(typeof config == "string"){
30660 bconfig.text = config;
30663 bconfig.dhconfig = config;
30665 Roo.apply(bconfig, config);
30669 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30670 bconfig.position = Math.max(0, bconfig.position);
30671 fc = this.btnContainer.childNodes[bconfig.position];
30674 var btn = new Roo.Button(
30676 this.btnContainer.insertBefore(document.createElement("td"),fc)
30677 : this.btnContainer.appendChild(document.createElement("td")),
30678 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30681 this.syncBodyHeight();
30684 * Array of all the buttons that have been added to this dialog via addButton
30689 this.buttons.push(btn);
30694 * Sets the default button to be focused when the dialog is displayed.
30695 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30696 * @return {Roo.BasicDialog} this
30698 setDefaultButton : function(btn){
30699 this.defaultButton = btn;
30704 getHeaderFooterHeight : function(safe){
30707 height += this.header.getHeight();
30710 var fm = this.footer.getMargins();
30711 height += (this.footer.getHeight()+fm.top+fm.bottom);
30713 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30714 height += this.centerBg.getPadding("tb");
30719 syncBodyHeight : function()
30721 var bd = this.body, // the text
30722 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30724 var height = this.size.height - this.getHeaderFooterHeight(false);
30725 bd.setHeight(height-bd.getMargins("tb"));
30726 var hh = this.header.getHeight();
30727 var h = this.size.height-hh;
30730 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30731 bw.setHeight(h-cb.getPadding("tb"));
30733 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30734 bd.setWidth(bw.getWidth(true));
30736 this.tabs.syncHeight();
30738 this.tabs.el.repaint();
30744 * Restores the previous state of the dialog if Roo.state is configured.
30745 * @return {Roo.BasicDialog} this
30747 restoreState : function(){
30748 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30749 if(box && box.width){
30750 this.xy = [box.x, box.y];
30751 this.resizeTo(box.width, box.height);
30757 beforeShow : function(){
30759 if(this.fixedcenter){
30760 this.xy = this.el.getCenterXY(true);
30763 Roo.get(document.body).addClass("x-body-masked");
30764 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30767 this.constrainXY();
30771 animShow : function(){
30772 var b = Roo.get(this.animateTarget).getBox();
30773 this.proxy.setSize(b.width, b.height);
30774 this.proxy.setLocation(b.x, b.y);
30776 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30777 true, .35, this.showEl.createDelegate(this));
30781 * Shows the dialog.
30782 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30783 * @return {Roo.BasicDialog} this
30785 show : function(animateTarget){
30786 if (this.fireEvent("beforeshow", this) === false){
30789 if(this.syncHeightBeforeShow){
30790 this.syncBodyHeight();
30791 }else if(this.firstShow){
30792 this.firstShow = false;
30793 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30795 this.animateTarget = animateTarget || this.animateTarget;
30796 if(!this.el.isVisible()){
30798 if(this.animateTarget && Roo.get(this.animateTarget)){
30808 showEl : function(){
30810 this.el.setXY(this.xy);
30812 this.adjustAssets(true);
30815 // IE peekaboo bug - fix found by Dave Fenwick
30819 this.fireEvent("show", this);
30823 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30824 * dialog itself will receive focus.
30826 focus : function(){
30827 if(this.defaultButton){
30828 this.defaultButton.focus();
30830 this.focusEl.focus();
30835 constrainXY : function(){
30836 if(this.constraintoviewport !== false){
30837 if(!this.viewSize){
30838 if(this.container){
30839 var s = this.container.getSize();
30840 this.viewSize = [s.width, s.height];
30842 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30845 var s = Roo.get(this.container||document).getScroll();
30847 var x = this.xy[0], y = this.xy[1];
30848 var w = this.size.width, h = this.size.height;
30849 var vw = this.viewSize[0], vh = this.viewSize[1];
30850 // only move it if it needs it
30852 // first validate right/bottom
30853 if(x + w > vw+s.left){
30857 if(y + h > vh+s.top){
30861 // then make sure top/left isn't negative
30873 if(this.isVisible()){
30874 this.el.setLocation(x, y);
30875 this.adjustAssets();
30882 onDrag : function(){
30883 if(!this.proxyDrag){
30884 this.xy = this.el.getXY();
30885 this.adjustAssets();
30890 adjustAssets : function(doShow){
30891 var x = this.xy[0], y = this.xy[1];
30892 var w = this.size.width, h = this.size.height;
30893 if(doShow === true){
30895 this.shadow.show(this.el);
30901 if(this.shadow && this.shadow.isVisible()){
30902 this.shadow.show(this.el);
30904 if(this.shim && this.shim.isVisible()){
30905 this.shim.setBounds(x, y, w, h);
30910 adjustViewport : function(w, h){
30912 w = Roo.lib.Dom.getViewWidth();
30913 h = Roo.lib.Dom.getViewHeight();
30916 this.viewSize = [w, h];
30917 if(this.modal && this.mask.isVisible()){
30918 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30919 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30921 if(this.isVisible()){
30922 this.constrainXY();
30927 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30928 * shadow, proxy, mask, etc.) Also removes all event listeners.
30929 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30931 destroy : function(removeEl){
30932 if(this.isVisible()){
30933 this.animateTarget = null;
30936 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30938 this.tabs.destroy(removeEl);
30951 for(var i = 0, len = this.buttons.length; i < len; i++){
30952 this.buttons[i].destroy();
30955 this.el.removeAllListeners();
30956 if(removeEl === true){
30957 this.el.update("");
30960 Roo.DialogManager.unregister(this);
30964 startMove : function(){
30965 if(this.proxyDrag){
30968 if(this.constraintoviewport !== false){
30969 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30974 endMove : function(){
30975 if(!this.proxyDrag){
30976 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30978 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30981 this.refreshSize();
30982 this.adjustAssets();
30984 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30988 * Brings this dialog to the front of any other visible dialogs
30989 * @return {Roo.BasicDialog} this
30991 toFront : function(){
30992 Roo.DialogManager.bringToFront(this);
30997 * Sends this dialog to the back (under) of any other visible dialogs
30998 * @return {Roo.BasicDialog} this
31000 toBack : function(){
31001 Roo.DialogManager.sendToBack(this);
31006 * Centers this dialog in the viewport
31007 * @return {Roo.BasicDialog} this
31009 center : function(){
31010 var xy = this.el.getCenterXY(true);
31011 this.moveTo(xy[0], xy[1]);
31016 * Moves the dialog's top-left corner to the specified point
31017 * @param {Number} x
31018 * @param {Number} y
31019 * @return {Roo.BasicDialog} this
31021 moveTo : function(x, y){
31023 if(this.isVisible()){
31024 this.el.setXY(this.xy);
31025 this.adjustAssets();
31031 * Aligns the dialog to the specified element
31032 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31033 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31034 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31035 * @return {Roo.BasicDialog} this
31037 alignTo : function(element, position, offsets){
31038 this.xy = this.el.getAlignToXY(element, position, offsets);
31039 if(this.isVisible()){
31040 this.el.setXY(this.xy);
31041 this.adjustAssets();
31047 * Anchors an element to another element and realigns it when the window is resized.
31048 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31049 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31050 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31051 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31052 * is a number, it is used as the buffer delay (defaults to 50ms).
31053 * @return {Roo.BasicDialog} this
31055 anchorTo : function(el, alignment, offsets, monitorScroll){
31056 var action = function(){
31057 this.alignTo(el, alignment, offsets);
31059 Roo.EventManager.onWindowResize(action, this);
31060 var tm = typeof monitorScroll;
31061 if(tm != 'undefined'){
31062 Roo.EventManager.on(window, 'scroll', action, this,
31063 {buffer: tm == 'number' ? monitorScroll : 50});
31070 * Returns true if the dialog is visible
31071 * @return {Boolean}
31073 isVisible : function(){
31074 return this.el.isVisible();
31078 animHide : function(callback){
31079 var b = Roo.get(this.animateTarget).getBox();
31081 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31083 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31084 this.hideEl.createDelegate(this, [callback]));
31088 * Hides the dialog.
31089 * @param {Function} callback (optional) Function to call when the dialog is hidden
31090 * @return {Roo.BasicDialog} this
31092 hide : function(callback){
31093 if (this.fireEvent("beforehide", this) === false){
31097 this.shadow.hide();
31102 // sometimes animateTarget seems to get set.. causing problems...
31103 // this just double checks..
31104 if(this.animateTarget && Roo.get(this.animateTarget)) {
31105 this.animHide(callback);
31108 this.hideEl(callback);
31114 hideEl : function(callback){
31118 Roo.get(document.body).removeClass("x-body-masked");
31120 this.fireEvent("hide", this);
31121 if(typeof callback == "function"){
31127 hideAction : function(){
31128 this.setLeft("-10000px");
31129 this.setTop("-10000px");
31130 this.setStyle("visibility", "hidden");
31134 refreshSize : function(){
31135 this.size = this.el.getSize();
31136 this.xy = this.el.getXY();
31137 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31141 // z-index is managed by the DialogManager and may be overwritten at any time
31142 setZIndex : function(index){
31144 this.mask.setStyle("z-index", index);
31147 this.shim.setStyle("z-index", ++index);
31150 this.shadow.setZIndex(++index);
31152 this.el.setStyle("z-index", ++index);
31154 this.proxy.setStyle("z-index", ++index);
31157 this.resizer.proxy.setStyle("z-index", ++index);
31160 this.lastZIndex = index;
31164 * Returns the element for this dialog
31165 * @return {Roo.Element} The underlying dialog Element
31167 getEl : function(){
31173 * @class Roo.DialogManager
31174 * Provides global access to BasicDialogs that have been created and
31175 * support for z-indexing (layering) multiple open dialogs.
31177 Roo.DialogManager = function(){
31179 var accessList = [];
31183 var sortDialogs = function(d1, d2){
31184 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31188 var orderDialogs = function(){
31189 accessList.sort(sortDialogs);
31190 var seed = Roo.DialogManager.zseed;
31191 for(var i = 0, len = accessList.length; i < len; i++){
31192 var dlg = accessList[i];
31194 dlg.setZIndex(seed + (i*10));
31201 * The starting z-index for BasicDialogs (defaults to 9000)
31202 * @type Number The z-index value
31207 register : function(dlg){
31208 list[dlg.id] = dlg;
31209 accessList.push(dlg);
31213 unregister : function(dlg){
31214 delete list[dlg.id];
31217 if(!accessList.indexOf){
31218 for( i = 0, len = accessList.length; i < len; i++){
31219 if(accessList[i] == dlg){
31220 accessList.splice(i, 1);
31225 i = accessList.indexOf(dlg);
31227 accessList.splice(i, 1);
31233 * Gets a registered dialog by id
31234 * @param {String/Object} id The id of the dialog or a dialog
31235 * @return {Roo.BasicDialog} this
31237 get : function(id){
31238 return typeof id == "object" ? id : list[id];
31242 * Brings the specified dialog to the front
31243 * @param {String/Object} dlg The id of the dialog or a dialog
31244 * @return {Roo.BasicDialog} this
31246 bringToFront : function(dlg){
31247 dlg = this.get(dlg);
31250 dlg._lastAccess = new Date().getTime();
31257 * Sends the specified dialog to the back
31258 * @param {String/Object} dlg The id of the dialog or a dialog
31259 * @return {Roo.BasicDialog} this
31261 sendToBack : function(dlg){
31262 dlg = this.get(dlg);
31263 dlg._lastAccess = -(new Date().getTime());
31269 * Hides all dialogs
31271 hideAll : function(){
31272 for(var id in list){
31273 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31282 * @class Roo.LayoutDialog
31283 * @extends Roo.BasicDialog
31284 * Dialog which provides adjustments for working with a layout in a Dialog.
31285 * Add your necessary layout config options to the dialog's config.<br>
31286 * Example usage (including a nested layout):
31289 dialog = new Roo.LayoutDialog("download-dlg", {
31298 // layout config merges with the dialog config
31300 tabPosition: "top",
31301 alwaysShowTabs: true
31304 dialog.addKeyListener(27, dialog.hide, dialog);
31305 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31306 dialog.addButton("Build It!", this.getDownload, this);
31308 // we can even add nested layouts
31309 var innerLayout = new Roo.BorderLayout("dl-inner", {
31319 innerLayout.beginUpdate();
31320 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31321 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31322 innerLayout.endUpdate(true);
31324 var layout = dialog.getLayout();
31325 layout.beginUpdate();
31326 layout.add("center", new Roo.ContentPanel("standard-panel",
31327 {title: "Download the Source", fitToFrame:true}));
31328 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31329 {title: "Build your own roo.js"}));
31330 layout.getRegion("center").showPanel(sp);
31331 layout.endUpdate();
31335 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31336 * @param {Object} config configuration options
31338 Roo.LayoutDialog = function(el, cfg){
31341 if (typeof(cfg) == 'undefined') {
31342 config = Roo.apply({}, el);
31343 // not sure why we use documentElement here.. - it should always be body.
31344 // IE7 borks horribly if we use documentElement.
31345 // webkit also does not like documentElement - it creates a body element...
31346 el = Roo.get( document.body || document.documentElement ).createChild();
31347 //config.autoCreate = true;
31351 config.autoTabs = false;
31352 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31353 this.body.setStyle({overflow:"hidden", position:"relative"});
31354 this.layout = new Roo.BorderLayout(this.body.dom, config);
31355 this.layout.monitorWindowResize = false;
31356 this.el.addClass("x-dlg-auto-layout");
31357 // fix case when center region overwrites center function
31358 this.center = Roo.BasicDialog.prototype.center;
31359 this.on("show", this.layout.layout, this.layout, true);
31360 if (config.items) {
31361 var xitems = config.items;
31362 delete config.items;
31363 Roo.each(xitems, this.addxtype, this);
31368 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31370 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31373 endUpdate : function(){
31374 this.layout.endUpdate();
31378 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31381 beginUpdate : function(){
31382 this.layout.beginUpdate();
31386 * Get the BorderLayout for this dialog
31387 * @return {Roo.BorderLayout}
31389 getLayout : function(){
31390 return this.layout;
31393 showEl : function(){
31394 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31396 this.layout.layout();
31401 // Use the syncHeightBeforeShow config option to control this automatically
31402 syncBodyHeight : function(){
31403 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31404 if(this.layout){this.layout.layout();}
31408 * Add an xtype element (actually adds to the layout.)
31409 * @return {Object} xdata xtype object data.
31412 addxtype : function(c) {
31413 return this.layout.addxtype(c);
31417 * Ext JS Library 1.1.1
31418 * Copyright(c) 2006-2007, Ext JS, LLC.
31420 * Originally Released Under LGPL - original licence link has changed is not relivant.
31423 * <script type="text/javascript">
31427 * @class Roo.MessageBox
31428 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31432 Roo.Msg.alert('Status', 'Changes saved successfully.');
31434 // Prompt for user data:
31435 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31437 // process text value...
31441 // Show a dialog using config options:
31443 title:'Save Changes?',
31444 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31445 buttons: Roo.Msg.YESNOCANCEL,
31452 Roo.MessageBox = function(){
31453 var dlg, opt, mask, waitTimer;
31454 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31455 var buttons, activeTextEl, bwidth;
31458 var handleButton = function(button){
31460 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31464 var handleHide = function(){
31465 if(opt && opt.cls){
31466 dlg.el.removeClass(opt.cls);
31469 Roo.TaskMgr.stop(waitTimer);
31475 var updateButtons = function(b){
31478 buttons["ok"].hide();
31479 buttons["cancel"].hide();
31480 buttons["yes"].hide();
31481 buttons["no"].hide();
31482 dlg.footer.dom.style.display = 'none';
31485 dlg.footer.dom.style.display = '';
31486 for(var k in buttons){
31487 if(typeof buttons[k] != "function"){
31490 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31491 width += buttons[k].el.getWidth()+15;
31501 var handleEsc = function(d, k, e){
31502 if(opt && opt.closable !== false){
31512 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31513 * @return {Roo.BasicDialog} The BasicDialog element
31515 getDialog : function(){
31517 dlg = new Roo.BasicDialog("x-msg-box", {
31522 constraintoviewport:false,
31524 collapsible : false,
31527 width:400, height:100,
31528 buttonAlign:"center",
31529 closeClick : function(){
31530 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31531 handleButton("no");
31533 handleButton("cancel");
31537 dlg.on("hide", handleHide);
31539 dlg.addKeyListener(27, handleEsc);
31541 var bt = this.buttonText;
31542 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31543 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31544 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31545 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31546 bodyEl = dlg.body.createChild({
31548 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>'
31550 msgEl = bodyEl.dom.firstChild;
31551 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31552 textboxEl.enableDisplayMode();
31553 textboxEl.addKeyListener([10,13], function(){
31554 if(dlg.isVisible() && opt && opt.buttons){
31555 if(opt.buttons.ok){
31556 handleButton("ok");
31557 }else if(opt.buttons.yes){
31558 handleButton("yes");
31562 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31563 textareaEl.enableDisplayMode();
31564 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31565 progressEl.enableDisplayMode();
31566 var pf = progressEl.dom.firstChild;
31568 pp = Roo.get(pf.firstChild);
31569 pp.setHeight(pf.offsetHeight);
31577 * Updates the message box body text
31578 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31579 * the XHTML-compliant non-breaking space character '&#160;')
31580 * @return {Roo.MessageBox} This message box
31582 updateText : function(text){
31583 if(!dlg.isVisible() && !opt.width){
31584 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31586 msgEl.innerHTML = text || ' ';
31588 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31589 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31591 Math.min(opt.width || cw , this.maxWidth),
31592 Math.max(opt.minWidth || this.minWidth, bwidth)
31595 activeTextEl.setWidth(w);
31597 if(dlg.isVisible()){
31598 dlg.fixedcenter = false;
31600 // to big, make it scroll. = But as usual stupid IE does not support
31603 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31604 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31605 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31607 bodyEl.dom.style.height = '';
31608 bodyEl.dom.style.overflowY = '';
31611 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31613 bodyEl.dom.style.overflowX = '';
31616 dlg.setContentSize(w, bodyEl.getHeight());
31617 if(dlg.isVisible()){
31618 dlg.fixedcenter = true;
31624 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31625 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31626 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31627 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31628 * @return {Roo.MessageBox} This message box
31630 updateProgress : function(value, text){
31632 this.updateText(text);
31634 if (pp) { // weird bug on my firefox - for some reason this is not defined
31635 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31641 * Returns true if the message box is currently displayed
31642 * @return {Boolean} True if the message box is visible, else false
31644 isVisible : function(){
31645 return dlg && dlg.isVisible();
31649 * Hides the message box if it is displayed
31652 if(this.isVisible()){
31658 * Displays a new message box, or reinitializes an existing message box, based on the config options
31659 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31660 * The following config object properties are supported:
31662 Property Type Description
31663 ---------- --------------- ------------------------------------------------------------------------------------
31664 animEl String/Element An id or Element from which the message box should animate as it opens and
31665 closes (defaults to undefined)
31666 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31667 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31668 closable Boolean False to hide the top-right close button (defaults to true). Note that
31669 progress and wait dialogs will ignore this property and always hide the
31670 close button as they can only be closed programmatically.
31671 cls String A custom CSS class to apply to the message box element
31672 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31673 displayed (defaults to 75)
31674 fn Function A callback function to execute after closing the dialog. The arguments to the
31675 function will be btn (the name of the button that was clicked, if applicable,
31676 e.g. "ok"), and text (the value of the active text field, if applicable).
31677 Progress and wait dialogs will ignore this option since they do not respond to
31678 user actions and can only be closed programmatically, so any required function
31679 should be called by the same code after it closes the dialog.
31680 icon String A CSS class that provides a background image to be used as an icon for
31681 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31682 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31683 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31684 modal Boolean False to allow user interaction with the page while the message box is
31685 displayed (defaults to true)
31686 msg String A string that will replace the existing message box body text (defaults
31687 to the XHTML-compliant non-breaking space character ' ')
31688 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31689 progress Boolean True to display a progress bar (defaults to false)
31690 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31691 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31692 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31693 title String The title text
31694 value String The string value to set into the active textbox element if displayed
31695 wait Boolean True to display a progress bar (defaults to false)
31696 width Number The width of the dialog in pixels
31703 msg: 'Please enter your address:',
31705 buttons: Roo.MessageBox.OKCANCEL,
31708 animEl: 'addAddressBtn'
31711 * @param {Object} config Configuration options
31712 * @return {Roo.MessageBox} This message box
31714 show : function(options)
31717 // this causes nightmares if you show one dialog after another
31718 // especially on callbacks..
31720 if(this.isVisible()){
31723 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31724 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31725 Roo.log("New Dialog Message:" + options.msg )
31726 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31727 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31730 var d = this.getDialog();
31732 d.setTitle(opt.title || " ");
31733 d.close.setDisplayed(opt.closable !== false);
31734 activeTextEl = textboxEl;
31735 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31740 textareaEl.setHeight(typeof opt.multiline == "number" ?
31741 opt.multiline : this.defaultTextHeight);
31742 activeTextEl = textareaEl;
31751 progressEl.setDisplayed(opt.progress === true);
31752 this.updateProgress(0);
31753 activeTextEl.dom.value = opt.value || "";
31755 dlg.setDefaultButton(activeTextEl);
31757 var bs = opt.buttons;
31760 db = buttons["ok"];
31761 }else if(bs && bs.yes){
31762 db = buttons["yes"];
31764 dlg.setDefaultButton(db);
31766 bwidth = updateButtons(opt.buttons);
31767 this.updateText(opt.msg);
31769 d.el.addClass(opt.cls);
31771 d.proxyDrag = opt.proxyDrag === true;
31772 d.modal = opt.modal !== false;
31773 d.mask = opt.modal !== false ? mask : false;
31774 if(!d.isVisible()){
31775 // force it to the end of the z-index stack so it gets a cursor in FF
31776 document.body.appendChild(dlg.el.dom);
31777 d.animateTarget = null;
31778 d.show(options.animEl);
31784 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31785 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31786 * and closing the message box when the process is complete.
31787 * @param {String} title The title bar text
31788 * @param {String} msg The message box body text
31789 * @return {Roo.MessageBox} This message box
31791 progress : function(title, msg){
31798 minWidth: this.minProgressWidth,
31805 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31806 * If a callback function is passed it will be called after the user clicks the button, and the
31807 * id of the button that was clicked will be passed as the only parameter to the callback
31808 * (could also be the top-right close button).
31809 * @param {String} title The title bar text
31810 * @param {String} msg The message box body text
31811 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31812 * @param {Object} scope (optional) The scope of the callback function
31813 * @return {Roo.MessageBox} This message box
31815 alert : function(title, msg, fn, scope){
31828 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31829 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31830 * You are responsible for closing the message box when the process is complete.
31831 * @param {String} msg The message box body text
31832 * @param {String} title (optional) The title bar text
31833 * @return {Roo.MessageBox} This message box
31835 wait : function(msg, title){
31846 waitTimer = Roo.TaskMgr.start({
31848 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31856 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31857 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31858 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31859 * @param {String} title The title bar text
31860 * @param {String} msg The message box body text
31861 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31862 * @param {Object} scope (optional) The scope of the callback function
31863 * @return {Roo.MessageBox} This message box
31865 confirm : function(title, msg, fn, scope){
31869 buttons: this.YESNO,
31878 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31879 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31880 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31881 * (could also be the top-right close button) and the text that was entered will be passed as the two
31882 * parameters to the callback.
31883 * @param {String} title The title bar text
31884 * @param {String} msg The message box body text
31885 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31886 * @param {Object} scope (optional) The scope of the callback function
31887 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31888 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31889 * @return {Roo.MessageBox} This message box
31891 prompt : function(title, msg, fn, scope, multiline){
31895 buttons: this.OKCANCEL,
31900 multiline: multiline,
31907 * Button config that displays a single OK button
31912 * Button config that displays Yes and No buttons
31915 YESNO : {yes:true, no:true},
31917 * Button config that displays OK and Cancel buttons
31920 OKCANCEL : {ok:true, cancel:true},
31922 * Button config that displays Yes, No and Cancel buttons
31925 YESNOCANCEL : {yes:true, no:true, cancel:true},
31928 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31931 defaultTextHeight : 75,
31933 * The maximum width in pixels of the message box (defaults to 600)
31938 * The minimum width in pixels of the message box (defaults to 100)
31943 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31944 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31947 minProgressWidth : 250,
31949 * An object containing the default button text strings that can be overriden for localized language support.
31950 * Supported properties are: ok, cancel, yes and no.
31951 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31964 * Shorthand for {@link Roo.MessageBox}
31966 Roo.Msg = Roo.MessageBox;/*
31968 * Ext JS Library 1.1.1
31969 * Copyright(c) 2006-2007, Ext JS, LLC.
31971 * Originally Released Under LGPL - original licence link has changed is not relivant.
31974 * <script type="text/javascript">
31977 * @class Roo.QuickTips
31978 * Provides attractive and customizable tooltips for any element.
31981 Roo.QuickTips = function(){
31982 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31983 var ce, bd, xy, dd;
31984 var visible = false, disabled = true, inited = false;
31985 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31987 var onOver = function(e){
31991 var t = e.getTarget();
31992 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31995 if(ce && t == ce.el){
31996 clearTimeout(hideProc);
31999 if(t && tagEls[t.id]){
32000 tagEls[t.id].el = t;
32001 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32004 var ttp, et = Roo.fly(t);
32005 var ns = cfg.namespace;
32006 if(tm.interceptTitles && t.title){
32009 t.removeAttribute("title");
32010 e.preventDefault();
32012 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32015 showProc = show.defer(tm.showDelay, tm, [{
32018 width: et.getAttributeNS(ns, cfg.width),
32019 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32020 title: et.getAttributeNS(ns, cfg.title),
32021 cls: et.getAttributeNS(ns, cfg.cls)
32026 var onOut = function(e){
32027 clearTimeout(showProc);
32028 var t = e.getTarget();
32029 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32030 hideProc = setTimeout(hide, tm.hideDelay);
32034 var onMove = function(e){
32040 if(tm.trackMouse && ce){
32045 var onDown = function(e){
32046 clearTimeout(showProc);
32047 clearTimeout(hideProc);
32049 if(tm.hideOnClick){
32052 tm.enable.defer(100, tm);
32057 var getPad = function(){
32058 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32061 var show = function(o){
32065 clearTimeout(dismissProc);
32067 if(removeCls){ // in case manually hidden
32068 el.removeClass(removeCls);
32072 el.addClass(ce.cls);
32073 removeCls = ce.cls;
32076 tipTitle.update(ce.title);
32079 tipTitle.update('');
32082 el.dom.style.width = tm.maxWidth+'px';
32083 //tipBody.dom.style.width = '';
32084 tipBodyText.update(o.text);
32085 var p = getPad(), w = ce.width;
32087 var td = tipBodyText.dom;
32088 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32089 if(aw > tm.maxWidth){
32091 }else if(aw < tm.minWidth){
32097 //tipBody.setWidth(w);
32098 el.setWidth(parseInt(w, 10) + p);
32099 if(ce.autoHide === false){
32100 close.setDisplayed(true);
32105 close.setDisplayed(false);
32111 el.avoidY = xy[1]-18;
32116 el.setStyle("visibility", "visible");
32117 el.fadeIn({callback: afterShow});
32123 var afterShow = function(){
32127 if(tm.autoDismiss && ce.autoHide !== false){
32128 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32133 var hide = function(noanim){
32134 clearTimeout(dismissProc);
32135 clearTimeout(hideProc);
32137 if(el.isVisible()){
32139 if(noanim !== true && tm.animate){
32140 el.fadeOut({callback: afterHide});
32147 var afterHide = function(){
32150 el.removeClass(removeCls);
32157 * @cfg {Number} minWidth
32158 * The minimum width of the quick tip (defaults to 40)
32162 * @cfg {Number} maxWidth
32163 * The maximum width of the quick tip (defaults to 300)
32167 * @cfg {Boolean} interceptTitles
32168 * True to automatically use the element's DOM title value if available (defaults to false)
32170 interceptTitles : false,
32172 * @cfg {Boolean} trackMouse
32173 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32175 trackMouse : false,
32177 * @cfg {Boolean} hideOnClick
32178 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32180 hideOnClick : true,
32182 * @cfg {Number} showDelay
32183 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32187 * @cfg {Number} hideDelay
32188 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32192 * @cfg {Boolean} autoHide
32193 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32194 * Used in conjunction with hideDelay.
32199 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32200 * (defaults to true). Used in conjunction with autoDismissDelay.
32202 autoDismiss : true,
32205 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32207 autoDismissDelay : 5000,
32209 * @cfg {Boolean} animate
32210 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32215 * @cfg {String} title
32216 * Title text to display (defaults to ''). This can be any valid HTML markup.
32220 * @cfg {String} text
32221 * Body text to display (defaults to ''). This can be any valid HTML markup.
32225 * @cfg {String} cls
32226 * A CSS class to apply to the base quick tip element (defaults to '').
32230 * @cfg {Number} width
32231 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32232 * minWidth or maxWidth.
32237 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32238 * or display QuickTips in a page.
32241 tm = Roo.QuickTips;
32242 cfg = tm.tagConfig;
32244 if(!Roo.isReady){ // allow calling of init() before onReady
32245 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32248 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32249 el.fxDefaults = {stopFx: true};
32250 // maximum custom styling
32251 //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>');
32252 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>');
32253 tipTitle = el.child('h3');
32254 tipTitle.enableDisplayMode("block");
32255 tipBody = el.child('div.x-tip-bd');
32256 tipBodyText = el.child('div.x-tip-bd-inner');
32257 //bdLeft = el.child('div.x-tip-bd-left');
32258 //bdRight = el.child('div.x-tip-bd-right');
32259 close = el.child('div.x-tip-close');
32260 close.enableDisplayMode("block");
32261 close.on("click", hide);
32262 var d = Roo.get(document);
32263 d.on("mousedown", onDown);
32264 d.on("mouseover", onOver);
32265 d.on("mouseout", onOut);
32266 d.on("mousemove", onMove);
32267 esc = d.addKeyListener(27, hide);
32270 dd = el.initDD("default", null, {
32271 onDrag : function(){
32275 dd.setHandleElId(tipTitle.id);
32284 * Configures a new quick tip instance and assigns it to a target element. The following config options
32287 Property Type Description
32288 ---------- --------------------- ------------------------------------------------------------------------
32289 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32291 * @param {Object} config The config object
32293 register : function(config){
32294 var cs = config instanceof Array ? config : arguments;
32295 for(var i = 0, len = cs.length; i < len; i++) {
32297 var target = c.target;
32299 if(target instanceof Array){
32300 for(var j = 0, jlen = target.length; j < jlen; j++){
32301 tagEls[target[j]] = c;
32304 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32311 * Removes this quick tip from its element and destroys it.
32312 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32314 unregister : function(el){
32315 delete tagEls[Roo.id(el)];
32319 * Enable this quick tip.
32321 enable : function(){
32322 if(inited && disabled){
32324 if(locks.length < 1){
32331 * Disable this quick tip.
32333 disable : function(){
32335 clearTimeout(showProc);
32336 clearTimeout(hideProc);
32337 clearTimeout(dismissProc);
32345 * Returns true if the quick tip is enabled, else false.
32347 isEnabled : function(){
32354 attribute : "qtip",
32364 // backwards compat
32365 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32367 * Ext JS Library 1.1.1
32368 * Copyright(c) 2006-2007, Ext JS, LLC.
32370 * Originally Released Under LGPL - original licence link has changed is not relivant.
32373 * <script type="text/javascript">
32378 * @class Roo.tree.TreePanel
32379 * @extends Roo.data.Tree
32381 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32382 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32383 * @cfg {Boolean} enableDD true to enable drag and drop
32384 * @cfg {Boolean} enableDrag true to enable just drag
32385 * @cfg {Boolean} enableDrop true to enable just drop
32386 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32387 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32388 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32389 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32390 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32391 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32392 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32393 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32394 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32395 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32396 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32397 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32398 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32399 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32400 * @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>
32401 * @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>
32404 * @param {String/HTMLElement/Element} el The container element
32405 * @param {Object} config
32407 Roo.tree.TreePanel = function(el, config){
32409 var loader = false;
32411 root = config.root;
32412 delete config.root;
32414 if (config.loader) {
32415 loader = config.loader;
32416 delete config.loader;
32419 Roo.apply(this, config);
32420 Roo.tree.TreePanel.superclass.constructor.call(this);
32421 this.el = Roo.get(el);
32422 this.el.addClass('x-tree');
32423 //console.log(root);
32425 this.setRootNode( Roo.factory(root, Roo.tree));
32428 this.loader = Roo.factory(loader, Roo.tree);
32431 * Read-only. The id of the container element becomes this TreePanel's id.
32433 this.id = this.el.id;
32436 * @event beforeload
32437 * Fires before a node is loaded, return false to cancel
32438 * @param {Node} node The node being loaded
32440 "beforeload" : true,
32443 * Fires when a node is loaded
32444 * @param {Node} node The node that was loaded
32448 * @event textchange
32449 * Fires when the text for a node is changed
32450 * @param {Node} node The node
32451 * @param {String} text The new text
32452 * @param {String} oldText The old text
32454 "textchange" : true,
32456 * @event beforeexpand
32457 * Fires before a node is expanded, return false to cancel.
32458 * @param {Node} node The node
32459 * @param {Boolean} deep
32460 * @param {Boolean} anim
32462 "beforeexpand" : true,
32464 * @event beforecollapse
32465 * Fires before a node is collapsed, return false to cancel.
32466 * @param {Node} node The node
32467 * @param {Boolean} deep
32468 * @param {Boolean} anim
32470 "beforecollapse" : true,
32473 * Fires when a node is expanded
32474 * @param {Node} node The node
32478 * @event disabledchange
32479 * Fires when the disabled status of a node changes
32480 * @param {Node} node The node
32481 * @param {Boolean} disabled
32483 "disabledchange" : true,
32486 * Fires when a node is collapsed
32487 * @param {Node} node The node
32491 * @event beforeclick
32492 * Fires before click processing on a node. Return false to cancel the default action.
32493 * @param {Node} node The node
32494 * @param {Roo.EventObject} e The event object
32496 "beforeclick":true,
32498 * @event checkchange
32499 * Fires when a node with a checkbox's checked property changes
32500 * @param {Node} this This node
32501 * @param {Boolean} checked
32503 "checkchange":true,
32506 * Fires when a node is clicked
32507 * @param {Node} node The node
32508 * @param {Roo.EventObject} e The event object
32513 * Fires when a node is double clicked
32514 * @param {Node} node The node
32515 * @param {Roo.EventObject} e The event object
32519 * @event contextmenu
32520 * Fires when a node is right clicked
32521 * @param {Node} node The node
32522 * @param {Roo.EventObject} e The event object
32524 "contextmenu":true,
32526 * @event beforechildrenrendered
32527 * Fires right before the child nodes for a node are rendered
32528 * @param {Node} node The node
32530 "beforechildrenrendered":true,
32533 * Fires when a node starts being dragged
32534 * @param {Roo.tree.TreePanel} this
32535 * @param {Roo.tree.TreeNode} node
32536 * @param {event} e The raw browser event
32538 "startdrag" : true,
32541 * Fires when a drag operation is complete
32542 * @param {Roo.tree.TreePanel} this
32543 * @param {Roo.tree.TreeNode} node
32544 * @param {event} e The raw browser event
32549 * Fires when a dragged node is dropped on a valid DD target
32550 * @param {Roo.tree.TreePanel} this
32551 * @param {Roo.tree.TreeNode} node
32552 * @param {DD} dd The dd it was dropped on
32553 * @param {event} e The raw browser event
32557 * @event beforenodedrop
32558 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32559 * passed to handlers has the following properties:<br />
32560 * <ul style="padding:5px;padding-left:16px;">
32561 * <li>tree - The TreePanel</li>
32562 * <li>target - The node being targeted for the drop</li>
32563 * <li>data - The drag data from the drag source</li>
32564 * <li>point - The point of the drop - append, above or below</li>
32565 * <li>source - The drag source</li>
32566 * <li>rawEvent - Raw mouse event</li>
32567 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32568 * to be inserted by setting them on this object.</li>
32569 * <li>cancel - Set this to true to cancel the drop.</li>
32571 * @param {Object} dropEvent
32573 "beforenodedrop" : true,
32576 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32577 * passed to handlers has the following properties:<br />
32578 * <ul style="padding:5px;padding-left:16px;">
32579 * <li>tree - The TreePanel</li>
32580 * <li>target - The node being targeted for the drop</li>
32581 * <li>data - The drag data from the drag source</li>
32582 * <li>point - The point of the drop - append, above or below</li>
32583 * <li>source - The drag source</li>
32584 * <li>rawEvent - Raw mouse event</li>
32585 * <li>dropNode - Dropped node(s).</li>
32587 * @param {Object} dropEvent
32591 * @event nodedragover
32592 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32593 * passed to handlers has the following properties:<br />
32594 * <ul style="padding:5px;padding-left:16px;">
32595 * <li>tree - The TreePanel</li>
32596 * <li>target - The node being targeted for the drop</li>
32597 * <li>data - The drag data from the drag source</li>
32598 * <li>point - The point of the drop - append, above or below</li>
32599 * <li>source - The drag source</li>
32600 * <li>rawEvent - Raw mouse event</li>
32601 * <li>dropNode - Drop node(s) provided by the source.</li>
32602 * <li>cancel - Set this to true to signal drop not allowed.</li>
32604 * @param {Object} dragOverEvent
32606 "nodedragover" : true
32609 if(this.singleExpand){
32610 this.on("beforeexpand", this.restrictExpand, this);
32613 this.editor.tree = this;
32614 this.editor = Roo.factory(this.editor, Roo.tree);
32617 if (this.selModel) {
32618 this.selModel = Roo.factory(this.selModel, Roo.tree);
32622 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32623 rootVisible : true,
32624 animate: Roo.enableFx,
32627 hlDrop : Roo.enableFx,
32631 rendererTip: false,
32633 restrictExpand : function(node){
32634 var p = node.parentNode;
32636 if(p.expandedChild && p.expandedChild.parentNode == p){
32637 p.expandedChild.collapse();
32639 p.expandedChild = node;
32643 // private override
32644 setRootNode : function(node){
32645 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32646 if(!this.rootVisible){
32647 node.ui = new Roo.tree.RootTreeNodeUI(node);
32653 * Returns the container element for this TreePanel
32655 getEl : function(){
32660 * Returns the default TreeLoader for this TreePanel
32662 getLoader : function(){
32663 return this.loader;
32669 expandAll : function(){
32670 this.root.expand(true);
32674 * Collapse all nodes
32676 collapseAll : function(){
32677 this.root.collapse(true);
32681 * Returns the selection model used by this TreePanel
32683 getSelectionModel : function(){
32684 if(!this.selModel){
32685 this.selModel = new Roo.tree.DefaultSelectionModel();
32687 return this.selModel;
32691 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32692 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32693 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32696 getChecked : function(a, startNode){
32697 startNode = startNode || this.root;
32699 var f = function(){
32700 if(this.attributes.checked){
32701 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32704 startNode.cascade(f);
32709 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32710 * @param {String} path
32711 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32712 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32713 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32715 expandPath : function(path, attr, callback){
32716 attr = attr || "id";
32717 var keys = path.split(this.pathSeparator);
32718 var curNode = this.root;
32719 if(curNode.attributes[attr] != keys[1]){ // invalid root
32721 callback(false, null);
32726 var f = function(){
32727 if(++index == keys.length){
32729 callback(true, curNode);
32733 var c = curNode.findChild(attr, keys[index]);
32736 callback(false, curNode);
32741 c.expand(false, false, f);
32743 curNode.expand(false, false, f);
32747 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32748 * @param {String} path
32749 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32750 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32751 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32753 selectPath : function(path, attr, callback){
32754 attr = attr || "id";
32755 var keys = path.split(this.pathSeparator);
32756 var v = keys.pop();
32757 if(keys.length > 0){
32758 var f = function(success, node){
32759 if(success && node){
32760 var n = node.findChild(attr, v);
32766 }else if(callback){
32767 callback(false, n);
32771 callback(false, n);
32775 this.expandPath(keys.join(this.pathSeparator), attr, f);
32777 this.root.select();
32779 callback(true, this.root);
32784 getTreeEl : function(){
32789 * Trigger rendering of this TreePanel
32791 render : function(){
32792 if (this.innerCt) {
32793 return this; // stop it rendering more than once!!
32796 this.innerCt = this.el.createChild({tag:"ul",
32797 cls:"x-tree-root-ct " +
32798 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32800 if(this.containerScroll){
32801 Roo.dd.ScrollManager.register(this.el);
32803 if((this.enableDD || this.enableDrop) && !this.dropZone){
32805 * The dropZone used by this tree if drop is enabled
32806 * @type Roo.tree.TreeDropZone
32808 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32809 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32812 if((this.enableDD || this.enableDrag) && !this.dragZone){
32814 * The dragZone used by this tree if drag is enabled
32815 * @type Roo.tree.TreeDragZone
32817 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32818 ddGroup: this.ddGroup || "TreeDD",
32819 scroll: this.ddScroll
32822 this.getSelectionModel().init(this);
32824 Roo.log("ROOT not set in tree");
32827 this.root.render();
32828 if(!this.rootVisible){
32829 this.root.renderChildren();
32835 * Ext JS Library 1.1.1
32836 * Copyright(c) 2006-2007, Ext JS, LLC.
32838 * Originally Released Under LGPL - original licence link has changed is not relivant.
32841 * <script type="text/javascript">
32846 * @class Roo.tree.DefaultSelectionModel
32847 * @extends Roo.util.Observable
32848 * The default single selection for a TreePanel.
32849 * @param {Object} cfg Configuration
32851 Roo.tree.DefaultSelectionModel = function(cfg){
32852 this.selNode = null;
32858 * @event selectionchange
32859 * Fires when the selected node changes
32860 * @param {DefaultSelectionModel} this
32861 * @param {TreeNode} node the new selection
32863 "selectionchange" : true,
32866 * @event beforeselect
32867 * Fires before the selected node changes, return false to cancel the change
32868 * @param {DefaultSelectionModel} this
32869 * @param {TreeNode} node the new selection
32870 * @param {TreeNode} node the old selection
32872 "beforeselect" : true
32875 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32878 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32879 init : function(tree){
32881 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32882 tree.on("click", this.onNodeClick, this);
32885 onNodeClick : function(node, e){
32886 if (e.ctrlKey && this.selNode == node) {
32887 this.unselect(node);
32895 * @param {TreeNode} node The node to select
32896 * @return {TreeNode} The selected node
32898 select : function(node){
32899 var last = this.selNode;
32900 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32902 last.ui.onSelectedChange(false);
32904 this.selNode = node;
32905 node.ui.onSelectedChange(true);
32906 this.fireEvent("selectionchange", this, node, last);
32913 * @param {TreeNode} node The node to unselect
32915 unselect : function(node){
32916 if(this.selNode == node){
32917 this.clearSelections();
32922 * Clear all selections
32924 clearSelections : function(){
32925 var n = this.selNode;
32927 n.ui.onSelectedChange(false);
32928 this.selNode = null;
32929 this.fireEvent("selectionchange", this, null);
32935 * Get the selected node
32936 * @return {TreeNode} The selected node
32938 getSelectedNode : function(){
32939 return this.selNode;
32943 * Returns true if the node is selected
32944 * @param {TreeNode} node The node to check
32945 * @return {Boolean}
32947 isSelected : function(node){
32948 return this.selNode == node;
32952 * Selects the node above the selected node in the tree, intelligently walking the nodes
32953 * @return TreeNode The new selection
32955 selectPrevious : function(){
32956 var s = this.selNode || this.lastSelNode;
32960 var ps = s.previousSibling;
32962 if(!ps.isExpanded() || ps.childNodes.length < 1){
32963 return this.select(ps);
32965 var lc = ps.lastChild;
32966 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32969 return this.select(lc);
32971 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32972 return this.select(s.parentNode);
32978 * Selects the node above the selected node in the tree, intelligently walking the nodes
32979 * @return TreeNode The new selection
32981 selectNext : function(){
32982 var s = this.selNode || this.lastSelNode;
32986 if(s.firstChild && s.isExpanded()){
32987 return this.select(s.firstChild);
32988 }else if(s.nextSibling){
32989 return this.select(s.nextSibling);
32990 }else if(s.parentNode){
32992 s.parentNode.bubble(function(){
32993 if(this.nextSibling){
32994 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33003 onKeyDown : function(e){
33004 var s = this.selNode || this.lastSelNode;
33005 // undesirable, but required
33010 var k = e.getKey();
33018 this.selectPrevious();
33021 e.preventDefault();
33022 if(s.hasChildNodes()){
33023 if(!s.isExpanded()){
33025 }else if(s.firstChild){
33026 this.select(s.firstChild, e);
33031 e.preventDefault();
33032 if(s.hasChildNodes() && s.isExpanded()){
33034 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33035 this.select(s.parentNode, e);
33043 * @class Roo.tree.MultiSelectionModel
33044 * @extends Roo.util.Observable
33045 * Multi selection for a TreePanel.
33046 * @param {Object} cfg Configuration
33048 Roo.tree.MultiSelectionModel = function(){
33049 this.selNodes = [];
33053 * @event selectionchange
33054 * Fires when the selected nodes change
33055 * @param {MultiSelectionModel} this
33056 * @param {Array} nodes Array of the selected nodes
33058 "selectionchange" : true
33060 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33064 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33065 init : function(tree){
33067 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33068 tree.on("click", this.onNodeClick, this);
33071 onNodeClick : function(node, e){
33072 this.select(node, e, e.ctrlKey);
33077 * @param {TreeNode} node The node to select
33078 * @param {EventObject} e (optional) An event associated with the selection
33079 * @param {Boolean} keepExisting True to retain existing selections
33080 * @return {TreeNode} The selected node
33082 select : function(node, e, keepExisting){
33083 if(keepExisting !== true){
33084 this.clearSelections(true);
33086 if(this.isSelected(node)){
33087 this.lastSelNode = node;
33090 this.selNodes.push(node);
33091 this.selMap[node.id] = node;
33092 this.lastSelNode = node;
33093 node.ui.onSelectedChange(true);
33094 this.fireEvent("selectionchange", this, this.selNodes);
33100 * @param {TreeNode} node The node to unselect
33102 unselect : function(node){
33103 if(this.selMap[node.id]){
33104 node.ui.onSelectedChange(false);
33105 var sn = this.selNodes;
33108 index = sn.indexOf(node);
33110 for(var i = 0, len = sn.length; i < len; i++){
33118 this.selNodes.splice(index, 1);
33120 delete this.selMap[node.id];
33121 this.fireEvent("selectionchange", this, this.selNodes);
33126 * Clear all selections
33128 clearSelections : function(suppressEvent){
33129 var sn = this.selNodes;
33131 for(var i = 0, len = sn.length; i < len; i++){
33132 sn[i].ui.onSelectedChange(false);
33134 this.selNodes = [];
33136 if(suppressEvent !== true){
33137 this.fireEvent("selectionchange", this, this.selNodes);
33143 * Returns true if the node is selected
33144 * @param {TreeNode} node The node to check
33145 * @return {Boolean}
33147 isSelected : function(node){
33148 return this.selMap[node.id] ? true : false;
33152 * Returns an array of the selected nodes
33155 getSelectedNodes : function(){
33156 return this.selNodes;
33159 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33161 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33163 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33166 * Ext JS Library 1.1.1
33167 * Copyright(c) 2006-2007, Ext JS, LLC.
33169 * Originally Released Under LGPL - original licence link has changed is not relivant.
33172 * <script type="text/javascript">
33176 * @class Roo.tree.TreeNode
33177 * @extends Roo.data.Node
33178 * @cfg {String} text The text for this node
33179 * @cfg {Boolean} expanded true to start the node expanded
33180 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33181 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33182 * @cfg {Boolean} disabled true to start the node disabled
33183 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33184 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33185 * @cfg {String} cls A css class to be added to the node
33186 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33187 * @cfg {String} href URL of the link used for the node (defaults to #)
33188 * @cfg {String} hrefTarget target frame for the link
33189 * @cfg {String} qtip An Ext QuickTip for the node
33190 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33191 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33192 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33193 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33194 * (defaults to undefined with no checkbox rendered)
33196 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33198 Roo.tree.TreeNode = function(attributes){
33199 attributes = attributes || {};
33200 if(typeof attributes == "string"){
33201 attributes = {text: attributes};
33203 this.childrenRendered = false;
33204 this.rendered = false;
33205 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33206 this.expanded = attributes.expanded === true;
33207 this.isTarget = attributes.isTarget !== false;
33208 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33209 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33212 * Read-only. The text for this node. To change it use setText().
33215 this.text = attributes.text;
33217 * True if this node is disabled.
33220 this.disabled = attributes.disabled === true;
33224 * @event textchange
33225 * Fires when the text for this node is changed
33226 * @param {Node} this This node
33227 * @param {String} text The new text
33228 * @param {String} oldText The old text
33230 "textchange" : true,
33232 * @event beforeexpand
33233 * Fires before this node is expanded, return false to cancel.
33234 * @param {Node} this This node
33235 * @param {Boolean} deep
33236 * @param {Boolean} anim
33238 "beforeexpand" : true,
33240 * @event beforecollapse
33241 * Fires before this node is collapsed, return false to cancel.
33242 * @param {Node} this This node
33243 * @param {Boolean} deep
33244 * @param {Boolean} anim
33246 "beforecollapse" : true,
33249 * Fires when this node is expanded
33250 * @param {Node} this This node
33254 * @event disabledchange
33255 * Fires when the disabled status of this node changes
33256 * @param {Node} this This node
33257 * @param {Boolean} disabled
33259 "disabledchange" : true,
33262 * Fires when this node is collapsed
33263 * @param {Node} this This node
33267 * @event beforeclick
33268 * Fires before click processing. Return false to cancel the default action.
33269 * @param {Node} this This node
33270 * @param {Roo.EventObject} e The event object
33272 "beforeclick":true,
33274 * @event checkchange
33275 * Fires when a node with a checkbox's checked property changes
33276 * @param {Node} this This node
33277 * @param {Boolean} checked
33279 "checkchange":true,
33282 * Fires when this node is clicked
33283 * @param {Node} this This node
33284 * @param {Roo.EventObject} e The event object
33289 * Fires when this node is double clicked
33290 * @param {Node} this This node
33291 * @param {Roo.EventObject} e The event object
33295 * @event contextmenu
33296 * Fires when this node is right clicked
33297 * @param {Node} this This node
33298 * @param {Roo.EventObject} e The event object
33300 "contextmenu":true,
33302 * @event beforechildrenrendered
33303 * Fires right before the child nodes for this node are rendered
33304 * @param {Node} this This node
33306 "beforechildrenrendered":true
33309 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33312 * Read-only. The UI for this node
33315 this.ui = new uiClass(this);
33317 // finally support items[]
33318 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33323 Roo.each(this.attributes.items, function(c) {
33324 this.appendChild(Roo.factory(c,Roo.Tree));
33326 delete this.attributes.items;
33331 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33332 preventHScroll: true,
33334 * Returns true if this node is expanded
33335 * @return {Boolean}
33337 isExpanded : function(){
33338 return this.expanded;
33342 * Returns the UI object for this node
33343 * @return {TreeNodeUI}
33345 getUI : function(){
33349 // private override
33350 setFirstChild : function(node){
33351 var of = this.firstChild;
33352 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33353 if(this.childrenRendered && of && node != of){
33354 of.renderIndent(true, true);
33357 this.renderIndent(true, true);
33361 // private override
33362 setLastChild : function(node){
33363 var ol = this.lastChild;
33364 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33365 if(this.childrenRendered && ol && node != ol){
33366 ol.renderIndent(true, true);
33369 this.renderIndent(true, true);
33373 // these methods are overridden to provide lazy rendering support
33374 // private override
33375 appendChild : function()
33377 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33378 if(node && this.childrenRendered){
33381 this.ui.updateExpandIcon();
33385 // private override
33386 removeChild : function(node){
33387 this.ownerTree.getSelectionModel().unselect(node);
33388 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33389 // if it's been rendered remove dom node
33390 if(this.childrenRendered){
33393 if(this.childNodes.length < 1){
33394 this.collapse(false, false);
33396 this.ui.updateExpandIcon();
33398 if(!this.firstChild) {
33399 this.childrenRendered = false;
33404 // private override
33405 insertBefore : function(node, refNode){
33406 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33407 if(newNode && refNode && this.childrenRendered){
33410 this.ui.updateExpandIcon();
33415 * Sets the text for this node
33416 * @param {String} text
33418 setText : function(text){
33419 var oldText = this.text;
33421 this.attributes.text = text;
33422 if(this.rendered){ // event without subscribing
33423 this.ui.onTextChange(this, text, oldText);
33425 this.fireEvent("textchange", this, text, oldText);
33429 * Triggers selection of this node
33431 select : function(){
33432 this.getOwnerTree().getSelectionModel().select(this);
33436 * Triggers deselection of this node
33438 unselect : function(){
33439 this.getOwnerTree().getSelectionModel().unselect(this);
33443 * Returns true if this node is selected
33444 * @return {Boolean}
33446 isSelected : function(){
33447 return this.getOwnerTree().getSelectionModel().isSelected(this);
33451 * Expand this node.
33452 * @param {Boolean} deep (optional) True to expand all children as well
33453 * @param {Boolean} anim (optional) false to cancel the default animation
33454 * @param {Function} callback (optional) A callback to be called when
33455 * expanding this node completes (does not wait for deep expand to complete).
33456 * Called with 1 parameter, this node.
33458 expand : function(deep, anim, callback){
33459 if(!this.expanded){
33460 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33463 if(!this.childrenRendered){
33464 this.renderChildren();
33466 this.expanded = true;
33467 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33468 this.ui.animExpand(function(){
33469 this.fireEvent("expand", this);
33470 if(typeof callback == "function"){
33474 this.expandChildNodes(true);
33476 }.createDelegate(this));
33480 this.fireEvent("expand", this);
33481 if(typeof callback == "function"){
33486 if(typeof callback == "function"){
33491 this.expandChildNodes(true);
33495 isHiddenRoot : function(){
33496 return this.isRoot && !this.getOwnerTree().rootVisible;
33500 * Collapse this node.
33501 * @param {Boolean} deep (optional) True to collapse all children as well
33502 * @param {Boolean} anim (optional) false to cancel the default animation
33504 collapse : function(deep, anim){
33505 if(this.expanded && !this.isHiddenRoot()){
33506 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33509 this.expanded = false;
33510 if((this.getOwnerTree().animate && anim !== false) || anim){
33511 this.ui.animCollapse(function(){
33512 this.fireEvent("collapse", this);
33514 this.collapseChildNodes(true);
33516 }.createDelegate(this));
33519 this.ui.collapse();
33520 this.fireEvent("collapse", this);
33524 var cs = this.childNodes;
33525 for(var i = 0, len = cs.length; i < len; i++) {
33526 cs[i].collapse(true, false);
33532 delayedExpand : function(delay){
33533 if(!this.expandProcId){
33534 this.expandProcId = this.expand.defer(delay, this);
33539 cancelExpand : function(){
33540 if(this.expandProcId){
33541 clearTimeout(this.expandProcId);
33543 this.expandProcId = false;
33547 * Toggles expanded/collapsed state of the node
33549 toggle : function(){
33558 * Ensures all parent nodes are expanded
33560 ensureVisible : function(callback){
33561 var tree = this.getOwnerTree();
33562 tree.expandPath(this.parentNode.getPath(), false, function(){
33563 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33564 Roo.callback(callback);
33565 }.createDelegate(this));
33569 * Expand all child nodes
33570 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33572 expandChildNodes : function(deep){
33573 var cs = this.childNodes;
33574 for(var i = 0, len = cs.length; i < len; i++) {
33575 cs[i].expand(deep);
33580 * Collapse all child nodes
33581 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33583 collapseChildNodes : function(deep){
33584 var cs = this.childNodes;
33585 for(var i = 0, len = cs.length; i < len; i++) {
33586 cs[i].collapse(deep);
33591 * Disables this node
33593 disable : function(){
33594 this.disabled = true;
33596 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33597 this.ui.onDisableChange(this, true);
33599 this.fireEvent("disabledchange", this, true);
33603 * Enables this node
33605 enable : function(){
33606 this.disabled = false;
33607 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33608 this.ui.onDisableChange(this, false);
33610 this.fireEvent("disabledchange", this, false);
33614 renderChildren : function(suppressEvent){
33615 if(suppressEvent !== false){
33616 this.fireEvent("beforechildrenrendered", this);
33618 var cs = this.childNodes;
33619 for(var i = 0, len = cs.length; i < len; i++){
33620 cs[i].render(true);
33622 this.childrenRendered = true;
33626 sort : function(fn, scope){
33627 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33628 if(this.childrenRendered){
33629 var cs = this.childNodes;
33630 for(var i = 0, len = cs.length; i < len; i++){
33631 cs[i].render(true);
33637 render : function(bulkRender){
33638 this.ui.render(bulkRender);
33639 if(!this.rendered){
33640 this.rendered = true;
33642 this.expanded = false;
33643 this.expand(false, false);
33649 renderIndent : function(deep, refresh){
33651 this.ui.childIndent = null;
33653 this.ui.renderIndent();
33654 if(deep === true && this.childrenRendered){
33655 var cs = this.childNodes;
33656 for(var i = 0, len = cs.length; i < len; i++){
33657 cs[i].renderIndent(true, refresh);
33663 * Ext JS Library 1.1.1
33664 * Copyright(c) 2006-2007, Ext JS, LLC.
33666 * Originally Released Under LGPL - original licence link has changed is not relivant.
33669 * <script type="text/javascript">
33673 * @class Roo.tree.AsyncTreeNode
33674 * @extends Roo.tree.TreeNode
33675 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33677 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33679 Roo.tree.AsyncTreeNode = function(config){
33680 this.loaded = false;
33681 this.loading = false;
33682 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33684 * @event beforeload
33685 * Fires before this node is loaded, return false to cancel
33686 * @param {Node} this This node
33688 this.addEvents({'beforeload':true, 'load': true});
33691 * Fires when this node is loaded
33692 * @param {Node} this This node
33695 * The loader used by this node (defaults to using the tree's defined loader)
33700 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33701 expand : function(deep, anim, callback){
33702 if(this.loading){ // if an async load is already running, waiting til it's done
33704 var f = function(){
33705 if(!this.loading){ // done loading
33706 clearInterval(timer);
33707 this.expand(deep, anim, callback);
33709 }.createDelegate(this);
33710 timer = setInterval(f, 200);
33714 if(this.fireEvent("beforeload", this) === false){
33717 this.loading = true;
33718 this.ui.beforeLoad(this);
33719 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33721 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33725 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33729 * Returns true if this node is currently loading
33730 * @return {Boolean}
33732 isLoading : function(){
33733 return this.loading;
33736 loadComplete : function(deep, anim, callback){
33737 this.loading = false;
33738 this.loaded = true;
33739 this.ui.afterLoad(this);
33740 this.fireEvent("load", this);
33741 this.expand(deep, anim, callback);
33745 * Returns true if this node has been loaded
33746 * @return {Boolean}
33748 isLoaded : function(){
33749 return this.loaded;
33752 hasChildNodes : function(){
33753 if(!this.isLeaf() && !this.loaded){
33756 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33761 * Trigger a reload for this node
33762 * @param {Function} callback
33764 reload : function(callback){
33765 this.collapse(false, false);
33766 while(this.firstChild){
33767 this.removeChild(this.firstChild);
33769 this.childrenRendered = false;
33770 this.loaded = false;
33771 if(this.isHiddenRoot()){
33772 this.expanded = false;
33774 this.expand(false, false, callback);
33778 * Ext JS Library 1.1.1
33779 * Copyright(c) 2006-2007, Ext JS, LLC.
33781 * Originally Released Under LGPL - original licence link has changed is not relivant.
33784 * <script type="text/javascript">
33788 * @class Roo.tree.TreeNodeUI
33790 * @param {Object} node The node to render
33791 * The TreeNode UI implementation is separate from the
33792 * tree implementation. Unless you are customizing the tree UI,
33793 * you should never have to use this directly.
33795 Roo.tree.TreeNodeUI = function(node){
33797 this.rendered = false;
33798 this.animating = false;
33799 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33802 Roo.tree.TreeNodeUI.prototype = {
33803 removeChild : function(node){
33805 this.ctNode.removeChild(node.ui.getEl());
33809 beforeLoad : function(){
33810 this.addClass("x-tree-node-loading");
33813 afterLoad : function(){
33814 this.removeClass("x-tree-node-loading");
33817 onTextChange : function(node, text, oldText){
33819 this.textNode.innerHTML = text;
33823 onDisableChange : function(node, state){
33824 this.disabled = state;
33826 this.addClass("x-tree-node-disabled");
33828 this.removeClass("x-tree-node-disabled");
33832 onSelectedChange : function(state){
33835 this.addClass("x-tree-selected");
33838 this.removeClass("x-tree-selected");
33842 onMove : function(tree, node, oldParent, newParent, index, refNode){
33843 this.childIndent = null;
33845 var targetNode = newParent.ui.getContainer();
33846 if(!targetNode){//target not rendered
33847 this.holder = document.createElement("div");
33848 this.holder.appendChild(this.wrap);
33851 var insertBefore = refNode ? refNode.ui.getEl() : null;
33853 targetNode.insertBefore(this.wrap, insertBefore);
33855 targetNode.appendChild(this.wrap);
33857 this.node.renderIndent(true);
33861 addClass : function(cls){
33863 Roo.fly(this.elNode).addClass(cls);
33867 removeClass : function(cls){
33869 Roo.fly(this.elNode).removeClass(cls);
33873 remove : function(){
33875 this.holder = document.createElement("div");
33876 this.holder.appendChild(this.wrap);
33880 fireEvent : function(){
33881 return this.node.fireEvent.apply(this.node, arguments);
33884 initEvents : function(){
33885 this.node.on("move", this.onMove, this);
33886 var E = Roo.EventManager;
33887 var a = this.anchor;
33889 var el = Roo.fly(a, '_treeui');
33891 if(Roo.isOpera){ // opera render bug ignores the CSS
33892 el.setStyle("text-decoration", "none");
33895 el.on("click", this.onClick, this);
33896 el.on("dblclick", this.onDblClick, this);
33899 Roo.EventManager.on(this.checkbox,
33900 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33903 el.on("contextmenu", this.onContextMenu, this);
33905 var icon = Roo.fly(this.iconNode);
33906 icon.on("click", this.onClick, this);
33907 icon.on("dblclick", this.onDblClick, this);
33908 icon.on("contextmenu", this.onContextMenu, this);
33909 E.on(this.ecNode, "click", this.ecClick, this, true);
33911 if(this.node.disabled){
33912 this.addClass("x-tree-node-disabled");
33914 if(this.node.hidden){
33915 this.addClass("x-tree-node-disabled");
33917 var ot = this.node.getOwnerTree();
33918 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33919 if(dd && (!this.node.isRoot || ot.rootVisible)){
33920 Roo.dd.Registry.register(this.elNode, {
33922 handles: this.getDDHandles(),
33928 getDDHandles : function(){
33929 return [this.iconNode, this.textNode];
33934 this.wrap.style.display = "none";
33940 this.wrap.style.display = "";
33944 onContextMenu : function(e){
33945 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33946 e.preventDefault();
33948 this.fireEvent("contextmenu", this.node, e);
33952 onClick : function(e){
33957 if(this.fireEvent("beforeclick", this.node, e) !== false){
33958 if(!this.disabled && this.node.attributes.href){
33959 this.fireEvent("click", this.node, e);
33962 e.preventDefault();
33967 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33968 this.node.toggle();
33971 this.fireEvent("click", this.node, e);
33977 onDblClick : function(e){
33978 e.preventDefault();
33983 this.toggleCheck();
33985 if(!this.animating && this.node.hasChildNodes()){
33986 this.node.toggle();
33988 this.fireEvent("dblclick", this.node, e);
33991 onCheckChange : function(){
33992 var checked = this.checkbox.checked;
33993 this.node.attributes.checked = checked;
33994 this.fireEvent('checkchange', this.node, checked);
33997 ecClick : function(e){
33998 if(!this.animating && this.node.hasChildNodes()){
33999 this.node.toggle();
34003 startDrop : function(){
34004 this.dropping = true;
34007 // delayed drop so the click event doesn't get fired on a drop
34008 endDrop : function(){
34009 setTimeout(function(){
34010 this.dropping = false;
34011 }.createDelegate(this), 50);
34014 expand : function(){
34015 this.updateExpandIcon();
34016 this.ctNode.style.display = "";
34019 focus : function(){
34020 if(!this.node.preventHScroll){
34021 try{this.anchor.focus();
34023 }else if(!Roo.isIE){
34025 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34026 var l = noscroll.scrollLeft;
34027 this.anchor.focus();
34028 noscroll.scrollLeft = l;
34033 toggleCheck : function(value){
34034 var cb = this.checkbox;
34036 cb.checked = (value === undefined ? !cb.checked : value);
34042 this.anchor.blur();
34046 animExpand : function(callback){
34047 var ct = Roo.get(this.ctNode);
34049 if(!this.node.hasChildNodes()){
34050 this.updateExpandIcon();
34051 this.ctNode.style.display = "";
34052 Roo.callback(callback);
34055 this.animating = true;
34056 this.updateExpandIcon();
34059 callback : function(){
34060 this.animating = false;
34061 Roo.callback(callback);
34064 duration: this.node.ownerTree.duration || .25
34068 highlight : function(){
34069 var tree = this.node.getOwnerTree();
34070 Roo.fly(this.wrap).highlight(
34071 tree.hlColor || "C3DAF9",
34072 {endColor: tree.hlBaseColor}
34076 collapse : function(){
34077 this.updateExpandIcon();
34078 this.ctNode.style.display = "none";
34081 animCollapse : function(callback){
34082 var ct = Roo.get(this.ctNode);
34083 ct.enableDisplayMode('block');
34086 this.animating = true;
34087 this.updateExpandIcon();
34090 callback : function(){
34091 this.animating = false;
34092 Roo.callback(callback);
34095 duration: this.node.ownerTree.duration || .25
34099 getContainer : function(){
34100 return this.ctNode;
34103 getEl : function(){
34107 appendDDGhost : function(ghostNode){
34108 ghostNode.appendChild(this.elNode.cloneNode(true));
34111 getDDRepairXY : function(){
34112 return Roo.lib.Dom.getXY(this.iconNode);
34115 onRender : function(){
34119 render : function(bulkRender){
34120 var n = this.node, a = n.attributes;
34121 var targetNode = n.parentNode ?
34122 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34124 if(!this.rendered){
34125 this.rendered = true;
34127 this.renderElements(n, a, targetNode, bulkRender);
34130 if(this.textNode.setAttributeNS){
34131 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34133 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34136 this.textNode.setAttribute("ext:qtip", a.qtip);
34138 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34141 }else if(a.qtipCfg){
34142 a.qtipCfg.target = Roo.id(this.textNode);
34143 Roo.QuickTips.register(a.qtipCfg);
34146 if(!this.node.expanded){
34147 this.updateExpandIcon();
34150 if(bulkRender === true) {
34151 targetNode.appendChild(this.wrap);
34156 renderElements : function(n, a, targetNode, bulkRender)
34158 // add some indent caching, this helps performance when rendering a large tree
34159 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34160 var t = n.getOwnerTree();
34161 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34162 if (typeof(n.attributes.html) != 'undefined') {
34163 txt = n.attributes.html;
34165 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34166 var cb = typeof a.checked == 'boolean';
34167 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34168 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34169 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34170 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34171 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34172 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34173 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34174 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34175 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34176 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34179 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34180 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34181 n.nextSibling.ui.getEl(), buf.join(""));
34183 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34186 this.elNode = this.wrap.childNodes[0];
34187 this.ctNode = this.wrap.childNodes[1];
34188 var cs = this.elNode.childNodes;
34189 this.indentNode = cs[0];
34190 this.ecNode = cs[1];
34191 this.iconNode = cs[2];
34194 this.checkbox = cs[3];
34197 this.anchor = cs[index];
34198 this.textNode = cs[index].firstChild;
34201 getAnchor : function(){
34202 return this.anchor;
34205 getTextEl : function(){
34206 return this.textNode;
34209 getIconEl : function(){
34210 return this.iconNode;
34213 isChecked : function(){
34214 return this.checkbox ? this.checkbox.checked : false;
34217 updateExpandIcon : function(){
34219 var n = this.node, c1, c2;
34220 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34221 var hasChild = n.hasChildNodes();
34225 c1 = "x-tree-node-collapsed";
34226 c2 = "x-tree-node-expanded";
34229 c1 = "x-tree-node-expanded";
34230 c2 = "x-tree-node-collapsed";
34233 this.removeClass("x-tree-node-leaf");
34234 this.wasLeaf = false;
34236 if(this.c1 != c1 || this.c2 != c2){
34237 Roo.fly(this.elNode).replaceClass(c1, c2);
34238 this.c1 = c1; this.c2 = c2;
34241 // this changes non-leafs into leafs if they have no children.
34242 // it's not very rational behaviour..
34244 if(!this.wasLeaf && this.node.leaf){
34245 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34248 this.wasLeaf = true;
34251 var ecc = "x-tree-ec-icon "+cls;
34252 if(this.ecc != ecc){
34253 this.ecNode.className = ecc;
34259 getChildIndent : function(){
34260 if(!this.childIndent){
34264 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34266 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34268 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34273 this.childIndent = buf.join("");
34275 return this.childIndent;
34278 renderIndent : function(){
34281 var p = this.node.parentNode;
34283 indent = p.ui.getChildIndent();
34285 if(this.indentMarkup != indent){ // don't rerender if not required
34286 this.indentNode.innerHTML = indent;
34287 this.indentMarkup = indent;
34289 this.updateExpandIcon();
34294 Roo.tree.RootTreeNodeUI = function(){
34295 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34297 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34298 render : function(){
34299 if(!this.rendered){
34300 var targetNode = this.node.ownerTree.innerCt.dom;
34301 this.node.expanded = true;
34302 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34303 this.wrap = this.ctNode = targetNode.firstChild;
34306 collapse : function(){
34308 expand : function(){
34312 * Ext JS Library 1.1.1
34313 * Copyright(c) 2006-2007, Ext JS, LLC.
34315 * Originally Released Under LGPL - original licence link has changed is not relivant.
34318 * <script type="text/javascript">
34321 * @class Roo.tree.TreeLoader
34322 * @extends Roo.util.Observable
34323 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34324 * nodes from a specified URL. The response must be a javascript Array definition
34325 * who's elements are node definition objects. eg:
34330 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34331 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34338 * The old style respose with just an array is still supported, but not recommended.
34341 * A server request is sent, and child nodes are loaded only when a node is expanded.
34342 * The loading node's id is passed to the server under the parameter name "node" to
34343 * enable the server to produce the correct child nodes.
34345 * To pass extra parameters, an event handler may be attached to the "beforeload"
34346 * event, and the parameters specified in the TreeLoader's baseParams property:
34348 myTreeLoader.on("beforeload", function(treeLoader, node) {
34349 this.baseParams.category = node.attributes.category;
34352 * This would pass an HTTP parameter called "category" to the server containing
34353 * the value of the Node's "category" attribute.
34355 * Creates a new Treeloader.
34356 * @param {Object} config A config object containing config properties.
34358 Roo.tree.TreeLoader = function(config){
34359 this.baseParams = {};
34360 this.requestMethod = "POST";
34361 Roo.apply(this, config);
34366 * @event beforeload
34367 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34368 * @param {Object} This TreeLoader object.
34369 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34370 * @param {Object} callback The callback function specified in the {@link #load} call.
34375 * Fires when the node has been successfuly loaded.
34376 * @param {Object} This TreeLoader object.
34377 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34378 * @param {Object} response The response object containing the data from the server.
34382 * @event loadexception
34383 * Fires if the network request failed.
34384 * @param {Object} This TreeLoader object.
34385 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34386 * @param {Object} response The response object containing the data from the server.
34388 loadexception : true,
34391 * Fires before a node is created, enabling you to return custom Node types
34392 * @param {Object} This TreeLoader object.
34393 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34398 Roo.tree.TreeLoader.superclass.constructor.call(this);
34401 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34403 * @cfg {String} dataUrl The URL from which to request a Json string which
34404 * specifies an array of node definition object representing the child nodes
34408 * @cfg {String} requestMethod either GET or POST
34409 * defaults to POST (due to BC)
34413 * @cfg {Object} baseParams (optional) An object containing properties which
34414 * specify HTTP parameters to be passed to each request for child nodes.
34417 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34418 * created by this loader. If the attributes sent by the server have an attribute in this object,
34419 * they take priority.
34422 * @cfg {Object} uiProviders (optional) An object containing properties which
34424 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34425 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34426 * <i>uiProvider</i> attribute of a returned child node is a string rather
34427 * than a reference to a TreeNodeUI implementation, this that string value
34428 * is used as a property name in the uiProviders object. You can define the provider named
34429 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34434 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34435 * child nodes before loading.
34437 clearOnLoad : true,
34440 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34441 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34442 * Grid query { data : [ .....] }
34447 * @cfg {String} queryParam (optional)
34448 * Name of the query as it will be passed on the querystring (defaults to 'node')
34449 * eg. the request will be ?node=[id]
34456 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34457 * This is called automatically when a node is expanded, but may be used to reload
34458 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34459 * @param {Roo.tree.TreeNode} node
34460 * @param {Function} callback
34462 load : function(node, callback){
34463 if(this.clearOnLoad){
34464 while(node.firstChild){
34465 node.removeChild(node.firstChild);
34468 if(node.attributes.children){ // preloaded json children
34469 var cs = node.attributes.children;
34470 for(var i = 0, len = cs.length; i < len; i++){
34471 node.appendChild(this.createNode(cs[i]));
34473 if(typeof callback == "function"){
34476 }else if(this.dataUrl){
34477 this.requestData(node, callback);
34481 getParams: function(node){
34482 var buf = [], bp = this.baseParams;
34483 for(var key in bp){
34484 if(typeof bp[key] != "function"){
34485 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34488 var n = this.queryParam === false ? 'node' : this.queryParam;
34489 buf.push(n + "=", encodeURIComponent(node.id));
34490 return buf.join("");
34493 requestData : function(node, callback){
34494 if(this.fireEvent("beforeload", this, node, callback) !== false){
34495 this.transId = Roo.Ajax.request({
34496 method:this.requestMethod,
34497 url: this.dataUrl||this.url,
34498 success: this.handleResponse,
34499 failure: this.handleFailure,
34501 argument: {callback: callback, node: node},
34502 params: this.getParams(node)
34505 // if the load is cancelled, make sure we notify
34506 // the node that we are done
34507 if(typeof callback == "function"){
34513 isLoading : function(){
34514 return this.transId ? true : false;
34517 abort : function(){
34518 if(this.isLoading()){
34519 Roo.Ajax.abort(this.transId);
34524 createNode : function(attr)
34526 // apply baseAttrs, nice idea Corey!
34527 if(this.baseAttrs){
34528 Roo.applyIf(attr, this.baseAttrs);
34530 if(this.applyLoader !== false){
34531 attr.loader = this;
34533 // uiProvider = depreciated..
34535 if(typeof(attr.uiProvider) == 'string'){
34536 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34537 /** eval:var:attr */ eval(attr.uiProvider);
34539 if(typeof(this.uiProviders['default']) != 'undefined') {
34540 attr.uiProvider = this.uiProviders['default'];
34543 this.fireEvent('create', this, attr);
34545 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34547 new Roo.tree.TreeNode(attr) :
34548 new Roo.tree.AsyncTreeNode(attr));
34551 processResponse : function(response, node, callback)
34553 var json = response.responseText;
34556 var o = Roo.decode(json);
34558 if (this.root === false && typeof(o.success) != undefined) {
34559 this.root = 'data'; // the default behaviour for list like data..
34562 if (this.root !== false && !o.success) {
34563 // it's a failure condition.
34564 var a = response.argument;
34565 this.fireEvent("loadexception", this, a.node, response);
34566 Roo.log("Load failed - should have a handler really");
34572 if (this.root !== false) {
34576 for(var i = 0, len = o.length; i < len; i++){
34577 var n = this.createNode(o[i]);
34579 node.appendChild(n);
34582 if(typeof callback == "function"){
34583 callback(this, node);
34586 this.handleFailure(response);
34590 handleResponse : function(response){
34591 this.transId = false;
34592 var a = response.argument;
34593 this.processResponse(response, a.node, a.callback);
34594 this.fireEvent("load", this, a.node, response);
34597 handleFailure : function(response)
34599 // should handle failure better..
34600 this.transId = false;
34601 var a = response.argument;
34602 this.fireEvent("loadexception", this, a.node, response);
34603 if(typeof a.callback == "function"){
34604 a.callback(this, a.node);
34609 * Ext JS Library 1.1.1
34610 * Copyright(c) 2006-2007, Ext JS, LLC.
34612 * Originally Released Under LGPL - original licence link has changed is not relivant.
34615 * <script type="text/javascript">
34619 * @class Roo.tree.TreeFilter
34620 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34621 * @param {TreePanel} tree
34622 * @param {Object} config (optional)
34624 Roo.tree.TreeFilter = function(tree, config){
34626 this.filtered = {};
34627 Roo.apply(this, config);
34630 Roo.tree.TreeFilter.prototype = {
34637 * Filter the data by a specific attribute.
34638 * @param {String/RegExp} value Either string that the attribute value
34639 * should start with or a RegExp to test against the attribute
34640 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34641 * @param {TreeNode} startNode (optional) The node to start the filter at.
34643 filter : function(value, attr, startNode){
34644 attr = attr || "text";
34646 if(typeof value == "string"){
34647 var vlen = value.length;
34648 // auto clear empty filter
34649 if(vlen == 0 && this.clearBlank){
34653 value = value.toLowerCase();
34655 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34657 }else if(value.exec){ // regex?
34659 return value.test(n.attributes[attr]);
34662 throw 'Illegal filter type, must be string or regex';
34664 this.filterBy(f, null, startNode);
34668 * Filter by a function. The passed function will be called with each
34669 * node in the tree (or from the startNode). If the function returns true, the node is kept
34670 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34671 * @param {Function} fn The filter function
34672 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34674 filterBy : function(fn, scope, startNode){
34675 startNode = startNode || this.tree.root;
34676 if(this.autoClear){
34679 var af = this.filtered, rv = this.reverse;
34680 var f = function(n){
34681 if(n == startNode){
34687 var m = fn.call(scope || n, n);
34695 startNode.cascade(f);
34698 if(typeof id != "function"){
34700 if(n && n.parentNode){
34701 n.parentNode.removeChild(n);
34709 * Clears the current filter. Note: with the "remove" option
34710 * set a filter cannot be cleared.
34712 clear : function(){
34714 var af = this.filtered;
34716 if(typeof id != "function"){
34723 this.filtered = {};
34728 * Ext JS Library 1.1.1
34729 * Copyright(c) 2006-2007, Ext JS, LLC.
34731 * Originally Released Under LGPL - original licence link has changed is not relivant.
34734 * <script type="text/javascript">
34739 * @class Roo.tree.TreeSorter
34740 * Provides sorting of nodes in a TreePanel
34742 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34743 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34744 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34745 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34746 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34747 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34749 * @param {TreePanel} tree
34750 * @param {Object} config
34752 Roo.tree.TreeSorter = function(tree, config){
34753 Roo.apply(this, config);
34754 tree.on("beforechildrenrendered", this.doSort, this);
34755 tree.on("append", this.updateSort, this);
34756 tree.on("insert", this.updateSort, this);
34758 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34759 var p = this.property || "text";
34760 var sortType = this.sortType;
34761 var fs = this.folderSort;
34762 var cs = this.caseSensitive === true;
34763 var leafAttr = this.leafAttr || 'leaf';
34765 this.sortFn = function(n1, n2){
34767 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34770 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34774 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34775 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34777 return dsc ? +1 : -1;
34779 return dsc ? -1 : +1;
34786 Roo.tree.TreeSorter.prototype = {
34787 doSort : function(node){
34788 node.sort(this.sortFn);
34791 compareNodes : function(n1, n2){
34792 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34795 updateSort : function(tree, node){
34796 if(node.childrenRendered){
34797 this.doSort.defer(1, this, [node]);
34802 * Ext JS Library 1.1.1
34803 * Copyright(c) 2006-2007, Ext JS, LLC.
34805 * Originally Released Under LGPL - original licence link has changed is not relivant.
34808 * <script type="text/javascript">
34811 if(Roo.dd.DropZone){
34813 Roo.tree.TreeDropZone = function(tree, config){
34814 this.allowParentInsert = false;
34815 this.allowContainerDrop = false;
34816 this.appendOnly = false;
34817 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34819 this.lastInsertClass = "x-tree-no-status";
34820 this.dragOverData = {};
34823 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34824 ddGroup : "TreeDD",
34827 expandDelay : 1000,
34829 expandNode : function(node){
34830 if(node.hasChildNodes() && !node.isExpanded()){
34831 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34835 queueExpand : function(node){
34836 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34839 cancelExpand : function(){
34840 if(this.expandProcId){
34841 clearTimeout(this.expandProcId);
34842 this.expandProcId = false;
34846 isValidDropPoint : function(n, pt, dd, e, data){
34847 if(!n || !data){ return false; }
34848 var targetNode = n.node;
34849 var dropNode = data.node;
34850 // default drop rules
34851 if(!(targetNode && targetNode.isTarget && pt)){
34854 if(pt == "append" && targetNode.allowChildren === false){
34857 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34860 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34863 // reuse the object
34864 var overEvent = this.dragOverData;
34865 overEvent.tree = this.tree;
34866 overEvent.target = targetNode;
34867 overEvent.data = data;
34868 overEvent.point = pt;
34869 overEvent.source = dd;
34870 overEvent.rawEvent = e;
34871 overEvent.dropNode = dropNode;
34872 overEvent.cancel = false;
34873 var result = this.tree.fireEvent("nodedragover", overEvent);
34874 return overEvent.cancel === false && result !== false;
34877 getDropPoint : function(e, n, dd)
34881 return tn.allowChildren !== false ? "append" : false; // always append for root
34883 var dragEl = n.ddel;
34884 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34885 var y = Roo.lib.Event.getPageY(e);
34886 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34888 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34889 var noAppend = tn.allowChildren === false;
34890 if(this.appendOnly || tn.parentNode.allowChildren === false){
34891 return noAppend ? false : "append";
34893 var noBelow = false;
34894 if(!this.allowParentInsert){
34895 noBelow = tn.hasChildNodes() && tn.isExpanded();
34897 var q = (b - t) / (noAppend ? 2 : 3);
34898 if(y >= t && y < (t + q)){
34900 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34907 onNodeEnter : function(n, dd, e, data)
34909 this.cancelExpand();
34912 onNodeOver : function(n, dd, e, data)
34915 var pt = this.getDropPoint(e, n, dd);
34918 // auto node expand check
34919 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34920 this.queueExpand(node);
34921 }else if(pt != "append"){
34922 this.cancelExpand();
34925 // set the insert point style on the target node
34926 var returnCls = this.dropNotAllowed;
34927 if(this.isValidDropPoint(n, pt, dd, e, data)){
34932 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34933 cls = "x-tree-drag-insert-above";
34934 }else if(pt == "below"){
34935 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34936 cls = "x-tree-drag-insert-below";
34938 returnCls = "x-tree-drop-ok-append";
34939 cls = "x-tree-drag-append";
34941 if(this.lastInsertClass != cls){
34942 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34943 this.lastInsertClass = cls;
34950 onNodeOut : function(n, dd, e, data){
34952 this.cancelExpand();
34953 this.removeDropIndicators(n);
34956 onNodeDrop : function(n, dd, e, data){
34957 var point = this.getDropPoint(e, n, dd);
34958 var targetNode = n.node;
34959 targetNode.ui.startDrop();
34960 if(!this.isValidDropPoint(n, point, dd, e, data)){
34961 targetNode.ui.endDrop();
34964 // first try to find the drop node
34965 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34968 target: targetNode,
34973 dropNode: dropNode,
34976 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34977 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34978 targetNode.ui.endDrop();
34981 // allow target changing
34982 targetNode = dropEvent.target;
34983 if(point == "append" && !targetNode.isExpanded()){
34984 targetNode.expand(false, null, function(){
34985 this.completeDrop(dropEvent);
34986 }.createDelegate(this));
34988 this.completeDrop(dropEvent);
34993 completeDrop : function(de){
34994 var ns = de.dropNode, p = de.point, t = de.target;
34995 if(!(ns instanceof Array)){
34999 for(var i = 0, len = ns.length; i < len; i++){
35002 t.parentNode.insertBefore(n, t);
35003 }else if(p == "below"){
35004 t.parentNode.insertBefore(n, t.nextSibling);
35010 if(this.tree.hlDrop){
35014 this.tree.fireEvent("nodedrop", de);
35017 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35018 if(this.tree.hlDrop){
35019 dropNode.ui.focus();
35020 dropNode.ui.highlight();
35022 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35025 getTree : function(){
35029 removeDropIndicators : function(n){
35032 Roo.fly(el).removeClass([
35033 "x-tree-drag-insert-above",
35034 "x-tree-drag-insert-below",
35035 "x-tree-drag-append"]);
35036 this.lastInsertClass = "_noclass";
35040 beforeDragDrop : function(target, e, id){
35041 this.cancelExpand();
35045 afterRepair : function(data){
35046 if(data && Roo.enableFx){
35047 data.node.ui.highlight();
35057 * Ext JS Library 1.1.1
35058 * Copyright(c) 2006-2007, Ext JS, LLC.
35060 * Originally Released Under LGPL - original licence link has changed is not relivant.
35063 * <script type="text/javascript">
35067 if(Roo.dd.DragZone){
35068 Roo.tree.TreeDragZone = function(tree, config){
35069 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35073 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35074 ddGroup : "TreeDD",
35076 onBeforeDrag : function(data, e){
35078 return n && n.draggable && !n.disabled;
35082 onInitDrag : function(e){
35083 var data = this.dragData;
35084 this.tree.getSelectionModel().select(data.node);
35085 this.proxy.update("");
35086 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35087 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35090 getRepairXY : function(e, data){
35091 return data.node.ui.getDDRepairXY();
35094 onEndDrag : function(data, e){
35095 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35100 onValidDrop : function(dd, e, id){
35101 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35105 beforeInvalidDrop : function(e, id){
35106 // this scrolls the original position back into view
35107 var sm = this.tree.getSelectionModel();
35108 sm.clearSelections();
35109 sm.select(this.dragData.node);
35114 * Ext JS Library 1.1.1
35115 * Copyright(c) 2006-2007, Ext JS, LLC.
35117 * Originally Released Under LGPL - original licence link has changed is not relivant.
35120 * <script type="text/javascript">
35123 * @class Roo.tree.TreeEditor
35124 * @extends Roo.Editor
35125 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35126 * as the editor field.
35128 * @param {Object} config (used to be the tree panel.)
35129 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35131 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35132 * @cfg {Roo.form.TextField|Object} field The field configuration
35136 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35139 if (oldconfig) { // old style..
35140 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35143 tree = config.tree;
35144 config.field = config.field || {};
35145 config.field.xtype = 'TextField';
35146 field = Roo.factory(config.field, Roo.form);
35148 config = config || {};
35153 * @event beforenodeedit
35154 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35155 * false from the handler of this event.
35156 * @param {Editor} this
35157 * @param {Roo.tree.Node} node
35159 "beforenodeedit" : true
35163 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35167 tree.on('beforeclick', this.beforeNodeClick, this);
35168 tree.getTreeEl().on('mousedown', this.hide, this);
35169 this.on('complete', this.updateNode, this);
35170 this.on('beforestartedit', this.fitToTree, this);
35171 this.on('startedit', this.bindScroll, this, {delay:10});
35172 this.on('specialkey', this.onSpecialKey, this);
35175 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35177 * @cfg {String} alignment
35178 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35184 * @cfg {Boolean} hideEl
35185 * True to hide the bound element while the editor is displayed (defaults to false)
35189 * @cfg {String} cls
35190 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35192 cls: "x-small-editor x-tree-editor",
35194 * @cfg {Boolean} shim
35195 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35201 * @cfg {Number} maxWidth
35202 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35203 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35204 * scroll and client offsets into account prior to each edit.
35211 fitToTree : function(ed, el){
35212 var td = this.tree.getTreeEl().dom, nd = el.dom;
35213 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35214 td.scrollLeft = nd.offsetLeft;
35218 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35219 this.setSize(w, '');
35221 return this.fireEvent('beforenodeedit', this, this.editNode);
35226 triggerEdit : function(node){
35227 this.completeEdit();
35228 this.editNode = node;
35229 this.startEdit(node.ui.textNode, node.text);
35233 bindScroll : function(){
35234 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35238 beforeNodeClick : function(node, e){
35239 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35240 this.lastClick = new Date();
35241 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35243 this.triggerEdit(node);
35250 updateNode : function(ed, value){
35251 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35252 this.editNode.setText(value);
35256 onHide : function(){
35257 Roo.tree.TreeEditor.superclass.onHide.call(this);
35259 this.editNode.ui.focus();
35264 onSpecialKey : function(field, e){
35265 var k = e.getKey();
35269 }else if(k == e.ENTER && !e.hasModifier()){
35271 this.completeEdit();
35274 });//<Script type="text/javascript">
35277 * Ext JS Library 1.1.1
35278 * Copyright(c) 2006-2007, Ext JS, LLC.
35280 * Originally Released Under LGPL - original licence link has changed is not relivant.
35283 * <script type="text/javascript">
35287 * Not documented??? - probably should be...
35290 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35291 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35293 renderElements : function(n, a, targetNode, bulkRender){
35294 //consel.log("renderElements?");
35295 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35297 var t = n.getOwnerTree();
35298 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35300 var cols = t.columns;
35301 var bw = t.borderWidth;
35303 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35304 var cb = typeof a.checked == "boolean";
35305 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35306 var colcls = 'x-t-' + tid + '-c0';
35308 '<li class="x-tree-node">',
35311 '<div class="x-tree-node-el ', a.cls,'">',
35313 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35316 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35317 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35318 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35319 (a.icon ? ' x-tree-node-inline-icon' : ''),
35320 (a.iconCls ? ' '+a.iconCls : ''),
35321 '" unselectable="on" />',
35322 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35323 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35325 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35326 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35327 '<span unselectable="on" qtip="' + tx + '">',
35331 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35332 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35334 for(var i = 1, len = cols.length; i < len; i++){
35336 colcls = 'x-t-' + tid + '-c' +i;
35337 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35338 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35339 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35345 '<div class="x-clear"></div></div>',
35346 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35349 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35350 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35351 n.nextSibling.ui.getEl(), buf.join(""));
35353 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35355 var el = this.wrap.firstChild;
35357 this.elNode = el.firstChild;
35358 this.ranchor = el.childNodes[1];
35359 this.ctNode = this.wrap.childNodes[1];
35360 var cs = el.firstChild.childNodes;
35361 this.indentNode = cs[0];
35362 this.ecNode = cs[1];
35363 this.iconNode = cs[2];
35366 this.checkbox = cs[3];
35369 this.anchor = cs[index];
35371 this.textNode = cs[index].firstChild;
35373 //el.on("click", this.onClick, this);
35374 //el.on("dblclick", this.onDblClick, this);
35377 // console.log(this);
35379 initEvents : function(){
35380 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35383 var a = this.ranchor;
35385 var el = Roo.get(a);
35387 if(Roo.isOpera){ // opera render bug ignores the CSS
35388 el.setStyle("text-decoration", "none");
35391 el.on("click", this.onClick, this);
35392 el.on("dblclick", this.onDblClick, this);
35393 el.on("contextmenu", this.onContextMenu, this);
35397 /*onSelectedChange : function(state){
35400 this.addClass("x-tree-selected");
35403 this.removeClass("x-tree-selected");
35406 addClass : function(cls){
35408 Roo.fly(this.elRow).addClass(cls);
35414 removeClass : function(cls){
35416 Roo.fly(this.elRow).removeClass(cls);
35422 });//<Script type="text/javascript">
35426 * Ext JS Library 1.1.1
35427 * Copyright(c) 2006-2007, Ext JS, LLC.
35429 * Originally Released Under LGPL - original licence link has changed is not relivant.
35432 * <script type="text/javascript">
35437 * @class Roo.tree.ColumnTree
35438 * @extends Roo.data.TreePanel
35439 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35440 * @cfg {int} borderWidth compined right/left border allowance
35442 * @param {String/HTMLElement/Element} el The container element
35443 * @param {Object} config
35445 Roo.tree.ColumnTree = function(el, config)
35447 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35451 * Fire this event on a container when it resizes
35452 * @param {int} w Width
35453 * @param {int} h Height
35457 this.on('resize', this.onResize, this);
35460 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35464 borderWidth: Roo.isBorderBox ? 0 : 2,
35467 render : function(){
35468 // add the header.....
35470 Roo.tree.ColumnTree.superclass.render.apply(this);
35472 this.el.addClass('x-column-tree');
35474 this.headers = this.el.createChild(
35475 {cls:'x-tree-headers'},this.innerCt.dom);
35477 var cols = this.columns, c;
35478 var totalWidth = 0;
35480 var len = cols.length;
35481 for(var i = 0; i < len; i++){
35483 totalWidth += c.width;
35484 this.headEls.push(this.headers.createChild({
35485 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35487 cls:'x-tree-hd-text',
35490 style:'width:'+(c.width-this.borderWidth)+'px;'
35493 this.headers.createChild({cls:'x-clear'});
35494 // prevent floats from wrapping when clipped
35495 this.headers.setWidth(totalWidth);
35496 //this.innerCt.setWidth(totalWidth);
35497 this.innerCt.setStyle({ overflow: 'auto' });
35498 this.onResize(this.width, this.height);
35502 onResize : function(w,h)
35507 this.innerCt.setWidth(this.width);
35508 this.innerCt.setHeight(this.height-20);
35511 var cols = this.columns, c;
35512 var totalWidth = 0;
35514 var len = cols.length;
35515 for(var i = 0; i < len; i++){
35517 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35518 // it's the expander..
35519 expEl = this.headEls[i];
35522 totalWidth += c.width;
35526 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35528 this.headers.setWidth(w-20);
35537 * Ext JS Library 1.1.1
35538 * Copyright(c) 2006-2007, Ext JS, LLC.
35540 * Originally Released Under LGPL - original licence link has changed is not relivant.
35543 * <script type="text/javascript">
35547 * @class Roo.menu.Menu
35548 * @extends Roo.util.Observable
35549 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35550 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35552 * Creates a new Menu
35553 * @param {Object} config Configuration options
35555 Roo.menu.Menu = function(config){
35556 Roo.apply(this, config);
35557 this.id = this.id || Roo.id();
35560 * @event beforeshow
35561 * Fires before this menu is displayed
35562 * @param {Roo.menu.Menu} this
35566 * @event beforehide
35567 * Fires before this menu is hidden
35568 * @param {Roo.menu.Menu} this
35573 * Fires after this menu is displayed
35574 * @param {Roo.menu.Menu} this
35579 * Fires after this menu is hidden
35580 * @param {Roo.menu.Menu} this
35585 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35586 * @param {Roo.menu.Menu} this
35587 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35588 * @param {Roo.EventObject} e
35593 * Fires when the mouse is hovering over this menu
35594 * @param {Roo.menu.Menu} this
35595 * @param {Roo.EventObject} e
35596 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35601 * Fires when the mouse exits this menu
35602 * @param {Roo.menu.Menu} this
35603 * @param {Roo.EventObject} e
35604 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35609 * Fires when a menu item contained in this menu is clicked
35610 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35611 * @param {Roo.EventObject} e
35615 if (this.registerMenu) {
35616 Roo.menu.MenuMgr.register(this);
35619 var mis = this.items;
35620 this.items = new Roo.util.MixedCollection();
35622 this.add.apply(this, mis);
35626 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35628 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35632 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35633 * for bottom-right shadow (defaults to "sides")
35637 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35638 * this menu (defaults to "tl-tr?")
35640 subMenuAlign : "tl-tr?",
35642 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35643 * relative to its element of origin (defaults to "tl-bl?")
35645 defaultAlign : "tl-bl?",
35647 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35649 allowOtherMenus : false,
35651 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35653 registerMenu : true,
35658 render : function(){
35662 var el = this.el = new Roo.Layer({
35664 shadow:this.shadow,
35666 parentEl: this.parentEl || document.body,
35670 this.keyNav = new Roo.menu.MenuNav(this);
35673 el.addClass("x-menu-plain");
35676 el.addClass(this.cls);
35678 // generic focus element
35679 this.focusEl = el.createChild({
35680 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35682 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35683 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35685 ul.on("mouseover", this.onMouseOver, this);
35686 ul.on("mouseout", this.onMouseOut, this);
35687 this.items.each(function(item){
35692 var li = document.createElement("li");
35693 li.className = "x-menu-list-item";
35694 ul.dom.appendChild(li);
35695 item.render(li, this);
35702 autoWidth : function(){
35703 var el = this.el, ul = this.ul;
35707 var w = this.width;
35710 }else if(Roo.isIE){
35711 el.setWidth(this.minWidth);
35712 var t = el.dom.offsetWidth; // force recalc
35713 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35718 delayAutoWidth : function(){
35721 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35723 this.awTask.delay(20);
35728 findTargetItem : function(e){
35729 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35730 if(t && t.menuItemId){
35731 return this.items.get(t.menuItemId);
35736 onClick : function(e){
35737 Roo.log("menu.onClick");
35738 var t = this.findTargetItem(e);
35743 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35744 if(t == this.activeItem && t.shouldDeactivate(e)){
35745 this.activeItem.deactivate();
35746 delete this.activeItem;
35750 this.setActiveItem(t, true);
35758 this.fireEvent("click", this, t, e);
35762 setActiveItem : function(item, autoExpand){
35763 if(item != this.activeItem){
35764 if(this.activeItem){
35765 this.activeItem.deactivate();
35767 this.activeItem = item;
35768 item.activate(autoExpand);
35769 }else if(autoExpand){
35775 tryActivate : function(start, step){
35776 var items = this.items;
35777 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35778 var item = items.get(i);
35779 if(!item.disabled && item.canActivate){
35780 this.setActiveItem(item, false);
35788 onMouseOver : function(e){
35790 if(t = this.findTargetItem(e)){
35791 if(t.canActivate && !t.disabled){
35792 this.setActiveItem(t, true);
35795 this.fireEvent("mouseover", this, e, t);
35799 onMouseOut : function(e){
35801 if(t = this.findTargetItem(e)){
35802 if(t == this.activeItem && t.shouldDeactivate(e)){
35803 this.activeItem.deactivate();
35804 delete this.activeItem;
35807 this.fireEvent("mouseout", this, e, t);
35811 * Read-only. Returns true if the menu is currently displayed, else false.
35814 isVisible : function(){
35815 return this.el && !this.hidden;
35819 * Displays this menu relative to another element
35820 * @param {String/HTMLElement/Roo.Element} element The element to align to
35821 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35822 * the element (defaults to this.defaultAlign)
35823 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35825 show : function(el, pos, parentMenu){
35826 this.parentMenu = parentMenu;
35830 this.fireEvent("beforeshow", this);
35831 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35835 * Displays this menu at a specific xy position
35836 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35837 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35839 showAt : function(xy, parentMenu, /* private: */_e){
35840 this.parentMenu = parentMenu;
35845 this.fireEvent("beforeshow", this);
35846 xy = this.el.adjustForConstraints(xy);
35850 this.hidden = false;
35852 this.fireEvent("show", this);
35855 focus : function(){
35857 this.doFocus.defer(50, this);
35861 doFocus : function(){
35863 this.focusEl.focus();
35868 * Hides this menu and optionally all parent menus
35869 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35871 hide : function(deep){
35872 if(this.el && this.isVisible()){
35873 this.fireEvent("beforehide", this);
35874 if(this.activeItem){
35875 this.activeItem.deactivate();
35876 this.activeItem = null;
35879 this.hidden = true;
35880 this.fireEvent("hide", this);
35882 if(deep === true && this.parentMenu){
35883 this.parentMenu.hide(true);
35888 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35889 * Any of the following are valid:
35891 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35892 * <li>An HTMLElement object which will be converted to a menu item</li>
35893 * <li>A menu item config object that will be created as a new menu item</li>
35894 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35895 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35900 var menu = new Roo.menu.Menu();
35902 // Create a menu item to add by reference
35903 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35905 // Add a bunch of items at once using different methods.
35906 // Only the last item added will be returned.
35907 var item = menu.add(
35908 menuItem, // add existing item by ref
35909 'Dynamic Item', // new TextItem
35910 '-', // new separator
35911 { text: 'Config Item' } // new item by config
35914 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35915 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35918 var a = arguments, l = a.length, item;
35919 for(var i = 0; i < l; i++){
35921 if ((typeof(el) == "object") && el.xtype && el.xns) {
35922 el = Roo.factory(el, Roo.menu);
35925 if(el.render){ // some kind of Item
35926 item = this.addItem(el);
35927 }else if(typeof el == "string"){ // string
35928 if(el == "separator" || el == "-"){
35929 item = this.addSeparator();
35931 item = this.addText(el);
35933 }else if(el.tagName || el.el){ // element
35934 item = this.addElement(el);
35935 }else if(typeof el == "object"){ // must be menu item config?
35936 item = this.addMenuItem(el);
35943 * Returns this menu's underlying {@link Roo.Element} object
35944 * @return {Roo.Element} The element
35946 getEl : function(){
35954 * Adds a separator bar to the menu
35955 * @return {Roo.menu.Item} The menu item that was added
35957 addSeparator : function(){
35958 return this.addItem(new Roo.menu.Separator());
35962 * Adds an {@link Roo.Element} object to the menu
35963 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35964 * @return {Roo.menu.Item} The menu item that was added
35966 addElement : function(el){
35967 return this.addItem(new Roo.menu.BaseItem(el));
35971 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35972 * @param {Roo.menu.Item} item The menu item to add
35973 * @return {Roo.menu.Item} The menu item that was added
35975 addItem : function(item){
35976 this.items.add(item);
35978 var li = document.createElement("li");
35979 li.className = "x-menu-list-item";
35980 this.ul.dom.appendChild(li);
35981 item.render(li, this);
35982 this.delayAutoWidth();
35988 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35989 * @param {Object} config A MenuItem config object
35990 * @return {Roo.menu.Item} The menu item that was added
35992 addMenuItem : function(config){
35993 if(!(config instanceof Roo.menu.Item)){
35994 if(typeof config.checked == "boolean"){ // must be check menu item config?
35995 config = new Roo.menu.CheckItem(config);
35997 config = new Roo.menu.Item(config);
36000 return this.addItem(config);
36004 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36005 * @param {String} text The text to display in the menu item
36006 * @return {Roo.menu.Item} The menu item that was added
36008 addText : function(text){
36009 return this.addItem(new Roo.menu.TextItem({ text : text }));
36013 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36014 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36015 * @param {Roo.menu.Item} item The menu item to add
36016 * @return {Roo.menu.Item} The menu item that was added
36018 insert : function(index, item){
36019 this.items.insert(index, item);
36021 var li = document.createElement("li");
36022 li.className = "x-menu-list-item";
36023 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36024 item.render(li, this);
36025 this.delayAutoWidth();
36031 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36032 * @param {Roo.menu.Item} item The menu item to remove
36034 remove : function(item){
36035 this.items.removeKey(item.id);
36040 * Removes and destroys all items in the menu
36042 removeAll : function(){
36044 while(f = this.items.first()){
36050 // MenuNav is a private utility class used internally by the Menu
36051 Roo.menu.MenuNav = function(menu){
36052 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36053 this.scope = this.menu = menu;
36056 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36057 doRelay : function(e, h){
36058 var k = e.getKey();
36059 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36060 this.menu.tryActivate(0, 1);
36063 return h.call(this.scope || this, e, this.menu);
36066 up : function(e, m){
36067 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36068 m.tryActivate(m.items.length-1, -1);
36072 down : function(e, m){
36073 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36074 m.tryActivate(0, 1);
36078 right : function(e, m){
36080 m.activeItem.expandMenu(true);
36084 left : function(e, m){
36086 if(m.parentMenu && m.parentMenu.activeItem){
36087 m.parentMenu.activeItem.activate();
36091 enter : function(e, m){
36093 e.stopPropagation();
36094 m.activeItem.onClick(e);
36095 m.fireEvent("click", this, m.activeItem);
36101 * Ext JS Library 1.1.1
36102 * Copyright(c) 2006-2007, Ext JS, LLC.
36104 * Originally Released Under LGPL - original licence link has changed is not relivant.
36107 * <script type="text/javascript">
36111 * @class Roo.menu.MenuMgr
36112 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36115 Roo.menu.MenuMgr = function(){
36116 var menus, active, groups = {}, attached = false, lastShow = new Date();
36118 // private - called when first menu is created
36121 active = new Roo.util.MixedCollection();
36122 Roo.get(document).addKeyListener(27, function(){
36123 if(active.length > 0){
36130 function hideAll(){
36131 if(active && active.length > 0){
36132 var c = active.clone();
36133 c.each(function(m){
36140 function onHide(m){
36142 if(active.length < 1){
36143 Roo.get(document).un("mousedown", onMouseDown);
36149 function onShow(m){
36150 var last = active.last();
36151 lastShow = new Date();
36154 Roo.get(document).on("mousedown", onMouseDown);
36158 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36159 m.parentMenu.activeChild = m;
36160 }else if(last && last.isVisible()){
36161 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36166 function onBeforeHide(m){
36168 m.activeChild.hide();
36170 if(m.autoHideTimer){
36171 clearTimeout(m.autoHideTimer);
36172 delete m.autoHideTimer;
36177 function onBeforeShow(m){
36178 var pm = m.parentMenu;
36179 if(!pm && !m.allowOtherMenus){
36181 }else if(pm && pm.activeChild && active != m){
36182 pm.activeChild.hide();
36187 function onMouseDown(e){
36188 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36194 function onBeforeCheck(mi, state){
36196 var g = groups[mi.group];
36197 for(var i = 0, l = g.length; i < l; i++){
36199 g[i].setChecked(false);
36208 * Hides all menus that are currently visible
36210 hideAll : function(){
36215 register : function(menu){
36219 menus[menu.id] = menu;
36220 menu.on("beforehide", onBeforeHide);
36221 menu.on("hide", onHide);
36222 menu.on("beforeshow", onBeforeShow);
36223 menu.on("show", onShow);
36224 var g = menu.group;
36225 if(g && menu.events["checkchange"]){
36229 groups[g].push(menu);
36230 menu.on("checkchange", onCheck);
36235 * Returns a {@link Roo.menu.Menu} object
36236 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36237 * be used to generate and return a new Menu instance.
36239 get : function(menu){
36240 if(typeof menu == "string"){ // menu id
36241 return menus[menu];
36242 }else if(menu.events){ // menu instance
36244 }else if(typeof menu.length == 'number'){ // array of menu items?
36245 return new Roo.menu.Menu({items:menu});
36246 }else{ // otherwise, must be a config
36247 return new Roo.menu.Menu(menu);
36252 unregister : function(menu){
36253 delete menus[menu.id];
36254 menu.un("beforehide", onBeforeHide);
36255 menu.un("hide", onHide);
36256 menu.un("beforeshow", onBeforeShow);
36257 menu.un("show", onShow);
36258 var g = menu.group;
36259 if(g && menu.events["checkchange"]){
36260 groups[g].remove(menu);
36261 menu.un("checkchange", onCheck);
36266 registerCheckable : function(menuItem){
36267 var g = menuItem.group;
36272 groups[g].push(menuItem);
36273 menuItem.on("beforecheckchange", onBeforeCheck);
36278 unregisterCheckable : function(menuItem){
36279 var g = menuItem.group;
36281 groups[g].remove(menuItem);
36282 menuItem.un("beforecheckchange", onBeforeCheck);
36288 * Ext JS Library 1.1.1
36289 * Copyright(c) 2006-2007, Ext JS, LLC.
36291 * Originally Released Under LGPL - original licence link has changed is not relivant.
36294 * <script type="text/javascript">
36299 * @class Roo.menu.BaseItem
36300 * @extends Roo.Component
36301 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36302 * management and base configuration options shared by all menu components.
36304 * Creates a new BaseItem
36305 * @param {Object} config Configuration options
36307 Roo.menu.BaseItem = function(config){
36308 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36313 * Fires when this item is clicked
36314 * @param {Roo.menu.BaseItem} this
36315 * @param {Roo.EventObject} e
36320 * Fires when this item is activated
36321 * @param {Roo.menu.BaseItem} this
36325 * @event deactivate
36326 * Fires when this item is deactivated
36327 * @param {Roo.menu.BaseItem} this
36333 this.on("click", this.handler, this.scope, true);
36337 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36339 * @cfg {Function} handler
36340 * A function that will handle the click event of this menu item (defaults to undefined)
36343 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36345 canActivate : false,
36348 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36353 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36355 activeClass : "x-menu-item-active",
36357 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36359 hideOnClick : true,
36361 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36366 ctype: "Roo.menu.BaseItem",
36369 actionMode : "container",
36372 render : function(container, parentMenu){
36373 this.parentMenu = parentMenu;
36374 Roo.menu.BaseItem.superclass.render.call(this, container);
36375 this.container.menuItemId = this.id;
36379 onRender : function(container, position){
36380 this.el = Roo.get(this.el);
36381 container.dom.appendChild(this.el.dom);
36385 onClick : function(e){
36386 if(!this.disabled && this.fireEvent("click", this, e) !== false
36387 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36388 this.handleClick(e);
36395 activate : function(){
36399 var li = this.container;
36400 li.addClass(this.activeClass);
36401 this.region = li.getRegion().adjust(2, 2, -2, -2);
36402 this.fireEvent("activate", this);
36407 deactivate : function(){
36408 this.container.removeClass(this.activeClass);
36409 this.fireEvent("deactivate", this);
36413 shouldDeactivate : function(e){
36414 return !this.region || !this.region.contains(e.getPoint());
36418 handleClick : function(e){
36419 if(this.hideOnClick){
36420 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36425 expandMenu : function(autoActivate){
36430 hideMenu : function(){
36435 * Ext JS Library 1.1.1
36436 * Copyright(c) 2006-2007, Ext JS, LLC.
36438 * Originally Released Under LGPL - original licence link has changed is not relivant.
36441 * <script type="text/javascript">
36445 * @class Roo.menu.Adapter
36446 * @extends Roo.menu.BaseItem
36447 * 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.
36448 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36450 * Creates a new Adapter
36451 * @param {Object} config Configuration options
36453 Roo.menu.Adapter = function(component, config){
36454 Roo.menu.Adapter.superclass.constructor.call(this, config);
36455 this.component = component;
36457 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36459 canActivate : true,
36462 onRender : function(container, position){
36463 this.component.render(container);
36464 this.el = this.component.getEl();
36468 activate : function(){
36472 this.component.focus();
36473 this.fireEvent("activate", this);
36478 deactivate : function(){
36479 this.fireEvent("deactivate", this);
36483 disable : function(){
36484 this.component.disable();
36485 Roo.menu.Adapter.superclass.disable.call(this);
36489 enable : function(){
36490 this.component.enable();
36491 Roo.menu.Adapter.superclass.enable.call(this);
36495 * Ext JS Library 1.1.1
36496 * Copyright(c) 2006-2007, Ext JS, LLC.
36498 * Originally Released Under LGPL - original licence link has changed is not relivant.
36501 * <script type="text/javascript">
36505 * @class Roo.menu.TextItem
36506 * @extends Roo.menu.BaseItem
36507 * Adds a static text string to a menu, usually used as either a heading or group separator.
36508 * Note: old style constructor with text is still supported.
36511 * Creates a new TextItem
36512 * @param {Object} cfg Configuration
36514 Roo.menu.TextItem = function(cfg){
36515 if (typeof(cfg) == 'string') {
36518 Roo.apply(this,cfg);
36521 Roo.menu.TextItem.superclass.constructor.call(this);
36524 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36526 * @cfg {Boolean} text Text to show on item.
36531 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36533 hideOnClick : false,
36535 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36537 itemCls : "x-menu-text",
36540 onRender : function(){
36541 var s = document.createElement("span");
36542 s.className = this.itemCls;
36543 s.innerHTML = this.text;
36545 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36549 * Ext JS Library 1.1.1
36550 * Copyright(c) 2006-2007, Ext JS, LLC.
36552 * Originally Released Under LGPL - original licence link has changed is not relivant.
36555 * <script type="text/javascript">
36559 * @class Roo.menu.Separator
36560 * @extends Roo.menu.BaseItem
36561 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36562 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36564 * @param {Object} config Configuration options
36566 Roo.menu.Separator = function(config){
36567 Roo.menu.Separator.superclass.constructor.call(this, config);
36570 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36572 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36574 itemCls : "x-menu-sep",
36576 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36578 hideOnClick : false,
36581 onRender : function(li){
36582 var s = document.createElement("span");
36583 s.className = this.itemCls;
36584 s.innerHTML = " ";
36586 li.addClass("x-menu-sep-li");
36587 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36591 * Ext JS Library 1.1.1
36592 * Copyright(c) 2006-2007, Ext JS, LLC.
36594 * Originally Released Under LGPL - original licence link has changed is not relivant.
36597 * <script type="text/javascript">
36600 * @class Roo.menu.Item
36601 * @extends Roo.menu.BaseItem
36602 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36603 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36604 * activation and click handling.
36606 * Creates a new Item
36607 * @param {Object} config Configuration options
36609 Roo.menu.Item = function(config){
36610 Roo.menu.Item.superclass.constructor.call(this, config);
36612 this.menu = Roo.menu.MenuMgr.get(this.menu);
36615 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36618 * @cfg {String} text
36619 * The text to show on the menu item.
36623 * @cfg {String} HTML to render in menu
36624 * The text to show on the menu item (HTML version).
36628 * @cfg {String} icon
36629 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36633 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36635 itemCls : "x-menu-item",
36637 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36639 canActivate : true,
36641 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36644 // doc'd in BaseItem
36648 ctype: "Roo.menu.Item",
36651 onRender : function(container, position){
36652 var el = document.createElement("a");
36653 el.hideFocus = true;
36654 el.unselectable = "on";
36655 el.href = this.href || "#";
36656 if(this.hrefTarget){
36657 el.target = this.hrefTarget;
36659 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36661 var html = this.html.length ? this.html : String.format('{0}',this.text);
36663 el.innerHTML = String.format(
36664 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36665 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36667 Roo.menu.Item.superclass.onRender.call(this, container, position);
36671 * Sets the text to display in this menu item
36672 * @param {String} text The text to display
36673 * @param {Boolean} isHTML true to indicate text is pure html.
36675 setText : function(text, isHTML){
36683 var html = this.html.length ? this.html : String.format('{0}',this.text);
36685 this.el.update(String.format(
36686 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36687 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36688 this.parentMenu.autoWidth();
36693 handleClick : function(e){
36694 if(!this.href){ // if no link defined, stop the event automatically
36697 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36701 activate : function(autoExpand){
36702 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36712 shouldDeactivate : function(e){
36713 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36714 if(this.menu && this.menu.isVisible()){
36715 return !this.menu.getEl().getRegion().contains(e.getPoint());
36723 deactivate : function(){
36724 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36729 expandMenu : function(autoActivate){
36730 if(!this.disabled && this.menu){
36731 clearTimeout(this.hideTimer);
36732 delete this.hideTimer;
36733 if(!this.menu.isVisible() && !this.showTimer){
36734 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36735 }else if (this.menu.isVisible() && autoActivate){
36736 this.menu.tryActivate(0, 1);
36742 deferExpand : function(autoActivate){
36743 delete this.showTimer;
36744 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36746 this.menu.tryActivate(0, 1);
36751 hideMenu : function(){
36752 clearTimeout(this.showTimer);
36753 delete this.showTimer;
36754 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36755 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36760 deferHide : function(){
36761 delete this.hideTimer;
36766 * Ext JS Library 1.1.1
36767 * Copyright(c) 2006-2007, Ext JS, LLC.
36769 * Originally Released Under LGPL - original licence link has changed is not relivant.
36772 * <script type="text/javascript">
36776 * @class Roo.menu.CheckItem
36777 * @extends Roo.menu.Item
36778 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36780 * Creates a new CheckItem
36781 * @param {Object} config Configuration options
36783 Roo.menu.CheckItem = function(config){
36784 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36787 * @event beforecheckchange
36788 * Fires before the checked value is set, providing an opportunity to cancel if needed
36789 * @param {Roo.menu.CheckItem} this
36790 * @param {Boolean} checked The new checked value that will be set
36792 "beforecheckchange" : true,
36794 * @event checkchange
36795 * Fires after the checked value has been set
36796 * @param {Roo.menu.CheckItem} this
36797 * @param {Boolean} checked The checked value that was set
36799 "checkchange" : true
36801 if(this.checkHandler){
36802 this.on('checkchange', this.checkHandler, this.scope);
36805 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36807 * @cfg {String} group
36808 * All check items with the same group name will automatically be grouped into a single-select
36809 * radio button group (defaults to '')
36812 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36814 itemCls : "x-menu-item x-menu-check-item",
36816 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36818 groupClass : "x-menu-group-item",
36821 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36822 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36823 * initialized with checked = true will be rendered as checked.
36828 ctype: "Roo.menu.CheckItem",
36831 onRender : function(c){
36832 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36834 this.el.addClass(this.groupClass);
36836 Roo.menu.MenuMgr.registerCheckable(this);
36838 this.checked = false;
36839 this.setChecked(true, true);
36844 destroy : function(){
36846 Roo.menu.MenuMgr.unregisterCheckable(this);
36848 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36852 * Set the checked state of this item
36853 * @param {Boolean} checked The new checked value
36854 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36856 setChecked : function(state, suppressEvent){
36857 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36858 if(this.container){
36859 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36861 this.checked = state;
36862 if(suppressEvent !== true){
36863 this.fireEvent("checkchange", this, state);
36869 handleClick : function(e){
36870 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36871 this.setChecked(!this.checked);
36873 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36877 * Ext JS Library 1.1.1
36878 * Copyright(c) 2006-2007, Ext JS, LLC.
36880 * Originally Released Under LGPL - original licence link has changed is not relivant.
36883 * <script type="text/javascript">
36887 * @class Roo.menu.DateItem
36888 * @extends Roo.menu.Adapter
36889 * A menu item that wraps the {@link Roo.DatPicker} component.
36891 * Creates a new DateItem
36892 * @param {Object} config Configuration options
36894 Roo.menu.DateItem = function(config){
36895 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36896 /** The Roo.DatePicker object @type Roo.DatePicker */
36897 this.picker = this.component;
36898 this.addEvents({select: true});
36900 this.picker.on("render", function(picker){
36901 picker.getEl().swallowEvent("click");
36902 picker.container.addClass("x-menu-date-item");
36905 this.picker.on("select", this.onSelect, this);
36908 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36910 onSelect : function(picker, date){
36911 this.fireEvent("select", this, date, picker);
36912 Roo.menu.DateItem.superclass.handleClick.call(this);
36916 * Ext JS Library 1.1.1
36917 * Copyright(c) 2006-2007, Ext JS, LLC.
36919 * Originally Released Under LGPL - original licence link has changed is not relivant.
36922 * <script type="text/javascript">
36926 * @class Roo.menu.ColorItem
36927 * @extends Roo.menu.Adapter
36928 * A menu item that wraps the {@link Roo.ColorPalette} component.
36930 * Creates a new ColorItem
36931 * @param {Object} config Configuration options
36933 Roo.menu.ColorItem = function(config){
36934 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36935 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36936 this.palette = this.component;
36937 this.relayEvents(this.palette, ["select"]);
36938 if(this.selectHandler){
36939 this.on('select', this.selectHandler, this.scope);
36942 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36944 * Ext JS Library 1.1.1
36945 * Copyright(c) 2006-2007, Ext JS, LLC.
36947 * Originally Released Under LGPL - original licence link has changed is not relivant.
36950 * <script type="text/javascript">
36955 * @class Roo.menu.DateMenu
36956 * @extends Roo.menu.Menu
36957 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36959 * Creates a new DateMenu
36960 * @param {Object} config Configuration options
36962 Roo.menu.DateMenu = function(config){
36963 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36965 var di = new Roo.menu.DateItem(config);
36968 * The {@link Roo.DatePicker} instance for this DateMenu
36971 this.picker = di.picker;
36974 * @param {DatePicker} picker
36975 * @param {Date} date
36977 this.relayEvents(di, ["select"]);
36978 this.on('beforeshow', function(){
36980 this.picker.hideMonthPicker(false);
36984 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36988 * Ext JS Library 1.1.1
36989 * Copyright(c) 2006-2007, Ext JS, LLC.
36991 * Originally Released Under LGPL - original licence link has changed is not relivant.
36994 * <script type="text/javascript">
36999 * @class Roo.menu.ColorMenu
37000 * @extends Roo.menu.Menu
37001 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37003 * Creates a new ColorMenu
37004 * @param {Object} config Configuration options
37006 Roo.menu.ColorMenu = function(config){
37007 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37009 var ci = new Roo.menu.ColorItem(config);
37012 * The {@link Roo.ColorPalette} instance for this ColorMenu
37013 * @type ColorPalette
37015 this.palette = ci.palette;
37018 * @param {ColorPalette} palette
37019 * @param {String} color
37021 this.relayEvents(ci, ["select"]);
37023 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37025 * Ext JS Library 1.1.1
37026 * Copyright(c) 2006-2007, Ext JS, LLC.
37028 * Originally Released Under LGPL - original licence link has changed is not relivant.
37031 * <script type="text/javascript">
37035 * @class Roo.form.Field
37036 * @extends Roo.BoxComponent
37037 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37039 * Creates a new Field
37040 * @param {Object} config Configuration options
37042 Roo.form.Field = function(config){
37043 Roo.form.Field.superclass.constructor.call(this, config);
37046 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37048 * @cfg {String} fieldLabel Label to use when rendering a form.
37051 * @cfg {String} qtip Mouse over tip
37055 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37057 invalidClass : "x-form-invalid",
37059 * @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")
37061 invalidText : "The value in this field is invalid",
37063 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37065 focusClass : "x-form-focus",
37067 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37068 automatic validation (defaults to "keyup").
37070 validationEvent : "keyup",
37072 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37074 validateOnBlur : true,
37076 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37078 validationDelay : 250,
37080 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37081 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37083 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37085 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37087 fieldClass : "x-form-field",
37089 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37092 ----------- ----------------------------------------------------------------------
37093 qtip Display a quick tip when the user hovers over the field
37094 title Display a default browser title attribute popup
37095 under Add a block div beneath the field containing the error text
37096 side Add an error icon to the right of the field with a popup on hover
37097 [element id] Add the error text directly to the innerHTML of the specified element
37100 msgTarget : 'qtip',
37102 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37107 * @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.
37112 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37117 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37119 inputType : undefined,
37122 * @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).
37124 tabIndex : undefined,
37127 isFormField : true,
37132 * @property {Roo.Element} fieldEl
37133 * Element Containing the rendered Field (with label etc.)
37136 * @cfg {Mixed} value A value to initialize this field with.
37141 * @cfg {String} name The field's HTML name attribute.
37144 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37148 initComponent : function(){
37149 Roo.form.Field.superclass.initComponent.call(this);
37153 * Fires when this field receives input focus.
37154 * @param {Roo.form.Field} this
37159 * Fires when this field loses input focus.
37160 * @param {Roo.form.Field} this
37164 * @event specialkey
37165 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37166 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37167 * @param {Roo.form.Field} this
37168 * @param {Roo.EventObject} e The event object
37173 * Fires just before the field blurs if the field value has changed.
37174 * @param {Roo.form.Field} this
37175 * @param {Mixed} newValue The new value
37176 * @param {Mixed} oldValue The original value
37181 * Fires after the field has been marked as invalid.
37182 * @param {Roo.form.Field} this
37183 * @param {String} msg The validation message
37188 * Fires after the field has been validated with no errors.
37189 * @param {Roo.form.Field} this
37194 * Fires after the key up
37195 * @param {Roo.form.Field} this
37196 * @param {Roo.EventObject} e The event Object
37203 * Returns the name attribute of the field if available
37204 * @return {String} name The field name
37206 getName: function(){
37207 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37211 onRender : function(ct, position){
37212 Roo.form.Field.superclass.onRender.call(this, ct, position);
37214 var cfg = this.getAutoCreate();
37216 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37218 if (!cfg.name.length) {
37221 if(this.inputType){
37222 cfg.type = this.inputType;
37224 this.el = ct.createChild(cfg, position);
37226 var type = this.el.dom.type;
37228 if(type == 'password'){
37231 this.el.addClass('x-form-'+type);
37234 this.el.dom.readOnly = true;
37236 if(this.tabIndex !== undefined){
37237 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37240 this.el.addClass([this.fieldClass, this.cls]);
37245 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37246 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37247 * @return {Roo.form.Field} this
37249 applyTo : function(target){
37250 this.allowDomMove = false;
37251 this.el = Roo.get(target);
37252 this.render(this.el.dom.parentNode);
37257 initValue : function(){
37258 if(this.value !== undefined){
37259 this.setValue(this.value);
37260 }else if(this.el.dom.value.length > 0){
37261 this.setValue(this.el.dom.value);
37266 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37268 isDirty : function() {
37269 if(this.disabled) {
37272 return String(this.getValue()) !== String(this.originalValue);
37276 afterRender : function(){
37277 Roo.form.Field.superclass.afterRender.call(this);
37282 fireKey : function(e){
37283 //Roo.log('field ' + e.getKey());
37284 if(e.isNavKeyPress()){
37285 this.fireEvent("specialkey", this, e);
37290 * Resets the current field value to the originally loaded value and clears any validation messages
37292 reset : function(){
37293 this.setValue(this.resetValue);
37294 this.clearInvalid();
37298 initEvents : function(){
37299 // safari killled keypress - so keydown is now used..
37300 this.el.on("keydown" , this.fireKey, this);
37301 this.el.on("focus", this.onFocus, this);
37302 this.el.on("blur", this.onBlur, this);
37303 this.el.relayEvent('keyup', this);
37305 // reference to original value for reset
37306 this.originalValue = this.getValue();
37307 this.resetValue = this.getValue();
37311 onFocus : function(){
37312 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37313 this.el.addClass(this.focusClass);
37315 if(!this.hasFocus){
37316 this.hasFocus = true;
37317 this.startValue = this.getValue();
37318 this.fireEvent("focus", this);
37322 beforeBlur : Roo.emptyFn,
37325 onBlur : function(){
37327 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37328 this.el.removeClass(this.focusClass);
37330 this.hasFocus = false;
37331 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37334 var v = this.getValue();
37335 if(String(v) !== String(this.startValue)){
37336 this.fireEvent('change', this, v, this.startValue);
37338 this.fireEvent("blur", this);
37342 * Returns whether or not the field value is currently valid
37343 * @param {Boolean} preventMark True to disable marking the field invalid
37344 * @return {Boolean} True if the value is valid, else false
37346 isValid : function(preventMark){
37350 var restore = this.preventMark;
37351 this.preventMark = preventMark === true;
37352 var v = this.validateValue(this.processValue(this.getRawValue()));
37353 this.preventMark = restore;
37358 * Validates the field value
37359 * @return {Boolean} True if the value is valid, else false
37361 validate : function(){
37362 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37363 this.clearInvalid();
37369 processValue : function(value){
37374 // Subclasses should provide the validation implementation by overriding this
37375 validateValue : function(value){
37380 * Mark this field as invalid
37381 * @param {String} msg The validation message
37383 markInvalid : function(msg){
37384 if(!this.rendered || this.preventMark){ // not rendered
37388 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37390 obj.el.addClass(this.invalidClass);
37391 msg = msg || this.invalidText;
37392 switch(this.msgTarget){
37394 obj.el.dom.qtip = msg;
37395 obj.el.dom.qclass = 'x-form-invalid-tip';
37396 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37397 Roo.QuickTips.enable();
37401 this.el.dom.title = msg;
37405 var elp = this.el.findParent('.x-form-element', 5, true);
37406 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37407 this.errorEl.setWidth(elp.getWidth(true)-20);
37409 this.errorEl.update(msg);
37410 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37413 if(!this.errorIcon){
37414 var elp = this.el.findParent('.x-form-element', 5, true);
37415 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37417 this.alignErrorIcon();
37418 this.errorIcon.dom.qtip = msg;
37419 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37420 this.errorIcon.show();
37421 this.on('resize', this.alignErrorIcon, this);
37424 var t = Roo.getDom(this.msgTarget);
37426 t.style.display = this.msgDisplay;
37429 this.fireEvent('invalid', this, msg);
37433 alignErrorIcon : function(){
37434 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37438 * Clear any invalid styles/messages for this field
37440 clearInvalid : function(){
37441 if(!this.rendered || this.preventMark){ // not rendered
37444 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37446 obj.el.removeClass(this.invalidClass);
37447 switch(this.msgTarget){
37449 obj.el.dom.qtip = '';
37452 this.el.dom.title = '';
37456 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37460 if(this.errorIcon){
37461 this.errorIcon.dom.qtip = '';
37462 this.errorIcon.hide();
37463 this.un('resize', this.alignErrorIcon, this);
37467 var t = Roo.getDom(this.msgTarget);
37469 t.style.display = 'none';
37472 this.fireEvent('valid', this);
37476 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37477 * @return {Mixed} value The field value
37479 getRawValue : function(){
37480 var v = this.el.getValue();
37486 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37487 * @return {Mixed} value The field value
37489 getValue : function(){
37490 var v = this.el.getValue();
37496 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37497 * @param {Mixed} value The value to set
37499 setRawValue : function(v){
37500 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37504 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37505 * @param {Mixed} value The value to set
37507 setValue : function(v){
37510 this.el.dom.value = (v === null || v === undefined ? '' : v);
37515 adjustSize : function(w, h){
37516 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37517 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37521 adjustWidth : function(tag, w){
37522 tag = tag.toLowerCase();
37523 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37524 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37525 if(tag == 'input'){
37528 if(tag == 'textarea'){
37531 }else if(Roo.isOpera){
37532 if(tag == 'input'){
37535 if(tag == 'textarea'){
37545 // anything other than normal should be considered experimental
37546 Roo.form.Field.msgFx = {
37548 show: function(msgEl, f){
37549 msgEl.setDisplayed('block');
37552 hide : function(msgEl, f){
37553 msgEl.setDisplayed(false).update('');
37558 show: function(msgEl, f){
37559 msgEl.slideIn('t', {stopFx:true});
37562 hide : function(msgEl, f){
37563 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37568 show: function(msgEl, f){
37569 msgEl.fixDisplay();
37570 msgEl.alignTo(f.el, 'tl-tr');
37571 msgEl.slideIn('l', {stopFx:true});
37574 hide : function(msgEl, f){
37575 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37580 * Ext JS Library 1.1.1
37581 * Copyright(c) 2006-2007, Ext JS, LLC.
37583 * Originally Released Under LGPL - original licence link has changed is not relivant.
37586 * <script type="text/javascript">
37591 * @class Roo.form.TextField
37592 * @extends Roo.form.Field
37593 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37594 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37596 * Creates a new TextField
37597 * @param {Object} config Configuration options
37599 Roo.form.TextField = function(config){
37600 Roo.form.TextField.superclass.constructor.call(this, config);
37604 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37605 * according to the default logic, but this event provides a hook for the developer to apply additional
37606 * logic at runtime to resize the field if needed.
37607 * @param {Roo.form.Field} this This text field
37608 * @param {Number} width The new field width
37614 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37616 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37620 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37624 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37628 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37632 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37636 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37638 disableKeyFilter : false,
37640 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37644 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37648 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37650 maxLength : Number.MAX_VALUE,
37652 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37654 minLengthText : "The minimum length for this field is {0}",
37656 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37658 maxLengthText : "The maximum length for this field is {0}",
37660 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37662 selectOnFocus : false,
37664 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37666 blankText : "This field is required",
37668 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37669 * If available, this function will be called only after the basic validators all return true, and will be passed the
37670 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37674 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37675 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37676 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37680 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37684 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37690 initEvents : function()
37692 if (this.emptyText) {
37693 this.el.attr('placeholder', this.emptyText);
37696 Roo.form.TextField.superclass.initEvents.call(this);
37697 if(this.validationEvent == 'keyup'){
37698 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37699 this.el.on('keyup', this.filterValidation, this);
37701 else if(this.validationEvent !== false){
37702 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37705 if(this.selectOnFocus){
37706 this.on("focus", this.preFocus, this);
37709 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37710 this.el.on("keypress", this.filterKeys, this);
37713 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37714 this.el.on("click", this.autoSize, this);
37716 if(this.el.is('input[type=password]') && Roo.isSafari){
37717 this.el.on('keydown', this.SafariOnKeyDown, this);
37721 processValue : function(value){
37722 if(this.stripCharsRe){
37723 var newValue = value.replace(this.stripCharsRe, '');
37724 if(newValue !== value){
37725 this.setRawValue(newValue);
37732 filterValidation : function(e){
37733 if(!e.isNavKeyPress()){
37734 this.validationTask.delay(this.validationDelay);
37739 onKeyUp : function(e){
37740 if(!e.isNavKeyPress()){
37746 * Resets the current field value to the originally-loaded value and clears any validation messages.
37749 reset : function(){
37750 Roo.form.TextField.superclass.reset.call(this);
37756 preFocus : function(){
37758 if(this.selectOnFocus){
37759 this.el.dom.select();
37765 filterKeys : function(e){
37766 var k = e.getKey();
37767 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37770 var c = e.getCharCode(), cc = String.fromCharCode(c);
37771 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37774 if(!this.maskRe.test(cc)){
37779 setValue : function(v){
37781 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37787 * Validates a value according to the field's validation rules and marks the field as invalid
37788 * if the validation fails
37789 * @param {Mixed} value The value to validate
37790 * @return {Boolean} True if the value is valid, else false
37792 validateValue : function(value){
37793 if(value.length < 1) { // if it's blank
37794 if(this.allowBlank){
37795 this.clearInvalid();
37798 this.markInvalid(this.blankText);
37802 if(value.length < this.minLength){
37803 this.markInvalid(String.format(this.minLengthText, this.minLength));
37806 if(value.length > this.maxLength){
37807 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37811 var vt = Roo.form.VTypes;
37812 if(!vt[this.vtype](value, this)){
37813 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37817 if(typeof this.validator == "function"){
37818 var msg = this.validator(value);
37820 this.markInvalid(msg);
37824 if(this.regex && !this.regex.test(value)){
37825 this.markInvalid(this.regexText);
37832 * Selects text in this field
37833 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37834 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37836 selectText : function(start, end){
37837 var v = this.getRawValue();
37839 start = start === undefined ? 0 : start;
37840 end = end === undefined ? v.length : end;
37841 var d = this.el.dom;
37842 if(d.setSelectionRange){
37843 d.setSelectionRange(start, end);
37844 }else if(d.createTextRange){
37845 var range = d.createTextRange();
37846 range.moveStart("character", start);
37847 range.moveEnd("character", v.length-end);
37854 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37855 * This only takes effect if grow = true, and fires the autosize event.
37857 autoSize : function(){
37858 if(!this.grow || !this.rendered){
37862 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37865 var v = el.dom.value;
37866 var d = document.createElement('div');
37867 d.appendChild(document.createTextNode(v));
37871 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37872 this.el.setWidth(w);
37873 this.fireEvent("autosize", this, w);
37877 SafariOnKeyDown : function(event)
37879 // this is a workaround for a password hang bug on chrome/ webkit.
37881 var isSelectAll = false;
37883 if(this.el.dom.selectionEnd > 0){
37884 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37886 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37887 event.preventDefault();
37892 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37894 event.preventDefault();
37895 // this is very hacky as keydown always get's upper case.
37897 var cc = String.fromCharCode(event.getCharCode());
37900 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37908 * Ext JS Library 1.1.1
37909 * Copyright(c) 2006-2007, Ext JS, LLC.
37911 * Originally Released Under LGPL - original licence link has changed is not relivant.
37914 * <script type="text/javascript">
37918 * @class Roo.form.Hidden
37919 * @extends Roo.form.TextField
37920 * Simple Hidden element used on forms
37922 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37925 * Creates a new Hidden form element.
37926 * @param {Object} config Configuration options
37931 // easy hidden field...
37932 Roo.form.Hidden = function(config){
37933 Roo.form.Hidden.superclass.constructor.call(this, config);
37936 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37938 inputType: 'hidden',
37941 labelSeparator: '',
37943 itemCls : 'x-form-item-display-none'
37951 * Ext JS Library 1.1.1
37952 * Copyright(c) 2006-2007, Ext JS, LLC.
37954 * Originally Released Under LGPL - original licence link has changed is not relivant.
37957 * <script type="text/javascript">
37961 * @class Roo.form.TriggerField
37962 * @extends Roo.form.TextField
37963 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37964 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37965 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37966 * for which you can provide a custom implementation. For example:
37968 var trigger = new Roo.form.TriggerField();
37969 trigger.onTriggerClick = myTriggerFn;
37970 trigger.applyTo('my-field');
37973 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37974 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37975 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37976 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37978 * Create a new TriggerField.
37979 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37980 * to the base TextField)
37982 Roo.form.TriggerField = function(config){
37983 this.mimicing = false;
37984 Roo.form.TriggerField.superclass.constructor.call(this, config);
37987 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37989 * @cfg {String} triggerClass A CSS class to apply to the trigger
37992 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37993 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37995 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
37997 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38001 /** @cfg {Boolean} grow @hide */
38002 /** @cfg {Number} growMin @hide */
38003 /** @cfg {Number} growMax @hide */
38009 autoSize: Roo.emptyFn,
38013 deferHeight : true,
38016 actionMode : 'wrap',
38018 onResize : function(w, h){
38019 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38020 if(typeof w == 'number'){
38021 var x = w - this.trigger.getWidth();
38022 this.el.setWidth(this.adjustWidth('input', x));
38023 this.trigger.setStyle('left', x+'px');
38028 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38031 getResizeEl : function(){
38036 getPositionEl : function(){
38041 alignErrorIcon : function(){
38042 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38046 onRender : function(ct, position){
38047 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38048 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38049 this.trigger = this.wrap.createChild(this.triggerConfig ||
38050 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38051 if(this.hideTrigger){
38052 this.trigger.setDisplayed(false);
38054 this.initTrigger();
38056 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38061 initTrigger : function(){
38062 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38063 this.trigger.addClassOnOver('x-form-trigger-over');
38064 this.trigger.addClassOnClick('x-form-trigger-click');
38068 onDestroy : function(){
38070 this.trigger.removeAllListeners();
38071 this.trigger.remove();
38074 this.wrap.remove();
38076 Roo.form.TriggerField.superclass.onDestroy.call(this);
38080 onFocus : function(){
38081 Roo.form.TriggerField.superclass.onFocus.call(this);
38082 if(!this.mimicing){
38083 this.wrap.addClass('x-trigger-wrap-focus');
38084 this.mimicing = true;
38085 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38086 if(this.monitorTab){
38087 this.el.on("keydown", this.checkTab, this);
38093 checkTab : function(e){
38094 if(e.getKey() == e.TAB){
38095 this.triggerBlur();
38100 onBlur : function(){
38105 mimicBlur : function(e, t){
38106 if(!this.wrap.contains(t) && this.validateBlur()){
38107 this.triggerBlur();
38112 triggerBlur : function(){
38113 this.mimicing = false;
38114 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38115 if(this.monitorTab){
38116 this.el.un("keydown", this.checkTab, this);
38118 this.wrap.removeClass('x-trigger-wrap-focus');
38119 Roo.form.TriggerField.superclass.onBlur.call(this);
38123 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38124 validateBlur : function(e, t){
38129 onDisable : function(){
38130 Roo.form.TriggerField.superclass.onDisable.call(this);
38132 this.wrap.addClass('x-item-disabled');
38137 onEnable : function(){
38138 Roo.form.TriggerField.superclass.onEnable.call(this);
38140 this.wrap.removeClass('x-item-disabled');
38145 onShow : function(){
38146 var ae = this.getActionEl();
38149 ae.dom.style.display = '';
38150 ae.dom.style.visibility = 'visible';
38156 onHide : function(){
38157 var ae = this.getActionEl();
38158 ae.dom.style.display = 'none';
38162 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38163 * by an implementing function.
38165 * @param {EventObject} e
38167 onTriggerClick : Roo.emptyFn
38170 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38171 // to be extended by an implementing class. For an example of implementing this class, see the custom
38172 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38173 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38174 initComponent : function(){
38175 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38177 this.triggerConfig = {
38178 tag:'span', cls:'x-form-twin-triggers', cn:[
38179 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38180 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38184 getTrigger : function(index){
38185 return this.triggers[index];
38188 initTrigger : function(){
38189 var ts = this.trigger.select('.x-form-trigger', true);
38190 this.wrap.setStyle('overflow', 'hidden');
38191 var triggerField = this;
38192 ts.each(function(t, all, index){
38193 t.hide = function(){
38194 var w = triggerField.wrap.getWidth();
38195 this.dom.style.display = 'none';
38196 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38198 t.show = function(){
38199 var w = triggerField.wrap.getWidth();
38200 this.dom.style.display = '';
38201 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38203 var triggerIndex = 'Trigger'+(index+1);
38205 if(this['hide'+triggerIndex]){
38206 t.dom.style.display = 'none';
38208 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38209 t.addClassOnOver('x-form-trigger-over');
38210 t.addClassOnClick('x-form-trigger-click');
38212 this.triggers = ts.elements;
38215 onTrigger1Click : Roo.emptyFn,
38216 onTrigger2Click : Roo.emptyFn
38219 * Ext JS Library 1.1.1
38220 * Copyright(c) 2006-2007, Ext JS, LLC.
38222 * Originally Released Under LGPL - original licence link has changed is not relivant.
38225 * <script type="text/javascript">
38229 * @class Roo.form.TextArea
38230 * @extends Roo.form.TextField
38231 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38232 * support for auto-sizing.
38234 * Creates a new TextArea
38235 * @param {Object} config Configuration options
38237 Roo.form.TextArea = function(config){
38238 Roo.form.TextArea.superclass.constructor.call(this, config);
38239 // these are provided exchanges for backwards compat
38240 // minHeight/maxHeight were replaced by growMin/growMax to be
38241 // compatible with TextField growing config values
38242 if(this.minHeight !== undefined){
38243 this.growMin = this.minHeight;
38245 if(this.maxHeight !== undefined){
38246 this.growMax = this.maxHeight;
38250 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38252 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38256 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38260 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38261 * in the field (equivalent to setting overflow: hidden, defaults to false)
38263 preventScrollbars: false,
38265 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38266 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38270 onRender : function(ct, position){
38272 this.defaultAutoCreate = {
38274 style:"width:300px;height:60px;",
38275 autocomplete: "new-password"
38278 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38280 this.textSizeEl = Roo.DomHelper.append(document.body, {
38281 tag: "pre", cls: "x-form-grow-sizer"
38283 if(this.preventScrollbars){
38284 this.el.setStyle("overflow", "hidden");
38286 this.el.setHeight(this.growMin);
38290 onDestroy : function(){
38291 if(this.textSizeEl){
38292 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38294 Roo.form.TextArea.superclass.onDestroy.call(this);
38298 onKeyUp : function(e){
38299 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38305 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38306 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38308 autoSize : function(){
38309 if(!this.grow || !this.textSizeEl){
38313 var v = el.dom.value;
38314 var ts = this.textSizeEl;
38317 ts.appendChild(document.createTextNode(v));
38320 Roo.fly(ts).setWidth(this.el.getWidth());
38322 v = "  ";
38325 v = v.replace(/\n/g, '<p> </p>');
38327 v += " \n ";
38330 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38331 if(h != this.lastHeight){
38332 this.lastHeight = h;
38333 this.el.setHeight(h);
38334 this.fireEvent("autosize", this, h);
38339 * Ext JS Library 1.1.1
38340 * Copyright(c) 2006-2007, Ext JS, LLC.
38342 * Originally Released Under LGPL - original licence link has changed is not relivant.
38345 * <script type="text/javascript">
38350 * @class Roo.form.NumberField
38351 * @extends Roo.form.TextField
38352 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38354 * Creates a new NumberField
38355 * @param {Object} config Configuration options
38357 Roo.form.NumberField = function(config){
38358 Roo.form.NumberField.superclass.constructor.call(this, config);
38361 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38363 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38365 fieldClass: "x-form-field x-form-num-field",
38367 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38369 allowDecimals : true,
38371 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38373 decimalSeparator : ".",
38375 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38377 decimalPrecision : 2,
38379 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38381 allowNegative : true,
38383 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38385 minValue : Number.NEGATIVE_INFINITY,
38387 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38389 maxValue : Number.MAX_VALUE,
38391 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38393 minText : "The minimum value for this field is {0}",
38395 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38397 maxText : "The maximum value for this field is {0}",
38399 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38400 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38402 nanText : "{0} is not a valid number",
38405 initEvents : function(){
38406 Roo.form.NumberField.superclass.initEvents.call(this);
38407 var allowed = "0123456789";
38408 if(this.allowDecimals){
38409 allowed += this.decimalSeparator;
38411 if(this.allowNegative){
38414 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38415 var keyPress = function(e){
38416 var k = e.getKey();
38417 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38420 var c = e.getCharCode();
38421 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38425 this.el.on("keypress", keyPress, this);
38429 validateValue : function(value){
38430 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38433 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38436 var num = this.parseValue(value);
38438 this.markInvalid(String.format(this.nanText, value));
38441 if(num < this.minValue){
38442 this.markInvalid(String.format(this.minText, this.minValue));
38445 if(num > this.maxValue){
38446 this.markInvalid(String.format(this.maxText, this.maxValue));
38452 getValue : function(){
38453 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38457 parseValue : function(value){
38458 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38459 return isNaN(value) ? '' : value;
38463 fixPrecision : function(value){
38464 var nan = isNaN(value);
38465 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38466 return nan ? '' : value;
38468 return parseFloat(value).toFixed(this.decimalPrecision);
38471 setValue : function(v){
38472 v = this.fixPrecision(v);
38473 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38477 decimalPrecisionFcn : function(v){
38478 return Math.floor(v);
38481 beforeBlur : function(){
38482 var v = this.parseValue(this.getRawValue());
38489 * Ext JS Library 1.1.1
38490 * Copyright(c) 2006-2007, Ext JS, LLC.
38492 * Originally Released Under LGPL - original licence link has changed is not relivant.
38495 * <script type="text/javascript">
38499 * @class Roo.form.DateField
38500 * @extends Roo.form.TriggerField
38501 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38503 * Create a new DateField
38504 * @param {Object} config
38506 Roo.form.DateField = function(config){
38507 Roo.form.DateField.superclass.constructor.call(this, config);
38513 * Fires when a date is selected
38514 * @param {Roo.form.DateField} combo This combo box
38515 * @param {Date} date The date selected
38522 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38523 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38524 this.ddMatch = null;
38525 if(this.disabledDates){
38526 var dd = this.disabledDates;
38528 for(var i = 0; i < dd.length; i++){
38530 if(i != dd.length-1) re += "|";
38532 this.ddMatch = new RegExp(re + ")");
38536 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38538 * @cfg {String} format
38539 * The default date format string which can be overriden for localization support. The format must be
38540 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38544 * @cfg {String} altFormats
38545 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38546 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38548 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38550 * @cfg {Array} disabledDays
38551 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38553 disabledDays : null,
38555 * @cfg {String} disabledDaysText
38556 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38558 disabledDaysText : "Disabled",
38560 * @cfg {Array} disabledDates
38561 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38562 * expression so they are very powerful. Some examples:
38564 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38565 * <li>["03/08", "09/16"] would disable those days for every year</li>
38566 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38567 * <li>["03/../2006"] would disable every day in March 2006</li>
38568 * <li>["^03"] would disable every day in every March</li>
38570 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38571 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38573 disabledDates : null,
38575 * @cfg {String} disabledDatesText
38576 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38578 disabledDatesText : "Disabled",
38580 * @cfg {Date/String} minValue
38581 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38582 * valid format (defaults to null).
38586 * @cfg {Date/String} maxValue
38587 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38588 * valid format (defaults to null).
38592 * @cfg {String} minText
38593 * The error text to display when the date in the cell is before minValue (defaults to
38594 * 'The date in this field must be after {minValue}').
38596 minText : "The date in this field must be equal to or after {0}",
38598 * @cfg {String} maxText
38599 * The error text to display when the date in the cell is after maxValue (defaults to
38600 * 'The date in this field must be before {maxValue}').
38602 maxText : "The date in this field must be equal to or before {0}",
38604 * @cfg {String} invalidText
38605 * The error text to display when the date in the field is invalid (defaults to
38606 * '{value} is not a valid date - it must be in the format {format}').
38608 invalidText : "{0} is not a valid date - it must be in the format {1}",
38610 * @cfg {String} triggerClass
38611 * An additional CSS class used to style the trigger button. The trigger will always get the
38612 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38613 * which displays a calendar icon).
38615 triggerClass : 'x-form-date-trigger',
38619 * @cfg {Boolean} useIso
38620 * if enabled, then the date field will use a hidden field to store the
38621 * real value as iso formated date. default (false)
38625 * @cfg {String/Object} autoCreate
38626 * A DomHelper element spec, or true for a default element spec (defaults to
38627 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38630 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38633 hiddenField: false,
38635 onRender : function(ct, position)
38637 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38639 //this.el.dom.removeAttribute('name');
38640 Roo.log("Changing name?");
38641 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38642 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38644 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38645 // prevent input submission
38646 this.hiddenName = this.name;
38653 validateValue : function(value)
38655 value = this.formatDate(value);
38656 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38657 Roo.log('super failed');
38660 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38663 var svalue = value;
38664 value = this.parseDate(value);
38666 Roo.log('parse date failed' + svalue);
38667 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38670 var time = value.getTime();
38671 if(this.minValue && time < this.minValue.getTime()){
38672 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38675 if(this.maxValue && time > this.maxValue.getTime()){
38676 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38679 if(this.disabledDays){
38680 var day = value.getDay();
38681 for(var i = 0; i < this.disabledDays.length; i++) {
38682 if(day === this.disabledDays[i]){
38683 this.markInvalid(this.disabledDaysText);
38688 var fvalue = this.formatDate(value);
38689 if(this.ddMatch && this.ddMatch.test(fvalue)){
38690 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38697 // Provides logic to override the default TriggerField.validateBlur which just returns true
38698 validateBlur : function(){
38699 return !this.menu || !this.menu.isVisible();
38702 getName: function()
38704 // returns hidden if it's set..
38705 if (!this.rendered) {return ''};
38706 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38711 * Returns the current date value of the date field.
38712 * @return {Date} The date value
38714 getValue : function(){
38716 return this.hiddenField ?
38717 this.hiddenField.value :
38718 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38722 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38723 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38724 * (the default format used is "m/d/y").
38727 //All of these calls set the same date value (May 4, 2006)
38729 //Pass a date object:
38730 var dt = new Date('5/4/06');
38731 dateField.setValue(dt);
38733 //Pass a date string (default format):
38734 dateField.setValue('5/4/06');
38736 //Pass a date string (custom format):
38737 dateField.format = 'Y-m-d';
38738 dateField.setValue('2006-5-4');
38740 * @param {String/Date} date The date or valid date string
38742 setValue : function(date){
38743 if (this.hiddenField) {
38744 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38746 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38747 // make sure the value field is always stored as a date..
38748 this.value = this.parseDate(date);
38754 parseDate : function(value){
38755 if(!value || value instanceof Date){
38758 var v = Date.parseDate(value, this.format);
38759 if (!v && this.useIso) {
38760 v = Date.parseDate(value, 'Y-m-d');
38762 if(!v && this.altFormats){
38763 if(!this.altFormatsArray){
38764 this.altFormatsArray = this.altFormats.split("|");
38766 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38767 v = Date.parseDate(value, this.altFormatsArray[i]);
38774 formatDate : function(date, fmt){
38775 return (!date || !(date instanceof Date)) ?
38776 date : date.dateFormat(fmt || this.format);
38781 select: function(m, d){
38784 this.fireEvent('select', this, d);
38786 show : function(){ // retain focus styling
38790 this.focus.defer(10, this);
38791 var ml = this.menuListeners;
38792 this.menu.un("select", ml.select, this);
38793 this.menu.un("show", ml.show, this);
38794 this.menu.un("hide", ml.hide, this);
38799 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38800 onTriggerClick : function(){
38804 if(this.menu == null){
38805 this.menu = new Roo.menu.DateMenu();
38807 Roo.apply(this.menu.picker, {
38808 showClear: this.allowBlank,
38809 minDate : this.minValue,
38810 maxDate : this.maxValue,
38811 disabledDatesRE : this.ddMatch,
38812 disabledDatesText : this.disabledDatesText,
38813 disabledDays : this.disabledDays,
38814 disabledDaysText : this.disabledDaysText,
38815 format : this.useIso ? 'Y-m-d' : this.format,
38816 minText : String.format(this.minText, this.formatDate(this.minValue)),
38817 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38819 this.menu.on(Roo.apply({}, this.menuListeners, {
38822 this.menu.picker.setValue(this.getValue() || new Date());
38823 this.menu.show(this.el, "tl-bl?");
38826 beforeBlur : function(){
38827 var v = this.parseDate(this.getRawValue());
38837 isDirty : function() {
38838 if(this.disabled) {
38842 if(typeof(this.startValue) === 'undefined'){
38846 return String(this.getValue()) !== String(this.startValue);
38851 * Ext JS Library 1.1.1
38852 * Copyright(c) 2006-2007, Ext JS, LLC.
38854 * Originally Released Under LGPL - original licence link has changed is not relivant.
38857 * <script type="text/javascript">
38861 * @class Roo.form.MonthField
38862 * @extends Roo.form.TriggerField
38863 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38865 * Create a new MonthField
38866 * @param {Object} config
38868 Roo.form.MonthField = function(config){
38870 Roo.form.MonthField.superclass.constructor.call(this, config);
38876 * Fires when a date is selected
38877 * @param {Roo.form.MonthFieeld} combo This combo box
38878 * @param {Date} date The date selected
38885 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38886 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38887 this.ddMatch = null;
38888 if(this.disabledDates){
38889 var dd = this.disabledDates;
38891 for(var i = 0; i < dd.length; i++){
38893 if(i != dd.length-1) re += "|";
38895 this.ddMatch = new RegExp(re + ")");
38899 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38901 * @cfg {String} format
38902 * The default date format string which can be overriden for localization support. The format must be
38903 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38907 * @cfg {String} altFormats
38908 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38909 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38911 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38913 * @cfg {Array} disabledDays
38914 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38916 disabledDays : [0,1,2,3,4,5,6],
38918 * @cfg {String} disabledDaysText
38919 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38921 disabledDaysText : "Disabled",
38923 * @cfg {Array} disabledDates
38924 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38925 * expression so they are very powerful. Some examples:
38927 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38928 * <li>["03/08", "09/16"] would disable those days for every year</li>
38929 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38930 * <li>["03/../2006"] would disable every day in March 2006</li>
38931 * <li>["^03"] would disable every day in every March</li>
38933 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38934 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38936 disabledDates : null,
38938 * @cfg {String} disabledDatesText
38939 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38941 disabledDatesText : "Disabled",
38943 * @cfg {Date/String} minValue
38944 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38945 * valid format (defaults to null).
38949 * @cfg {Date/String} maxValue
38950 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38951 * valid format (defaults to null).
38955 * @cfg {String} minText
38956 * The error text to display when the date in the cell is before minValue (defaults to
38957 * 'The date in this field must be after {minValue}').
38959 minText : "The date in this field must be equal to or after {0}",
38961 * @cfg {String} maxTextf
38962 * The error text to display when the date in the cell is after maxValue (defaults to
38963 * 'The date in this field must be before {maxValue}').
38965 maxText : "The date in this field must be equal to or before {0}",
38967 * @cfg {String} invalidText
38968 * The error text to display when the date in the field is invalid (defaults to
38969 * '{value} is not a valid date - it must be in the format {format}').
38971 invalidText : "{0} is not a valid date - it must be in the format {1}",
38973 * @cfg {String} triggerClass
38974 * An additional CSS class used to style the trigger button. The trigger will always get the
38975 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38976 * which displays a calendar icon).
38978 triggerClass : 'x-form-date-trigger',
38982 * @cfg {Boolean} useIso
38983 * if enabled, then the date field will use a hidden field to store the
38984 * real value as iso formated date. default (true)
38988 * @cfg {String/Object} autoCreate
38989 * A DomHelper element spec, or true for a default element spec (defaults to
38990 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38993 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
38996 hiddenField: false,
38998 hideMonthPicker : false,
39000 onRender : function(ct, position)
39002 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39004 this.el.dom.removeAttribute('name');
39005 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39007 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39008 // prevent input submission
39009 this.hiddenName = this.name;
39016 validateValue : function(value)
39018 value = this.formatDate(value);
39019 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39022 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39025 var svalue = value;
39026 value = this.parseDate(value);
39028 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39031 var time = value.getTime();
39032 if(this.minValue && time < this.minValue.getTime()){
39033 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39036 if(this.maxValue && time > this.maxValue.getTime()){
39037 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39040 /*if(this.disabledDays){
39041 var day = value.getDay();
39042 for(var i = 0; i < this.disabledDays.length; i++) {
39043 if(day === this.disabledDays[i]){
39044 this.markInvalid(this.disabledDaysText);
39050 var fvalue = this.formatDate(value);
39051 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39052 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39060 // Provides logic to override the default TriggerField.validateBlur which just returns true
39061 validateBlur : function(){
39062 return !this.menu || !this.menu.isVisible();
39066 * Returns the current date value of the date field.
39067 * @return {Date} The date value
39069 getValue : function(){
39073 return this.hiddenField ?
39074 this.hiddenField.value :
39075 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39079 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39080 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39081 * (the default format used is "m/d/y").
39084 //All of these calls set the same date value (May 4, 2006)
39086 //Pass a date object:
39087 var dt = new Date('5/4/06');
39088 monthField.setValue(dt);
39090 //Pass a date string (default format):
39091 monthField.setValue('5/4/06');
39093 //Pass a date string (custom format):
39094 monthField.format = 'Y-m-d';
39095 monthField.setValue('2006-5-4');
39097 * @param {String/Date} date The date or valid date string
39099 setValue : function(date){
39100 Roo.log('month setValue' + date);
39101 // can only be first of month..
39103 var val = this.parseDate(date);
39105 if (this.hiddenField) {
39106 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39108 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39109 this.value = this.parseDate(date);
39113 parseDate : function(value){
39114 if(!value || value instanceof Date){
39115 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39118 var v = Date.parseDate(value, this.format);
39119 if (!v && this.useIso) {
39120 v = Date.parseDate(value, 'Y-m-d');
39124 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39128 if(!v && this.altFormats){
39129 if(!this.altFormatsArray){
39130 this.altFormatsArray = this.altFormats.split("|");
39132 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39133 v = Date.parseDate(value, this.altFormatsArray[i]);
39140 formatDate : function(date, fmt){
39141 return (!date || !(date instanceof Date)) ?
39142 date : date.dateFormat(fmt || this.format);
39147 select: function(m, d){
39149 this.fireEvent('select', this, d);
39151 show : function(){ // retain focus styling
39155 this.focus.defer(10, this);
39156 var ml = this.menuListeners;
39157 this.menu.un("select", ml.select, this);
39158 this.menu.un("show", ml.show, this);
39159 this.menu.un("hide", ml.hide, this);
39163 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39164 onTriggerClick : function(){
39168 if(this.menu == null){
39169 this.menu = new Roo.menu.DateMenu();
39173 Roo.apply(this.menu.picker, {
39175 showClear: this.allowBlank,
39176 minDate : this.minValue,
39177 maxDate : this.maxValue,
39178 disabledDatesRE : this.ddMatch,
39179 disabledDatesText : this.disabledDatesText,
39181 format : this.useIso ? 'Y-m-d' : this.format,
39182 minText : String.format(this.minText, this.formatDate(this.minValue)),
39183 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39186 this.menu.on(Roo.apply({}, this.menuListeners, {
39194 // hide month picker get's called when we called by 'before hide';
39196 var ignorehide = true;
39197 p.hideMonthPicker = function(disableAnim){
39201 if(this.monthPicker){
39202 Roo.log("hideMonthPicker called");
39203 if(disableAnim === true){
39204 this.monthPicker.hide();
39206 this.monthPicker.slideOut('t', {duration:.2});
39207 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39208 p.fireEvent("select", this, this.value);
39214 Roo.log('picker set value');
39215 Roo.log(this.getValue());
39216 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39217 m.show(this.el, 'tl-bl?');
39218 ignorehide = false;
39219 // this will trigger hideMonthPicker..
39222 // hidden the day picker
39223 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39229 p.showMonthPicker.defer(100, p);
39235 beforeBlur : function(){
39236 var v = this.parseDate(this.getRawValue());
39242 /** @cfg {Boolean} grow @hide */
39243 /** @cfg {Number} growMin @hide */
39244 /** @cfg {Number} growMax @hide */
39251 * Ext JS Library 1.1.1
39252 * Copyright(c) 2006-2007, Ext JS, LLC.
39254 * Originally Released Under LGPL - original licence link has changed is not relivant.
39257 * <script type="text/javascript">
39262 * @class Roo.form.ComboBox
39263 * @extends Roo.form.TriggerField
39264 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39266 * Create a new ComboBox.
39267 * @param {Object} config Configuration options
39269 Roo.form.ComboBox = function(config){
39270 Roo.form.ComboBox.superclass.constructor.call(this, config);
39274 * Fires when the dropdown list is expanded
39275 * @param {Roo.form.ComboBox} combo This combo box
39280 * Fires when the dropdown list is collapsed
39281 * @param {Roo.form.ComboBox} combo This combo box
39285 * @event beforeselect
39286 * Fires before a list item is selected. Return false to cancel the selection.
39287 * @param {Roo.form.ComboBox} combo This combo box
39288 * @param {Roo.data.Record} record The data record returned from the underlying store
39289 * @param {Number} index The index of the selected item in the dropdown list
39291 'beforeselect' : true,
39294 * Fires when a list item is selected
39295 * @param {Roo.form.ComboBox} combo This combo box
39296 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39297 * @param {Number} index The index of the selected item in the dropdown list
39301 * @event beforequery
39302 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39303 * The event object passed has these properties:
39304 * @param {Roo.form.ComboBox} combo This combo box
39305 * @param {String} query The query
39306 * @param {Boolean} forceAll true to force "all" query
39307 * @param {Boolean} cancel true to cancel the query
39308 * @param {Object} e The query event object
39310 'beforequery': true,
39313 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39314 * @param {Roo.form.ComboBox} combo This combo box
39319 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39320 * @param {Roo.form.ComboBox} combo This combo box
39321 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39327 if(this.transform){
39328 this.allowDomMove = false;
39329 var s = Roo.getDom(this.transform);
39330 if(!this.hiddenName){
39331 this.hiddenName = s.name;
39334 this.mode = 'local';
39335 var d = [], opts = s.options;
39336 for(var i = 0, len = opts.length;i < len; i++){
39338 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39340 this.value = value;
39342 d.push([value, o.text]);
39344 this.store = new Roo.data.SimpleStore({
39346 fields: ['value', 'text'],
39349 this.valueField = 'value';
39350 this.displayField = 'text';
39352 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39353 if(!this.lazyRender){
39354 this.target = true;
39355 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39356 s.parentNode.removeChild(s); // remove it
39357 this.render(this.el.parentNode);
39359 s.parentNode.removeChild(s); // remove it
39364 this.store = Roo.factory(this.store, Roo.data);
39367 this.selectedIndex = -1;
39368 if(this.mode == 'local'){
39369 if(config.queryDelay === undefined){
39370 this.queryDelay = 10;
39372 if(config.minChars === undefined){
39378 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39380 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39383 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39384 * rendering into an Roo.Editor, defaults to false)
39387 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39388 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39391 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39394 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39395 * the dropdown list (defaults to undefined, with no header element)
39399 * @cfg {String/Roo.Template} tpl The template to use to render the output
39403 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39405 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39407 listWidth: undefined,
39409 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39410 * mode = 'remote' or 'text' if mode = 'local')
39412 displayField: undefined,
39414 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39415 * mode = 'remote' or 'value' if mode = 'local').
39416 * Note: use of a valueField requires the user make a selection
39417 * in order for a value to be mapped.
39419 valueField: undefined,
39423 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39424 * field's data value (defaults to the underlying DOM element's name)
39426 hiddenName: undefined,
39428 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39432 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39434 selectedClass: 'x-combo-selected',
39436 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39437 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39438 * which displays a downward arrow icon).
39440 triggerClass : 'x-form-arrow-trigger',
39442 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39446 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39447 * anchor positions (defaults to 'tl-bl')
39449 listAlign: 'tl-bl?',
39451 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39455 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39456 * query specified by the allQuery config option (defaults to 'query')
39458 triggerAction: 'query',
39460 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39461 * (defaults to 4, does not apply if editable = false)
39465 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39466 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39470 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39471 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39475 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39476 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39480 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39481 * when editable = true (defaults to false)
39483 selectOnFocus:false,
39485 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39487 queryParam: 'query',
39489 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39490 * when mode = 'remote' (defaults to 'Loading...')
39492 loadingText: 'Loading...',
39494 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39498 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39502 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39503 * traditional select (defaults to true)
39507 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39511 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39515 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39516 * listWidth has a higher value)
39520 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39521 * allow the user to set arbitrary text into the field (defaults to false)
39523 forceSelection:false,
39525 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39526 * if typeAhead = true (defaults to 250)
39528 typeAheadDelay : 250,
39530 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39531 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39533 valueNotFoundText : undefined,
39535 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39537 blockFocus : false,
39540 * @cfg {Boolean} disableClear Disable showing of clear button.
39542 disableClear : false,
39544 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39546 alwaysQuery : false,
39552 // element that contains real text value.. (when hidden is used..)
39555 onRender : function(ct, position){
39556 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39557 if(this.hiddenName){
39558 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39560 this.hiddenField.value =
39561 this.hiddenValue !== undefined ? this.hiddenValue :
39562 this.value !== undefined ? this.value : '';
39564 // prevent input submission
39565 this.el.dom.removeAttribute('name');
39570 this.el.dom.setAttribute('autocomplete', 'off');
39573 var cls = 'x-combo-list';
39575 this.list = new Roo.Layer({
39576 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39579 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39580 this.list.setWidth(lw);
39581 this.list.swallowEvent('mousewheel');
39582 this.assetHeight = 0;
39585 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39586 this.assetHeight += this.header.getHeight();
39589 this.innerList = this.list.createChild({cls:cls+'-inner'});
39590 this.innerList.on('mouseover', this.onViewOver, this);
39591 this.innerList.on('mousemove', this.onViewMove, this);
39592 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39594 if(this.allowBlank && !this.pageSize && !this.disableClear){
39595 this.footer = this.list.createChild({cls:cls+'-ft'});
39596 this.pageTb = new Roo.Toolbar(this.footer);
39600 this.footer = this.list.createChild({cls:cls+'-ft'});
39601 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39602 {pageSize: this.pageSize});
39606 if (this.pageTb && this.allowBlank && !this.disableClear) {
39608 this.pageTb.add(new Roo.Toolbar.Fill(), {
39609 cls: 'x-btn-icon x-btn-clear',
39611 handler: function()
39614 _this.clearValue();
39615 _this.onSelect(false, -1);
39620 this.assetHeight += this.footer.getHeight();
39625 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39628 this.view = new Roo.View(this.innerList, this.tpl, {
39629 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39632 this.view.on('click', this.onViewClick, this);
39634 this.store.on('beforeload', this.onBeforeLoad, this);
39635 this.store.on('load', this.onLoad, this);
39636 this.store.on('loadexception', this.onLoadException, this);
39638 if(this.resizable){
39639 this.resizer = new Roo.Resizable(this.list, {
39640 pinned:true, handles:'se'
39642 this.resizer.on('resize', function(r, w, h){
39643 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39644 this.listWidth = w;
39645 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39646 this.restrictHeight();
39648 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39650 if(!this.editable){
39651 this.editable = true;
39652 this.setEditable(false);
39656 if (typeof(this.events.add.listeners) != 'undefined') {
39658 this.addicon = this.wrap.createChild(
39659 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39661 this.addicon.on('click', function(e) {
39662 this.fireEvent('add', this);
39665 if (typeof(this.events.edit.listeners) != 'undefined') {
39667 this.editicon = this.wrap.createChild(
39668 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39669 if (this.addicon) {
39670 this.editicon.setStyle('margin-left', '40px');
39672 this.editicon.on('click', function(e) {
39674 // we fire even if inothing is selected..
39675 this.fireEvent('edit', this, this.lastData );
39685 initEvents : function(){
39686 Roo.form.ComboBox.superclass.initEvents.call(this);
39688 this.keyNav = new Roo.KeyNav(this.el, {
39689 "up" : function(e){
39690 this.inKeyMode = true;
39694 "down" : function(e){
39695 if(!this.isExpanded()){
39696 this.onTriggerClick();
39698 this.inKeyMode = true;
39703 "enter" : function(e){
39704 this.onViewClick();
39708 "esc" : function(e){
39712 "tab" : function(e){
39713 this.onViewClick(false);
39714 this.fireEvent("specialkey", this, e);
39720 doRelay : function(foo, bar, hname){
39721 if(hname == 'down' || this.scope.isExpanded()){
39722 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39729 this.queryDelay = Math.max(this.queryDelay || 10,
39730 this.mode == 'local' ? 10 : 250);
39731 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39732 if(this.typeAhead){
39733 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39735 if(this.editable !== false){
39736 this.el.on("keyup", this.onKeyUp, this);
39738 if(this.forceSelection){
39739 this.on('blur', this.doForce, this);
39743 onDestroy : function(){
39745 this.view.setStore(null);
39746 this.view.el.removeAllListeners();
39747 this.view.el.remove();
39748 this.view.purgeListeners();
39751 this.list.destroy();
39754 this.store.un('beforeload', this.onBeforeLoad, this);
39755 this.store.un('load', this.onLoad, this);
39756 this.store.un('loadexception', this.onLoadException, this);
39758 Roo.form.ComboBox.superclass.onDestroy.call(this);
39762 fireKey : function(e){
39763 if(e.isNavKeyPress() && !this.list.isVisible()){
39764 this.fireEvent("specialkey", this, e);
39769 onResize: function(w, h){
39770 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39772 if(typeof w != 'number'){
39773 // we do not handle it!?!?
39776 var tw = this.trigger.getWidth();
39777 tw += this.addicon ? this.addicon.getWidth() : 0;
39778 tw += this.editicon ? this.editicon.getWidth() : 0;
39780 this.el.setWidth( this.adjustWidth('input', x));
39782 this.trigger.setStyle('left', x+'px');
39784 if(this.list && this.listWidth === undefined){
39785 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39786 this.list.setWidth(lw);
39787 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39795 * Allow or prevent the user from directly editing the field text. If false is passed,
39796 * the user will only be able to select from the items defined in the dropdown list. This method
39797 * is the runtime equivalent of setting the 'editable' config option at config time.
39798 * @param {Boolean} value True to allow the user to directly edit the field text
39800 setEditable : function(value){
39801 if(value == this.editable){
39804 this.editable = value;
39806 this.el.dom.setAttribute('readOnly', true);
39807 this.el.on('mousedown', this.onTriggerClick, this);
39808 this.el.addClass('x-combo-noedit');
39810 this.el.dom.setAttribute('readOnly', false);
39811 this.el.un('mousedown', this.onTriggerClick, this);
39812 this.el.removeClass('x-combo-noedit');
39817 onBeforeLoad : function(){
39818 if(!this.hasFocus){
39821 this.innerList.update(this.loadingText ?
39822 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39823 this.restrictHeight();
39824 this.selectedIndex = -1;
39828 onLoad : function(){
39829 if(!this.hasFocus){
39832 if(this.store.getCount() > 0){
39834 this.restrictHeight();
39835 if(this.lastQuery == this.allQuery){
39837 this.el.dom.select();
39839 if(!this.selectByValue(this.value, true)){
39840 this.select(0, true);
39844 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39845 this.taTask.delay(this.typeAheadDelay);
39849 this.onEmptyResults();
39854 onLoadException : function()
39857 Roo.log(this.store.reader.jsonData);
39858 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39859 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39865 onTypeAhead : function(){
39866 if(this.store.getCount() > 0){
39867 var r = this.store.getAt(0);
39868 var newValue = r.data[this.displayField];
39869 var len = newValue.length;
39870 var selStart = this.getRawValue().length;
39871 if(selStart != len){
39872 this.setRawValue(newValue);
39873 this.selectText(selStart, newValue.length);
39879 onSelect : function(record, index){
39880 if(this.fireEvent('beforeselect', this, record, index) !== false){
39881 this.setFromData(index > -1 ? record.data : false);
39883 this.fireEvent('select', this, record, index);
39888 * Returns the currently selected field value or empty string if no value is set.
39889 * @return {String} value The selected value
39891 getValue : function(){
39892 if(this.valueField){
39893 return typeof this.value != 'undefined' ? this.value : '';
39895 return Roo.form.ComboBox.superclass.getValue.call(this);
39899 * Clears any text/value currently set in the field
39901 clearValue : function(){
39902 if(this.hiddenField){
39903 this.hiddenField.value = '';
39906 this.setRawValue('');
39907 this.lastSelectionText = '';
39912 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39913 * will be displayed in the field. If the value does not match the data value of an existing item,
39914 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39915 * Otherwise the field will be blank (although the value will still be set).
39916 * @param {String} value The value to match
39918 setValue : function(v){
39920 if(this.valueField){
39921 var r = this.findRecord(this.valueField, v);
39923 text = r.data[this.displayField];
39924 }else if(this.valueNotFoundText !== undefined){
39925 text = this.valueNotFoundText;
39928 this.lastSelectionText = text;
39929 if(this.hiddenField){
39930 this.hiddenField.value = v;
39932 Roo.form.ComboBox.superclass.setValue.call(this, text);
39936 * @property {Object} the last set data for the element
39941 * Sets the value of the field based on a object which is related to the record format for the store.
39942 * @param {Object} value the value to set as. or false on reset?
39944 setFromData : function(o){
39945 var dv = ''; // display value
39946 var vv = ''; // value value..
39948 if (this.displayField) {
39949 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39951 // this is an error condition!!!
39952 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39955 if(this.valueField){
39956 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39958 if(this.hiddenField){
39959 this.hiddenField.value = vv;
39961 this.lastSelectionText = dv;
39962 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39966 // no hidden field.. - we store the value in 'value', but still display
39967 // display field!!!!
39968 this.lastSelectionText = dv;
39969 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39975 reset : function(){
39976 // overridden so that last data is reset..
39977 this.setValue(this.resetValue);
39978 this.clearInvalid();
39979 this.lastData = false;
39981 this.view.clearSelections();
39985 findRecord : function(prop, value){
39987 if(this.store.getCount() > 0){
39988 this.store.each(function(r){
39989 if(r.data[prop] == value){
39999 getName: function()
40001 // returns hidden if it's set..
40002 if (!this.rendered) {return ''};
40003 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40007 onViewMove : function(e, t){
40008 this.inKeyMode = false;
40012 onViewOver : function(e, t){
40013 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40016 var item = this.view.findItemFromChild(t);
40018 var index = this.view.indexOf(item);
40019 this.select(index, false);
40024 onViewClick : function(doFocus)
40026 var index = this.view.getSelectedIndexes()[0];
40027 var r = this.store.getAt(index);
40029 this.onSelect(r, index);
40031 if(doFocus !== false && !this.blockFocus){
40037 restrictHeight : function(){
40038 this.innerList.dom.style.height = '';
40039 var inner = this.innerList.dom;
40040 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40041 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40042 this.list.beginUpdate();
40043 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40044 this.list.alignTo(this.el, this.listAlign);
40045 this.list.endUpdate();
40049 onEmptyResults : function(){
40054 * Returns true if the dropdown list is expanded, else false.
40056 isExpanded : function(){
40057 return this.list.isVisible();
40061 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40062 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40063 * @param {String} value The data value of the item to select
40064 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40065 * selected item if it is not currently in view (defaults to true)
40066 * @return {Boolean} True if the value matched an item in the list, else false
40068 selectByValue : function(v, scrollIntoView){
40069 if(v !== undefined && v !== null){
40070 var r = this.findRecord(this.valueField || this.displayField, v);
40072 this.select(this.store.indexOf(r), scrollIntoView);
40080 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40081 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40082 * @param {Number} index The zero-based index of the list item to select
40083 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40084 * selected item if it is not currently in view (defaults to true)
40086 select : function(index, scrollIntoView){
40087 this.selectedIndex = index;
40088 this.view.select(index);
40089 if(scrollIntoView !== false){
40090 var el = this.view.getNode(index);
40092 this.innerList.scrollChildIntoView(el, false);
40098 selectNext : function(){
40099 var ct = this.store.getCount();
40101 if(this.selectedIndex == -1){
40103 }else if(this.selectedIndex < ct-1){
40104 this.select(this.selectedIndex+1);
40110 selectPrev : function(){
40111 var ct = this.store.getCount();
40113 if(this.selectedIndex == -1){
40115 }else if(this.selectedIndex != 0){
40116 this.select(this.selectedIndex-1);
40122 onKeyUp : function(e){
40123 if(this.editable !== false && !e.isSpecialKey()){
40124 this.lastKey = e.getKey();
40125 this.dqTask.delay(this.queryDelay);
40130 validateBlur : function(){
40131 return !this.list || !this.list.isVisible();
40135 initQuery : function(){
40136 this.doQuery(this.getRawValue());
40140 doForce : function(){
40141 if(this.el.dom.value.length > 0){
40142 this.el.dom.value =
40143 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40149 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40150 * query allowing the query action to be canceled if needed.
40151 * @param {String} query The SQL query to execute
40152 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40153 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40154 * saved in the current store (defaults to false)
40156 doQuery : function(q, forceAll){
40157 if(q === undefined || q === null){
40162 forceAll: forceAll,
40166 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40170 forceAll = qe.forceAll;
40171 if(forceAll === true || (q.length >= this.minChars)){
40172 if(this.lastQuery != q || this.alwaysQuery){
40173 this.lastQuery = q;
40174 if(this.mode == 'local'){
40175 this.selectedIndex = -1;
40177 this.store.clearFilter();
40179 this.store.filter(this.displayField, q);
40183 this.store.baseParams[this.queryParam] = q;
40185 params: this.getParams(q)
40190 this.selectedIndex = -1;
40197 getParams : function(q){
40199 //p[this.queryParam] = q;
40202 p.limit = this.pageSize;
40208 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40210 collapse : function(){
40211 if(!this.isExpanded()){
40215 Roo.get(document).un('mousedown', this.collapseIf, this);
40216 Roo.get(document).un('mousewheel', this.collapseIf, this);
40217 if (!this.editable) {
40218 Roo.get(document).un('keydown', this.listKeyPress, this);
40220 this.fireEvent('collapse', this);
40224 collapseIf : function(e){
40225 if(!e.within(this.wrap) && !e.within(this.list)){
40231 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40233 expand : function(){
40234 if(this.isExpanded() || !this.hasFocus){
40237 this.list.alignTo(this.el, this.listAlign);
40239 Roo.get(document).on('mousedown', this.collapseIf, this);
40240 Roo.get(document).on('mousewheel', this.collapseIf, this);
40241 if (!this.editable) {
40242 Roo.get(document).on('keydown', this.listKeyPress, this);
40245 this.fireEvent('expand', this);
40249 // Implements the default empty TriggerField.onTriggerClick function
40250 onTriggerClick : function(){
40254 if(this.isExpanded()){
40256 if (!this.blockFocus) {
40261 this.hasFocus = true;
40262 if(this.triggerAction == 'all') {
40263 this.doQuery(this.allQuery, true);
40265 this.doQuery(this.getRawValue());
40267 if (!this.blockFocus) {
40272 listKeyPress : function(e)
40274 //Roo.log('listkeypress');
40275 // scroll to first matching element based on key pres..
40276 if (e.isSpecialKey()) {
40279 var k = String.fromCharCode(e.getKey()).toUpperCase();
40282 var csel = this.view.getSelectedNodes();
40283 var cselitem = false;
40285 var ix = this.view.indexOf(csel[0]);
40286 cselitem = this.store.getAt(ix);
40287 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40293 this.store.each(function(v) {
40295 // start at existing selection.
40296 if (cselitem.id == v.id) {
40302 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40303 match = this.store.indexOf(v);
40308 if (match === false) {
40309 return true; // no more action?
40312 this.view.select(match);
40313 var sn = Roo.get(this.view.getSelectedNodes()[0])
40314 sn.scrollIntoView(sn.dom.parentNode, false);
40318 * @cfg {Boolean} grow
40322 * @cfg {Number} growMin
40326 * @cfg {Number} growMax
40334 * Copyright(c) 2010-2012, Roo J Solutions Limited
40341 * @class Roo.form.ComboBoxArray
40342 * @extends Roo.form.TextField
40343 * A facebook style adder... for lists of email / people / countries etc...
40344 * pick multiple items from a combo box, and shows each one.
40346 * Fred [x] Brian [x] [Pick another |v]
40349 * For this to work: it needs various extra information
40350 * - normal combo problay has
40352 * + displayField, valueField
40354 * For our purpose...
40357 * If we change from 'extends' to wrapping...
40364 * Create a new ComboBoxArray.
40365 * @param {Object} config Configuration options
40369 Roo.form.ComboBoxArray = function(config)
40373 * @event beforeremove
40374 * Fires before remove the value from the list
40375 * @param {Roo.form.ComboBoxArray} _self This combo box array
40376 * @param {Roo.form.ComboBoxArray.Item} item removed item
40378 'beforeremove' : true,
40381 * Fires when remove the value from the list
40382 * @param {Roo.form.ComboBoxArray} _self This combo box array
40383 * @param {Roo.form.ComboBoxArray.Item} item removed item
40390 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40392 this.items = new Roo.util.MixedCollection(false);
40394 // construct the child combo...
40404 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40407 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40412 // behavies liek a hiddne field
40413 inputType: 'hidden',
40415 * @cfg {Number} width The width of the box that displays the selected element
40422 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40426 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40428 hiddenName : false,
40431 // private the array of items that are displayed..
40433 // private - the hidden field el.
40435 // private - the filed el..
40438 //validateValue : function() { return true; }, // all values are ok!
40439 //onAddClick: function() { },
40441 onRender : function(ct, position)
40444 // create the standard hidden element
40445 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40448 // give fake names to child combo;
40449 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40450 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40452 this.combo = Roo.factory(this.combo, Roo.form);
40453 this.combo.onRender(ct, position);
40454 if (typeof(this.combo.width) != 'undefined') {
40455 this.combo.onResize(this.combo.width,0);
40458 this.combo.initEvents();
40460 // assigned so form know we need to do this..
40461 this.store = this.combo.store;
40462 this.valueField = this.combo.valueField;
40463 this.displayField = this.combo.displayField ;
40466 this.combo.wrap.addClass('x-cbarray-grp');
40468 var cbwrap = this.combo.wrap.createChild(
40469 {tag: 'div', cls: 'x-cbarray-cb'},
40474 this.hiddenEl = this.combo.wrap.createChild({
40475 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40477 this.el = this.combo.wrap.createChild({
40478 tag: 'input', type:'hidden' , name: this.name, value : ''
40480 // this.el.dom.removeAttribute("name");
40483 this.outerWrap = this.combo.wrap;
40484 this.wrap = cbwrap;
40486 this.outerWrap.setWidth(this.width);
40487 this.outerWrap.dom.removeChild(this.el.dom);
40489 this.wrap.dom.appendChild(this.el.dom);
40490 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40491 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40493 this.combo.trigger.setStyle('position','relative');
40494 this.combo.trigger.setStyle('left', '0px');
40495 this.combo.trigger.setStyle('top', '2px');
40497 this.combo.el.setStyle('vertical-align', 'text-bottom');
40499 //this.trigger.setStyle('vertical-align', 'top');
40501 // this should use the code from combo really... on('add' ....)
40505 this.adder = this.outerWrap.createChild(
40506 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40508 this.adder.on('click', function(e) {
40509 _t.fireEvent('adderclick', this, e);
40513 //this.adder.on('click', this.onAddClick, _t);
40516 this.combo.on('select', function(cb, rec, ix) {
40517 this.addItem(rec.data);
40520 cb.el.dom.value = '';
40521 //cb.lastData = rec.data;
40530 getName: function()
40532 // returns hidden if it's set..
40533 if (!this.rendered) {return ''};
40534 return this.hiddenName ? this.hiddenName : this.name;
40539 onResize: function(w, h){
40542 // not sure if this is needed..
40543 //this.combo.onResize(w,h);
40545 if(typeof w != 'number'){
40546 // we do not handle it!?!?
40549 var tw = this.combo.trigger.getWidth();
40550 tw += this.addicon ? this.addicon.getWidth() : 0;
40551 tw += this.editicon ? this.editicon.getWidth() : 0;
40553 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40555 this.combo.trigger.setStyle('left', '0px');
40557 if(this.list && this.listWidth === undefined){
40558 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40559 this.list.setWidth(lw);
40560 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40567 addItem: function(rec)
40569 var valueField = this.combo.valueField;
40570 var displayField = this.combo.displayField;
40571 if (this.items.indexOfKey(rec[valueField]) > -1) {
40572 //console.log("GOT " + rec.data.id);
40576 var x = new Roo.form.ComboBoxArray.Item({
40577 //id : rec[this.idField],
40579 displayField : displayField ,
40580 tipField : displayField ,
40584 this.items.add(rec[valueField],x);
40585 // add it before the element..
40586 this.updateHiddenEl();
40587 x.render(this.outerWrap, this.wrap.dom);
40588 // add the image handler..
40591 updateHiddenEl : function()
40594 if (!this.hiddenEl) {
40598 var idField = this.combo.valueField;
40600 this.items.each(function(f) {
40601 ar.push(f.data[idField]);
40604 this.hiddenEl.dom.value = ar.join(',');
40610 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40611 this.items.each(function(f) {
40614 this.el.dom.value = '';
40615 if (this.hiddenEl) {
40616 this.hiddenEl.dom.value = '';
40620 getValue: function()
40622 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40624 setValue: function(v) // not a valid action - must use addItems..
40631 if (this.store.isLocal && (typeof(v) == 'string')) {
40632 // then we can use the store to find the values..
40633 // comma seperated at present.. this needs to allow JSON based encoding..
40634 this.hiddenEl.value = v;
40636 Roo.each(v.split(','), function(k) {
40637 Roo.log("CHECK " + this.valueField + ',' + k);
40638 var li = this.store.query(this.valueField, k);
40643 add[this.valueField] = k;
40644 add[this.displayField] = li.item(0).data[this.displayField];
40650 if (typeof(v) == 'object' ) {
40651 // then let's assume it's an array of objects..
40652 Roo.each(v, function(l) {
40660 setFromData: function(v)
40662 // this recieves an object, if setValues is called.
40664 this.el.dom.value = v[this.displayField];
40665 this.hiddenEl.dom.value = v[this.valueField];
40666 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40669 var kv = v[this.valueField];
40670 var dv = v[this.displayField];
40671 kv = typeof(kv) != 'string' ? '' : kv;
40672 dv = typeof(dv) != 'string' ? '' : dv;
40675 var keys = kv.split(',');
40676 var display = dv.split(',');
40677 for (var i = 0 ; i < keys.length; i++) {
40680 add[this.valueField] = keys[i];
40681 add[this.displayField] = display[i];
40689 * Validates the combox array value
40690 * @return {Boolean} True if the value is valid, else false
40692 validate : function(){
40693 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40694 this.clearInvalid();
40700 validateValue : function(value){
40701 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40709 isDirty : function() {
40710 if(this.disabled) {
40715 var d = Roo.decode(String(this.originalValue));
40717 return String(this.getValue()) !== String(this.originalValue);
40720 var originalValue = [];
40722 for (var i = 0; i < d.length; i++){
40723 originalValue.push(d[i][this.valueField]);
40726 return String(this.getValue()) !== String(originalValue.join(','));
40735 * @class Roo.form.ComboBoxArray.Item
40736 * @extends Roo.BoxComponent
40737 * A selected item in the list
40738 * Fred [x] Brian [x] [Pick another |v]
40741 * Create a new item.
40742 * @param {Object} config Configuration options
40745 Roo.form.ComboBoxArray.Item = function(config) {
40746 config.id = Roo.id();
40747 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40750 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40753 displayField : false,
40757 defaultAutoCreate : {
40759 cls: 'x-cbarray-item',
40766 src : Roo.BLANK_IMAGE_URL ,
40774 onRender : function(ct, position)
40776 Roo.form.Field.superclass.onRender.call(this, ct, position);
40779 var cfg = this.getAutoCreate();
40780 this.el = ct.createChild(cfg, position);
40783 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40785 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40786 this.cb.renderer(this.data) :
40787 String.format('{0}',this.data[this.displayField]);
40790 this.el.child('div').dom.setAttribute('qtip',
40791 String.format('{0}',this.data[this.tipField])
40794 this.el.child('img').on('click', this.remove, this);
40798 remove : function()
40800 if(this.cb.disabled){
40804 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40805 this.cb.items.remove(this);
40806 this.el.child('img').un('click', this.remove, this);
40808 this.cb.updateHiddenEl();
40810 this.cb.fireEvent('remove', this.cb, this);
40816 * Ext JS Library 1.1.1
40817 * Copyright(c) 2006-2007, Ext JS, LLC.
40819 * Originally Released Under LGPL - original licence link has changed is not relivant.
40822 * <script type="text/javascript">
40825 * @class Roo.form.Checkbox
40826 * @extends Roo.form.Field
40827 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40829 * Creates a new Checkbox
40830 * @param {Object} config Configuration options
40832 Roo.form.Checkbox = function(config){
40833 Roo.form.Checkbox.superclass.constructor.call(this, config);
40837 * Fires when the checkbox is checked or unchecked.
40838 * @param {Roo.form.Checkbox} this This checkbox
40839 * @param {Boolean} checked The new checked value
40845 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40847 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40849 focusClass : undefined,
40851 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40853 fieldClass: "x-form-field",
40855 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40859 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40860 * {tag: "input", type: "checkbox", autocomplete: "off"})
40862 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40864 * @cfg {String} boxLabel The text that appears beside the checkbox
40868 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40872 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40874 valueOff: '0', // value when not checked..
40876 actionMode : 'viewEl',
40879 itemCls : 'x-menu-check-item x-form-item',
40880 groupClass : 'x-menu-group-item',
40881 inputType : 'hidden',
40884 inSetChecked: false, // check that we are not calling self...
40886 inputElement: false, // real input element?
40887 basedOn: false, // ????
40889 isFormField: true, // not sure where this is needed!!!!
40891 onResize : function(){
40892 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40893 if(!this.boxLabel){
40894 this.el.alignTo(this.wrap, 'c-c');
40898 initEvents : function(){
40899 Roo.form.Checkbox.superclass.initEvents.call(this);
40900 this.el.on("click", this.onClick, this);
40901 this.el.on("change", this.onClick, this);
40905 getResizeEl : function(){
40909 getPositionEl : function(){
40914 onRender : function(ct, position){
40915 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40917 if(this.inputValue !== undefined){
40918 this.el.dom.value = this.inputValue;
40921 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40922 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40923 var viewEl = this.wrap.createChild({
40924 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40925 this.viewEl = viewEl;
40926 this.wrap.on('click', this.onClick, this);
40928 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40929 this.el.on('propertychange', this.setFromHidden, this); //ie
40934 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40935 // viewEl.on('click', this.onClick, this);
40937 //if(this.checked){
40938 this.setChecked(this.checked);
40940 //this.checked = this.el.dom;
40946 initValue : Roo.emptyFn,
40949 * Returns the checked state of the checkbox.
40950 * @return {Boolean} True if checked, else false
40952 getValue : function(){
40954 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40956 return this.valueOff;
40961 onClick : function(){
40962 if (this.disabled) {
40965 this.setChecked(!this.checked);
40967 //if(this.el.dom.checked != this.checked){
40968 // this.setValue(this.el.dom.checked);
40973 * Sets the checked state of the checkbox.
40974 * On is always based on a string comparison between inputValue and the param.
40975 * @param {Boolean/String} value - the value to set
40976 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40978 setValue : function(v,suppressEvent){
40981 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40982 //if(this.el && this.el.dom){
40983 // this.el.dom.checked = this.checked;
40984 // this.el.dom.defaultChecked = this.checked;
40986 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40987 //this.fireEvent("check", this, this.checked);
40990 setChecked : function(state,suppressEvent)
40992 if (this.inSetChecked) {
40993 this.checked = state;
40999 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41001 this.checked = state;
41002 if(suppressEvent !== true){
41003 this.fireEvent('check', this, state);
41005 this.inSetChecked = true;
41006 this.el.dom.value = state ? this.inputValue : this.valueOff;
41007 this.inSetChecked = false;
41010 // handle setting of hidden value by some other method!!?!?
41011 setFromHidden: function()
41016 //console.log("SET FROM HIDDEN");
41017 //alert('setFrom hidden');
41018 this.setValue(this.el.dom.value);
41021 onDestroy : function()
41024 Roo.get(this.viewEl).remove();
41027 Roo.form.Checkbox.superclass.onDestroy.call(this);
41032 * Ext JS Library 1.1.1
41033 * Copyright(c) 2006-2007, Ext JS, LLC.
41035 * Originally Released Under LGPL - original licence link has changed is not relivant.
41038 * <script type="text/javascript">
41042 * @class Roo.form.Radio
41043 * @extends Roo.form.Checkbox
41044 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41045 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41047 * Creates a new Radio
41048 * @param {Object} config Configuration options
41050 Roo.form.Radio = function(){
41051 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41053 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41054 inputType: 'radio',
41057 * If this radio is part of a group, it will return the selected value
41060 getGroupValue : function(){
41061 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41065 onRender : function(ct, position){
41066 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41068 if(this.inputValue !== undefined){
41069 this.el.dom.value = this.inputValue;
41072 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41073 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41074 //var viewEl = this.wrap.createChild({
41075 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41076 //this.viewEl = viewEl;
41077 //this.wrap.on('click', this.onClick, this);
41079 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41080 //this.el.on('propertychange', this.setFromHidden, this); //ie
41085 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41086 // viewEl.on('click', this.onClick, this);
41089 this.el.dom.checked = 'checked' ;
41095 });//<script type="text/javascript">
41098 * Based Ext JS Library 1.1.1
41099 * Copyright(c) 2006-2007, Ext JS, LLC.
41105 * @class Roo.HtmlEditorCore
41106 * @extends Roo.Component
41107 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41109 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41112 Roo.HtmlEditorCore = function(config){
41115 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41120 * @event initialize
41121 * Fires when the editor is fully initialized (including the iframe)
41122 * @param {Roo.HtmlEditorCore} this
41127 * Fires when the editor is first receives the focus. Any insertion must wait
41128 * until after this event.
41129 * @param {Roo.HtmlEditorCore} this
41133 * @event beforesync
41134 * Fires before the textarea is updated with content from the editor iframe. Return false
41135 * to cancel the sync.
41136 * @param {Roo.HtmlEditorCore} this
41137 * @param {String} html
41141 * @event beforepush
41142 * Fires before the iframe editor is updated with content from the textarea. Return false
41143 * to cancel the push.
41144 * @param {Roo.HtmlEditorCore} this
41145 * @param {String} html
41150 * Fires when the textarea is updated with content from the editor iframe.
41151 * @param {Roo.HtmlEditorCore} this
41152 * @param {String} html
41157 * Fires when the iframe editor is updated with content from the textarea.
41158 * @param {Roo.HtmlEditorCore} this
41159 * @param {String} html
41164 * @event editorevent
41165 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41166 * @param {Roo.HtmlEditorCore} this
41172 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41174 // defaults : white / black...
41175 this.applyBlacklists();
41182 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41186 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41192 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41197 * @cfg {Number} height (in pixels)
41201 * @cfg {Number} width (in pixels)
41206 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41209 stylesheets: false,
41214 // private properties
41215 validationEvent : false,
41217 initialized : false,
41219 sourceEditMode : false,
41220 onFocus : Roo.emptyFn,
41222 hideMode:'offsets',
41226 // blacklist + whitelisted elements..
41233 * Protected method that will not generally be called directly. It
41234 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41235 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41237 getDocMarkup : function(){
41241 // inherit styels from page...??
41242 if (this.stylesheets === false) {
41244 Roo.get(document.head).select('style').each(function(node) {
41245 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41248 Roo.get(document.head).select('link').each(function(node) {
41249 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41252 } else if (!this.stylesheets.length) {
41254 st = '<style type="text/css">' +
41255 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41261 st += '<style type="text/css">' +
41262 'IMG { cursor: pointer } ' +
41266 return '<html><head>' + st +
41267 //<style type="text/css">' +
41268 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41270 ' </head><body class="roo-htmleditor-body"></body></html>';
41274 onRender : function(ct, position)
41277 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41278 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41281 this.el.dom.style.border = '0 none';
41282 this.el.dom.setAttribute('tabIndex', -1);
41283 this.el.addClass('x-hidden hide');
41287 if(Roo.isIE){ // fix IE 1px bogus margin
41288 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41292 this.frameId = Roo.id();
41296 var iframe = this.owner.wrap.createChild({
41298 cls: 'form-control', // bootstrap..
41300 name: this.frameId,
41301 frameBorder : 'no',
41302 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41307 this.iframe = iframe.dom;
41309 this.assignDocWin();
41311 this.doc.designMode = 'on';
41314 this.doc.write(this.getDocMarkup());
41318 var task = { // must defer to wait for browser to be ready
41320 //console.log("run task?" + this.doc.readyState);
41321 this.assignDocWin();
41322 if(this.doc.body || this.doc.readyState == 'complete'){
41324 this.doc.designMode="on";
41328 Roo.TaskMgr.stop(task);
41329 this.initEditor.defer(10, this);
41336 Roo.TaskMgr.start(task);
41341 onResize : function(w, h)
41343 Roo.log('resize: ' +w + ',' + h );
41344 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41348 if(typeof w == 'number'){
41350 this.iframe.style.width = w + 'px';
41352 if(typeof h == 'number'){
41354 this.iframe.style.height = h + 'px';
41356 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41363 * Toggles the editor between standard and source edit mode.
41364 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41366 toggleSourceEdit : function(sourceEditMode){
41368 this.sourceEditMode = sourceEditMode === true;
41370 if(this.sourceEditMode){
41372 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41375 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41376 //this.iframe.className = '';
41379 //this.setSize(this.owner.wrap.getSize());
41380 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41387 * Protected method that will not generally be called directly. If you need/want
41388 * custom HTML cleanup, this is the method you should override.
41389 * @param {String} html The HTML to be cleaned
41390 * return {String} The cleaned HTML
41392 cleanHtml : function(html){
41393 html = String(html);
41394 if(html.length > 5){
41395 if(Roo.isSafari){ // strip safari nonsense
41396 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41399 if(html == ' '){
41406 * HTML Editor -> Textarea
41407 * Protected method that will not generally be called directly. Syncs the contents
41408 * of the editor iframe with the textarea.
41410 syncValue : function(){
41411 if(this.initialized){
41412 var bd = (this.doc.body || this.doc.documentElement);
41413 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41414 var html = bd.innerHTML;
41416 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41417 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41419 html = '<div style="'+m[0]+'">' + html + '</div>';
41422 html = this.cleanHtml(html);
41423 // fix up the special chars.. normaly like back quotes in word...
41424 // however we do not want to do this with chinese..
41425 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41426 var cc = b.charCodeAt();
41428 (cc >= 0x4E00 && cc < 0xA000 ) ||
41429 (cc >= 0x3400 && cc < 0x4E00 ) ||
41430 (cc >= 0xf900 && cc < 0xfb00 )
41436 if(this.owner.fireEvent('beforesync', this, html) !== false){
41437 this.el.dom.value = html;
41438 this.owner.fireEvent('sync', this, html);
41444 * Protected method that will not generally be called directly. Pushes the value of the textarea
41445 * into the iframe editor.
41447 pushValue : function(){
41448 if(this.initialized){
41449 var v = this.el.dom.value.trim();
41451 // if(v.length < 1){
41455 if(this.owner.fireEvent('beforepush', this, v) !== false){
41456 var d = (this.doc.body || this.doc.documentElement);
41458 this.cleanUpPaste();
41459 this.el.dom.value = d.innerHTML;
41460 this.owner.fireEvent('push', this, v);
41466 deferFocus : function(){
41467 this.focus.defer(10, this);
41471 focus : function(){
41472 if(this.win && !this.sourceEditMode){
41479 assignDocWin: function()
41481 var iframe = this.iframe;
41484 this.doc = iframe.contentWindow.document;
41485 this.win = iframe.contentWindow;
41487 // if (!Roo.get(this.frameId)) {
41490 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41491 // this.win = Roo.get(this.frameId).dom.contentWindow;
41493 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41497 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41498 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41503 initEditor : function(){
41504 //console.log("INIT EDITOR");
41505 this.assignDocWin();
41509 this.doc.designMode="on";
41511 this.doc.write(this.getDocMarkup());
41514 var dbody = (this.doc.body || this.doc.documentElement);
41515 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41516 // this copies styles from the containing element into thsi one..
41517 // not sure why we need all of this..
41518 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41520 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41521 //ss['background-attachment'] = 'fixed'; // w3c
41522 dbody.bgProperties = 'fixed'; // ie
41523 //Roo.DomHelper.applyStyles(dbody, ss);
41524 Roo.EventManager.on(this.doc, {
41525 //'mousedown': this.onEditorEvent,
41526 'mouseup': this.onEditorEvent,
41527 'dblclick': this.onEditorEvent,
41528 'click': this.onEditorEvent,
41529 'keyup': this.onEditorEvent,
41534 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41536 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41537 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41539 this.initialized = true;
41541 this.owner.fireEvent('initialize', this);
41546 onDestroy : function(){
41552 //for (var i =0; i < this.toolbars.length;i++) {
41553 // // fixme - ask toolbars for heights?
41554 // this.toolbars[i].onDestroy();
41557 //this.wrap.dom.innerHTML = '';
41558 //this.wrap.remove();
41563 onFirstFocus : function(){
41565 this.assignDocWin();
41568 this.activated = true;
41571 if(Roo.isGecko){ // prevent silly gecko errors
41573 var s = this.win.getSelection();
41574 if(!s.focusNode || s.focusNode.nodeType != 3){
41575 var r = s.getRangeAt(0);
41576 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41581 this.execCmd('useCSS', true);
41582 this.execCmd('styleWithCSS', false);
41585 this.owner.fireEvent('activate', this);
41589 adjustFont: function(btn){
41590 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41591 //if(Roo.isSafari){ // safari
41594 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41595 if(Roo.isSafari){ // safari
41596 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41597 v = (v < 10) ? 10 : v;
41598 v = (v > 48) ? 48 : v;
41599 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41604 v = Math.max(1, v+adjust);
41606 this.execCmd('FontSize', v );
41609 onEditorEvent : function(e){
41610 this.owner.fireEvent('editorevent', this, e);
41611 // this.updateToolbar();
41612 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41615 insertTag : function(tg)
41617 // could be a bit smarter... -> wrap the current selected tRoo..
41618 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41620 range = this.createRange(this.getSelection());
41621 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41622 wrappingNode.appendChild(range.extractContents());
41623 range.insertNode(wrappingNode);
41630 this.execCmd("formatblock", tg);
41634 insertText : function(txt)
41638 var range = this.createRange();
41639 range.deleteContents();
41640 //alert(Sender.getAttribute('label'));
41642 range.insertNode(this.doc.createTextNode(txt));
41648 * Executes a Midas editor command on the editor document and performs necessary focus and
41649 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41650 * @param {String} cmd The Midas command
41651 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41653 relayCmd : function(cmd, value){
41655 this.execCmd(cmd, value);
41656 this.owner.fireEvent('editorevent', this);
41657 //this.updateToolbar();
41658 this.owner.deferFocus();
41662 * Executes a Midas editor command directly on the editor document.
41663 * For visual commands, you should use {@link #relayCmd} instead.
41664 * <b>This should only be called after the editor is initialized.</b>
41665 * @param {String} cmd The Midas command
41666 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41668 execCmd : function(cmd, value){
41669 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41676 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41678 * @param {String} text | dom node..
41680 insertAtCursor : function(text)
41685 if(!this.activated){
41691 var r = this.doc.selection.createRange();
41702 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41706 // from jquery ui (MIT licenced)
41708 var win = this.win;
41710 if (win.getSelection && win.getSelection().getRangeAt) {
41711 range = win.getSelection().getRangeAt(0);
41712 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41713 range.insertNode(node);
41714 } else if (win.document.selection && win.document.selection.createRange) {
41715 // no firefox support
41716 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41717 win.document.selection.createRange().pasteHTML(txt);
41719 // no firefox support
41720 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41721 this.execCmd('InsertHTML', txt);
41730 mozKeyPress : function(e){
41732 var c = e.getCharCode(), cmd;
41735 c = String.fromCharCode(c).toLowerCase();
41749 this.cleanUpPaste.defer(100, this);
41757 e.preventDefault();
41765 fixKeys : function(){ // load time branching for fastest keydown performance
41767 return function(e){
41768 var k = e.getKey(), r;
41771 r = this.doc.selection.createRange();
41774 r.pasteHTML('    ');
41781 r = this.doc.selection.createRange();
41783 var target = r.parentElement();
41784 if(!target || target.tagName.toLowerCase() != 'li'){
41786 r.pasteHTML('<br />');
41792 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41793 this.cleanUpPaste.defer(100, this);
41799 }else if(Roo.isOpera){
41800 return function(e){
41801 var k = e.getKey();
41805 this.execCmd('InsertHTML','    ');
41808 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41809 this.cleanUpPaste.defer(100, this);
41814 }else if(Roo.isSafari){
41815 return function(e){
41816 var k = e.getKey();
41820 this.execCmd('InsertText','\t');
41824 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41825 this.cleanUpPaste.defer(100, this);
41833 getAllAncestors: function()
41835 var p = this.getSelectedNode();
41838 a.push(p); // push blank onto stack..
41839 p = this.getParentElement();
41843 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41847 a.push(this.doc.body);
41851 lastSelNode : false,
41854 getSelection : function()
41856 this.assignDocWin();
41857 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41860 getSelectedNode: function()
41862 // this may only work on Gecko!!!
41864 // should we cache this!!!!
41869 var range = this.createRange(this.getSelection()).cloneRange();
41872 var parent = range.parentElement();
41874 var testRange = range.duplicate();
41875 testRange.moveToElementText(parent);
41876 if (testRange.inRange(range)) {
41879 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41882 parent = parent.parentElement;
41887 // is ancestor a text element.
41888 var ac = range.commonAncestorContainer;
41889 if (ac.nodeType == 3) {
41890 ac = ac.parentNode;
41893 var ar = ac.childNodes;
41896 var other_nodes = [];
41897 var has_other_nodes = false;
41898 for (var i=0;i<ar.length;i++) {
41899 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41902 // fullly contained node.
41904 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41909 // probably selected..
41910 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41911 other_nodes.push(ar[i]);
41915 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41920 has_other_nodes = true;
41922 if (!nodes.length && other_nodes.length) {
41923 nodes= other_nodes;
41925 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41931 createRange: function(sel)
41933 // this has strange effects when using with
41934 // top toolbar - not sure if it's a great idea.
41935 //this.editor.contentWindow.focus();
41936 if (typeof sel != "undefined") {
41938 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41940 return this.doc.createRange();
41943 return this.doc.createRange();
41946 getParentElement: function()
41949 this.assignDocWin();
41950 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41952 var range = this.createRange(sel);
41955 var p = range.commonAncestorContainer;
41956 while (p.nodeType == 3) { // text node
41967 * Range intersection.. the hard stuff...
41971 * [ -- selected range --- ]
41975 * if end is before start or hits it. fail.
41976 * if start is after end or hits it fail.
41978 * if either hits (but other is outside. - then it's not
41984 // @see http://www.thismuchiknow.co.uk/?p=64.
41985 rangeIntersectsNode : function(range, node)
41987 var nodeRange = node.ownerDocument.createRange();
41989 nodeRange.selectNode(node);
41991 nodeRange.selectNodeContents(node);
41994 var rangeStartRange = range.cloneRange();
41995 rangeStartRange.collapse(true);
41997 var rangeEndRange = range.cloneRange();
41998 rangeEndRange.collapse(false);
42000 var nodeStartRange = nodeRange.cloneRange();
42001 nodeStartRange.collapse(true);
42003 var nodeEndRange = nodeRange.cloneRange();
42004 nodeEndRange.collapse(false);
42006 return rangeStartRange.compareBoundaryPoints(
42007 Range.START_TO_START, nodeEndRange) == -1 &&
42008 rangeEndRange.compareBoundaryPoints(
42009 Range.START_TO_START, nodeStartRange) == 1;
42013 rangeCompareNode : function(range, node)
42015 var nodeRange = node.ownerDocument.createRange();
42017 nodeRange.selectNode(node);
42019 nodeRange.selectNodeContents(node);
42023 range.collapse(true);
42025 nodeRange.collapse(true);
42027 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42028 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42030 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42032 var nodeIsBefore = ss == 1;
42033 var nodeIsAfter = ee == -1;
42035 if (nodeIsBefore && nodeIsAfter)
42037 if (!nodeIsBefore && nodeIsAfter)
42038 return 1; //right trailed.
42040 if (nodeIsBefore && !nodeIsAfter)
42041 return 2; // left trailed.
42046 // private? - in a new class?
42047 cleanUpPaste : function()
42049 // cleans up the whole document..
42050 Roo.log('cleanuppaste');
42052 this.cleanUpChildren(this.doc.body);
42053 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42054 if (clean != this.doc.body.innerHTML) {
42055 this.doc.body.innerHTML = clean;
42060 cleanWordChars : function(input) {// change the chars to hex code
42061 var he = Roo.HtmlEditorCore;
42063 var output = input;
42064 Roo.each(he.swapCodes, function(sw) {
42065 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42067 output = output.replace(swapper, sw[1]);
42074 cleanUpChildren : function (n)
42076 if (!n.childNodes.length) {
42079 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42080 this.cleanUpChild(n.childNodes[i]);
42087 cleanUpChild : function (node)
42090 //console.log(node);
42091 if (node.nodeName == "#text") {
42092 // clean up silly Windows -- stuff?
42095 if (node.nodeName == "#comment") {
42096 node.parentNode.removeChild(node);
42097 // clean up silly Windows -- stuff?
42100 var lcname = node.tagName.toLowerCase();
42101 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42102 // whitelist of tags..
42104 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42106 node.parentNode.removeChild(node);
42111 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42113 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42114 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42116 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42117 // remove_keep_children = true;
42120 if (remove_keep_children) {
42121 this.cleanUpChildren(node);
42122 // inserts everything just before this node...
42123 while (node.childNodes.length) {
42124 var cn = node.childNodes[0];
42125 node.removeChild(cn);
42126 node.parentNode.insertBefore(cn, node);
42128 node.parentNode.removeChild(node);
42132 if (!node.attributes || !node.attributes.length) {
42133 this.cleanUpChildren(node);
42137 function cleanAttr(n,v)
42140 if (v.match(/^\./) || v.match(/^\//)) {
42143 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42146 if (v.match(/^#/)) {
42149 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42150 node.removeAttribute(n);
42154 var cwhite = this.cwhite;
42155 var cblack = this.cblack;
42157 function cleanStyle(n,v)
42159 if (v.match(/expression/)) { //XSS?? should we even bother..
42160 node.removeAttribute(n);
42164 var parts = v.split(/;/);
42167 Roo.each(parts, function(p) {
42168 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42172 var l = p.split(':').shift().replace(/\s+/g,'');
42173 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42175 if ( cwhite.length && cblack.indexOf(l) > -1) {
42176 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42177 //node.removeAttribute(n);
42181 // only allow 'c whitelisted system attributes'
42182 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42183 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42184 //node.removeAttribute(n);
42194 if (clean.length) {
42195 node.setAttribute(n, clean.join(';'));
42197 node.removeAttribute(n);
42203 for (var i = node.attributes.length-1; i > -1 ; i--) {
42204 var a = node.attributes[i];
42207 if (a.name.toLowerCase().substr(0,2)=='on') {
42208 node.removeAttribute(a.name);
42211 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42212 node.removeAttribute(a.name);
42215 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42216 cleanAttr(a.name,a.value); // fixme..
42219 if (a.name == 'style') {
42220 cleanStyle(a.name,a.value);
42223 /// clean up MS crap..
42224 // tecnically this should be a list of valid class'es..
42227 if (a.name == 'class') {
42228 if (a.value.match(/^Mso/)) {
42229 node.className = '';
42232 if (a.value.match(/body/)) {
42233 node.className = '';
42244 this.cleanUpChildren(node);
42249 * Clean up MS wordisms...
42251 cleanWord : function(node)
42254 var cleanWordChildren = function()
42256 if (!node.childNodes.length) {
42259 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42260 _t.cleanWord(node.childNodes[i]);
42266 this.cleanWord(this.doc.body);
42269 if (node.nodeName == "#text") {
42270 // clean up silly Windows -- stuff?
42273 if (node.nodeName == "#comment") {
42274 node.parentNode.removeChild(node);
42275 // clean up silly Windows -- stuff?
42279 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42280 node.parentNode.removeChild(node);
42284 // remove - but keep children..
42285 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42286 while (node.childNodes.length) {
42287 var cn = node.childNodes[0];
42288 node.removeChild(cn);
42289 node.parentNode.insertBefore(cn, node);
42291 node.parentNode.removeChild(node);
42292 cleanWordChildren();
42296 if (node.className.length) {
42298 var cn = node.className.split(/\W+/);
42300 Roo.each(cn, function(cls) {
42301 if (cls.match(/Mso[a-zA-Z]+/)) {
42306 node.className = cna.length ? cna.join(' ') : '';
42308 node.removeAttribute("class");
42312 if (node.hasAttribute("lang")) {
42313 node.removeAttribute("lang");
42316 if (node.hasAttribute("style")) {
42318 var styles = node.getAttribute("style").split(";");
42320 Roo.each(styles, function(s) {
42321 if (!s.match(/:/)) {
42324 var kv = s.split(":");
42325 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42328 // what ever is left... we allow.
42331 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42332 if (!nstyle.length) {
42333 node.removeAttribute('style');
42337 cleanWordChildren();
42341 domToHTML : function(currentElement, depth, nopadtext) {
42343 depth = depth || 0;
42344 nopadtext = nopadtext || false;
42346 if (!currentElement) {
42347 return this.domToHTML(this.doc.body);
42350 //Roo.log(currentElement);
42352 var allText = false;
42353 var nodeName = currentElement.nodeName;
42354 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42356 if (nodeName == '#text') {
42358 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42363 if (nodeName != 'BODY') {
42366 // Prints the node tagName, such as <A>, <IMG>, etc
42369 for(i = 0; i < currentElement.attributes.length;i++) {
42371 var aname = currentElement.attributes.item(i).name;
42372 if (!currentElement.attributes.item(i).value.length) {
42375 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42378 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42387 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42390 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42395 // Traverse the tree
42397 var currentElementChild = currentElement.childNodes.item(i);
42398 var allText = true;
42399 var innerHTML = '';
42401 while (currentElementChild) {
42402 // Formatting code (indent the tree so it looks nice on the screen)
42403 var nopad = nopadtext;
42404 if (lastnode == 'SPAN') {
42408 if (currentElementChild.nodeName == '#text') {
42409 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42410 toadd = nopadtext ? toadd : toadd.trim();
42411 if (!nopad && toadd.length > 80) {
42412 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42414 innerHTML += toadd;
42417 currentElementChild = currentElement.childNodes.item(i);
42423 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42425 // Recursively traverse the tree structure of the child node
42426 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42427 lastnode = currentElementChild.nodeName;
42429 currentElementChild=currentElement.childNodes.item(i);
42435 // The remaining code is mostly for formatting the tree
42436 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42441 ret+= "</"+tagName+">";
42447 applyBlacklists : function()
42449 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42450 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42454 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42455 if (b.indexOf(tag) > -1) {
42458 this.white.push(tag);
42462 Roo.each(w, function(tag) {
42463 if (b.indexOf(tag) > -1) {
42466 if (this.white.indexOf(tag) > -1) {
42469 this.white.push(tag);
42474 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42475 if (w.indexOf(tag) > -1) {
42478 this.black.push(tag);
42482 Roo.each(b, function(tag) {
42483 if (w.indexOf(tag) > -1) {
42486 if (this.black.indexOf(tag) > -1) {
42489 this.black.push(tag);
42494 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42495 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42499 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42500 if (b.indexOf(tag) > -1) {
42503 this.cwhite.push(tag);
42507 Roo.each(w, function(tag) {
42508 if (b.indexOf(tag) > -1) {
42511 if (this.cwhite.indexOf(tag) > -1) {
42514 this.cwhite.push(tag);
42519 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42520 if (w.indexOf(tag) > -1) {
42523 this.cblack.push(tag);
42527 Roo.each(b, function(tag) {
42528 if (w.indexOf(tag) > -1) {
42531 if (this.cblack.indexOf(tag) > -1) {
42534 this.cblack.push(tag);
42539 setStylesheets : function(stylesheets)
42541 if(typeof(stylesheets) == 'string'){
42542 Roo.get(this.iframe.contentDocument.head).createChild({
42544 rel : 'stylesheet',
42553 Roo.each(stylesheets, function(s) {
42558 Roo.get(_this.iframe.contentDocument.head).createChild({
42560 rel : 'stylesheet',
42569 removeStylesheets : function()
42573 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42578 // hide stuff that is not compatible
42592 * @event specialkey
42596 * @cfg {String} fieldClass @hide
42599 * @cfg {String} focusClass @hide
42602 * @cfg {String} autoCreate @hide
42605 * @cfg {String} inputType @hide
42608 * @cfg {String} invalidClass @hide
42611 * @cfg {String} invalidText @hide
42614 * @cfg {String} msgFx @hide
42617 * @cfg {String} validateOnBlur @hide
42621 Roo.HtmlEditorCore.white = [
42622 'area', 'br', 'img', 'input', 'hr', 'wbr',
42624 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42625 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42626 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42627 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42628 'table', 'ul', 'xmp',
42630 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42633 'dir', 'menu', 'ol', 'ul', 'dl',
42639 Roo.HtmlEditorCore.black = [
42640 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42642 'base', 'basefont', 'bgsound', 'blink', 'body',
42643 'frame', 'frameset', 'head', 'html', 'ilayer',
42644 'iframe', 'layer', 'link', 'meta', 'object',
42645 'script', 'style' ,'title', 'xml' // clean later..
42647 Roo.HtmlEditorCore.clean = [
42648 'script', 'style', 'title', 'xml'
42650 Roo.HtmlEditorCore.remove = [
42655 Roo.HtmlEditorCore.ablack = [
42659 Roo.HtmlEditorCore.aclean = [
42660 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42664 Roo.HtmlEditorCore.pwhite= [
42665 'http', 'https', 'mailto'
42668 // white listed style attributes.
42669 Roo.HtmlEditorCore.cwhite= [
42670 // 'text-align', /// default is to allow most things..
42676 // black listed style attributes.
42677 Roo.HtmlEditorCore.cblack= [
42678 // 'font-size' -- this can be set by the project
42682 Roo.HtmlEditorCore.swapCodes =[
42693 //<script type="text/javascript">
42696 * Ext JS Library 1.1.1
42697 * Copyright(c) 2006-2007, Ext JS, LLC.
42703 Roo.form.HtmlEditor = function(config){
42707 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42709 if (!this.toolbars) {
42710 this.toolbars = [];
42712 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42718 * @class Roo.form.HtmlEditor
42719 * @extends Roo.form.Field
42720 * Provides a lightweight HTML Editor component.
42722 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42724 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42725 * supported by this editor.</b><br/><br/>
42726 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42727 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42729 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42731 * @cfg {Boolean} clearUp
42735 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42740 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42745 * @cfg {Number} height (in pixels)
42749 * @cfg {Number} width (in pixels)
42754 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42757 stylesheets: false,
42761 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42766 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42772 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42777 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42785 // private properties
42786 validationEvent : false,
42788 initialized : false,
42791 onFocus : Roo.emptyFn,
42793 hideMode:'offsets',
42795 actionMode : 'container', // defaults to hiding it...
42797 defaultAutoCreate : { // modified by initCompnoent..
42799 style:"width:500px;height:300px;",
42800 autocomplete: "new-password"
42804 initComponent : function(){
42807 * @event initialize
42808 * Fires when the editor is fully initialized (including the iframe)
42809 * @param {HtmlEditor} this
42814 * Fires when the editor is first receives the focus. Any insertion must wait
42815 * until after this event.
42816 * @param {HtmlEditor} this
42820 * @event beforesync
42821 * Fires before the textarea is updated with content from the editor iframe. Return false
42822 * to cancel the sync.
42823 * @param {HtmlEditor} this
42824 * @param {String} html
42828 * @event beforepush
42829 * Fires before the iframe editor is updated with content from the textarea. Return false
42830 * to cancel the push.
42831 * @param {HtmlEditor} this
42832 * @param {String} html
42837 * Fires when the textarea is updated with content from the editor iframe.
42838 * @param {HtmlEditor} this
42839 * @param {String} html
42844 * Fires when the iframe editor is updated with content from the textarea.
42845 * @param {HtmlEditor} this
42846 * @param {String} html
42850 * @event editmodechange
42851 * Fires when the editor switches edit modes
42852 * @param {HtmlEditor} this
42853 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42855 editmodechange: true,
42857 * @event editorevent
42858 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42859 * @param {HtmlEditor} this
42863 * @event firstfocus
42864 * Fires when on first focus - needed by toolbars..
42865 * @param {HtmlEditor} this
42870 * Auto save the htmlEditor value as a file into Events
42871 * @param {HtmlEditor} this
42875 * @event savedpreview
42876 * preview the saved version of htmlEditor
42877 * @param {HtmlEditor} this
42879 savedpreview: true,
42882 * @event stylesheetsclick
42883 * Fires when press the Sytlesheets button
42884 * @param {Roo.HtmlEditorCore} this
42886 stylesheetsclick: true
42888 this.defaultAutoCreate = {
42890 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42891 autocomplete: "new-password"
42896 * Protected method that will not generally be called directly. It
42897 * is called when the editor creates its toolbar. Override this method if you need to
42898 * add custom toolbar buttons.
42899 * @param {HtmlEditor} editor
42901 createToolbar : function(editor){
42902 Roo.log("create toolbars");
42903 if (!editor.toolbars || !editor.toolbars.length) {
42904 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42907 for (var i =0 ; i < editor.toolbars.length;i++) {
42908 editor.toolbars[i] = Roo.factory(
42909 typeof(editor.toolbars[i]) == 'string' ?
42910 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42911 Roo.form.HtmlEditor);
42912 editor.toolbars[i].init(editor);
42920 onRender : function(ct, position)
42923 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42925 this.wrap = this.el.wrap({
42926 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42929 this.editorcore.onRender(ct, position);
42931 if (this.resizable) {
42932 this.resizeEl = new Roo.Resizable(this.wrap, {
42936 minHeight : this.height,
42937 height: this.height,
42938 handles : this.resizable,
42941 resize : function(r, w, h) {
42942 _t.onResize(w,h); // -something
42948 this.createToolbar(this);
42952 this.setSize(this.wrap.getSize());
42954 if (this.resizeEl) {
42955 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42956 // should trigger onReize..
42959 this.keyNav = new Roo.KeyNav(this.el, {
42961 "tab" : function(e){
42962 e.preventDefault();
42964 var value = this.getValue();
42966 var start = this.el.dom.selectionStart;
42967 var end = this.el.dom.selectionEnd;
42971 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
42972 this.el.dom.setSelectionRange(end + 1, end + 1);
42976 var f = value.substring(0, start).split("\t");
42978 if(f.pop().length != 0){
42982 this.setValue(f.join("\t") + value.substring(end));
42983 this.el.dom.setSelectionRange(start - 1, start - 1);
42987 "home" : function(e){
42988 e.preventDefault();
42990 var curr = this.el.dom.selectionStart;
42991 var lines = this.getValue().split("\n");
42998 this.el.dom.setSelectionRange(0, 0);
43004 for (var i = 0; i < lines.length;i++) {
43005 pos += lines[i].length;
43015 pos -= lines[i].length;
43021 this.el.dom.setSelectionRange(pos, pos);
43025 this.el.dom.selectionStart = pos;
43026 this.el.dom.selectionEnd = curr;
43029 "end" : function(e){
43030 e.preventDefault();
43032 var curr = this.el.dom.selectionStart;
43033 var lines = this.getValue().split("\n");
43040 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43046 for (var i = 0; i < lines.length;i++) {
43048 pos += lines[i].length;
43062 this.el.dom.setSelectionRange(pos, pos);
43066 this.el.dom.selectionStart = curr;
43067 this.el.dom.selectionEnd = pos;
43072 doRelay : function(foo, bar, hname){
43073 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43079 // if(this.autosave && this.w){
43080 // this.autoSaveFn = setInterval(this.autosave, 1000);
43085 onResize : function(w, h)
43087 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43092 if(typeof w == 'number'){
43093 var aw = w - this.wrap.getFrameWidth('lr');
43094 this.el.setWidth(this.adjustWidth('textarea', aw));
43097 if(typeof h == 'number'){
43099 for (var i =0; i < this.toolbars.length;i++) {
43100 // fixme - ask toolbars for heights?
43101 tbh += this.toolbars[i].tb.el.getHeight();
43102 if (this.toolbars[i].footer) {
43103 tbh += this.toolbars[i].footer.el.getHeight();
43110 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43111 ah -= 5; // knock a few pixes off for look..
43113 this.el.setHeight(this.adjustWidth('textarea', ah));
43117 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43118 this.editorcore.onResize(ew,eh);
43123 * Toggles the editor between standard and source edit mode.
43124 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43126 toggleSourceEdit : function(sourceEditMode)
43128 this.editorcore.toggleSourceEdit(sourceEditMode);
43130 if(this.editorcore.sourceEditMode){
43131 Roo.log('editor - showing textarea');
43134 // Roo.log(this.syncValue());
43135 this.editorcore.syncValue();
43136 this.el.removeClass('x-hidden');
43137 this.el.dom.removeAttribute('tabIndex');
43140 for (var i = 0; i < this.toolbars.length; i++) {
43141 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43142 this.toolbars[i].tb.hide();
43143 this.toolbars[i].footer.hide();
43148 Roo.log('editor - hiding textarea');
43150 // Roo.log(this.pushValue());
43151 this.editorcore.pushValue();
43153 this.el.addClass('x-hidden');
43154 this.el.dom.setAttribute('tabIndex', -1);
43156 for (var i = 0; i < this.toolbars.length; i++) {
43157 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43158 this.toolbars[i].tb.show();
43159 this.toolbars[i].footer.show();
43163 //this.deferFocus();
43166 this.setSize(this.wrap.getSize());
43167 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43169 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43172 // private (for BoxComponent)
43173 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43175 // private (for BoxComponent)
43176 getResizeEl : function(){
43180 // private (for BoxComponent)
43181 getPositionEl : function(){
43186 initEvents : function(){
43187 this.originalValue = this.getValue();
43191 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43194 markInvalid : Roo.emptyFn,
43196 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43199 clearInvalid : Roo.emptyFn,
43201 setValue : function(v){
43202 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43203 this.editorcore.pushValue();
43208 deferFocus : function(){
43209 this.focus.defer(10, this);
43213 focus : function(){
43214 this.editorcore.focus();
43220 onDestroy : function(){
43226 for (var i =0; i < this.toolbars.length;i++) {
43227 // fixme - ask toolbars for heights?
43228 this.toolbars[i].onDestroy();
43231 this.wrap.dom.innerHTML = '';
43232 this.wrap.remove();
43237 onFirstFocus : function(){
43238 //Roo.log("onFirstFocus");
43239 this.editorcore.onFirstFocus();
43240 for (var i =0; i < this.toolbars.length;i++) {
43241 this.toolbars[i].onFirstFocus();
43247 syncValue : function()
43249 this.editorcore.syncValue();
43252 pushValue : function()
43254 this.editorcore.pushValue();
43257 setStylesheets : function(stylesheets)
43259 this.editorcore.setStylesheets(stylesheets);
43262 removeStylesheets : function()
43264 this.editorcore.removeStylesheets();
43268 // hide stuff that is not compatible
43282 * @event specialkey
43286 * @cfg {String} fieldClass @hide
43289 * @cfg {String} focusClass @hide
43292 * @cfg {String} autoCreate @hide
43295 * @cfg {String} inputType @hide
43298 * @cfg {String} invalidClass @hide
43301 * @cfg {String} invalidText @hide
43304 * @cfg {String} msgFx @hide
43307 * @cfg {String} validateOnBlur @hide
43311 // <script type="text/javascript">
43314 * Ext JS Library 1.1.1
43315 * Copyright(c) 2006-2007, Ext JS, LLC.
43321 * @class Roo.form.HtmlEditorToolbar1
43326 new Roo.form.HtmlEditor({
43329 new Roo.form.HtmlEditorToolbar1({
43330 disable : { fonts: 1 , format: 1, ..., ... , ...],
43336 * @cfg {Object} disable List of elements to disable..
43337 * @cfg {Array} btns List of additional buttons.
43341 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43344 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43347 Roo.apply(this, config);
43349 // default disabled, based on 'good practice'..
43350 this.disable = this.disable || {};
43351 Roo.applyIf(this.disable, {
43354 specialElements : true
43358 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43359 // dont call parent... till later.
43362 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43369 editorcore : false,
43371 * @cfg {Object} disable List of toolbar elements to disable
43378 * @cfg {String} createLinkText The default text for the create link prompt
43380 createLinkText : 'Please enter the URL for the link:',
43382 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43384 defaultLinkValue : 'http:/'+'/',
43388 * @cfg {Array} fontFamilies An array of available font families
43406 // "á" , ?? a acute?
43411 "°" // , // degrees
43413 // "é" , // e ecute
43414 // "ú" , // u ecute?
43417 specialElements : [
43419 text: "Insert Table",
43422 ihtml : '<table><tr><td>Cell</td></tr></table>'
43426 text: "Insert Image",
43429 ihtml : '<img src="about:blank"/>'
43438 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43439 "input:submit", "input:button", "select", "textarea", "label" ],
43442 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43444 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43452 * @cfg {String} defaultFont default font to use.
43454 defaultFont: 'tahoma',
43456 fontSelect : false,
43459 formatCombo : false,
43461 init : function(editor)
43463 this.editor = editor;
43464 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43465 var editorcore = this.editorcore;
43469 var fid = editorcore.frameId;
43471 function btn(id, toggle, handler){
43472 var xid = fid + '-'+ id ;
43476 cls : 'x-btn-icon x-edit-'+id,
43477 enableToggle:toggle !== false,
43478 scope: _t, // was editor...
43479 handler:handler||_t.relayBtnCmd,
43480 clickEvent:'mousedown',
43481 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43488 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43490 // stop form submits
43491 tb.el.on('click', function(e){
43492 e.preventDefault(); // what does this do?
43495 if(!this.disable.font) { // && !Roo.isSafari){
43496 /* why no safari for fonts
43497 editor.fontSelect = tb.el.createChild({
43500 cls:'x-font-select',
43501 html: this.createFontOptions()
43504 editor.fontSelect.on('change', function(){
43505 var font = editor.fontSelect.dom.value;
43506 editor.relayCmd('fontname', font);
43507 editor.deferFocus();
43511 editor.fontSelect.dom,
43517 if(!this.disable.formats){
43518 this.formatCombo = new Roo.form.ComboBox({
43519 store: new Roo.data.SimpleStore({
43522 data : this.formats // from states.js
43526 //autoCreate : {tag: "div", size: "20"},
43527 displayField:'tag',
43531 triggerAction: 'all',
43532 emptyText:'Add tag',
43533 selectOnFocus:true,
43536 'select': function(c, r, i) {
43537 editorcore.insertTag(r.get('tag'));
43543 tb.addField(this.formatCombo);
43547 if(!this.disable.format){
43554 if(!this.disable.fontSize){
43559 btn('increasefontsize', false, editorcore.adjustFont),
43560 btn('decreasefontsize', false, editorcore.adjustFont)
43565 if(!this.disable.colors){
43568 id:editorcore.frameId +'-forecolor',
43569 cls:'x-btn-icon x-edit-forecolor',
43570 clickEvent:'mousedown',
43571 tooltip: this.buttonTips['forecolor'] || undefined,
43573 menu : new Roo.menu.ColorMenu({
43574 allowReselect: true,
43575 focus: Roo.emptyFn,
43578 selectHandler: function(cp, color){
43579 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43580 editor.deferFocus();
43583 clickEvent:'mousedown'
43586 id:editorcore.frameId +'backcolor',
43587 cls:'x-btn-icon x-edit-backcolor',
43588 clickEvent:'mousedown',
43589 tooltip: this.buttonTips['backcolor'] || undefined,
43591 menu : new Roo.menu.ColorMenu({
43592 focus: Roo.emptyFn,
43595 allowReselect: true,
43596 selectHandler: function(cp, color){
43598 editorcore.execCmd('useCSS', false);
43599 editorcore.execCmd('hilitecolor', color);
43600 editorcore.execCmd('useCSS', true);
43601 editor.deferFocus();
43603 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43604 Roo.isSafari || Roo.isIE ? '#'+color : color);
43605 editor.deferFocus();
43609 clickEvent:'mousedown'
43614 // now add all the items...
43617 if(!this.disable.alignments){
43620 btn('justifyleft'),
43621 btn('justifycenter'),
43622 btn('justifyright')
43626 //if(!Roo.isSafari){
43627 if(!this.disable.links){
43630 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43634 if(!this.disable.lists){
43637 btn('insertorderedlist'),
43638 btn('insertunorderedlist')
43641 if(!this.disable.sourceEdit){
43644 btn('sourceedit', true, function(btn){
43645 this.toggleSourceEdit(btn.pressed);
43652 // special menu.. - needs to be tidied up..
43653 if (!this.disable.special) {
43656 cls: 'x-edit-none',
43662 for (var i =0; i < this.specialChars.length; i++) {
43663 smenu.menu.items.push({
43665 html: this.specialChars[i],
43666 handler: function(a,b) {
43667 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43668 //editor.insertAtCursor(a.html);
43682 if (!this.disable.cleanStyles) {
43684 cls: 'x-btn-icon x-btn-clear',
43690 for (var i =0; i < this.cleanStyles.length; i++) {
43691 cmenu.menu.items.push({
43692 actiontype : this.cleanStyles[i],
43693 html: 'Remove ' + this.cleanStyles[i],
43694 handler: function(a,b) {
43697 var c = Roo.get(editorcore.doc.body);
43698 c.select('[style]').each(function(s) {
43699 s.dom.style.removeProperty(a.actiontype);
43701 editorcore.syncValue();
43706 cmenu.menu.items.push({
43707 actiontype : 'word',
43708 html: 'Remove MS Word Formating',
43709 handler: function(a,b) {
43710 editorcore.cleanWord();
43711 editorcore.syncValue();
43716 cmenu.menu.items.push({
43717 actiontype : 'all',
43718 html: 'Remove All Styles',
43719 handler: function(a,b) {
43721 var c = Roo.get(editorcore.doc.body);
43722 c.select('[style]').each(function(s) {
43723 s.dom.removeAttribute('style');
43725 editorcore.syncValue();
43729 cmenu.menu.items.push({
43730 actiontype : 'word',
43731 html: 'Tidy HTML Source',
43732 handler: function(a,b) {
43733 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43734 editorcore.syncValue();
43743 if (!this.disable.specialElements) {
43746 cls: 'x-edit-none',
43751 for (var i =0; i < this.specialElements.length; i++) {
43752 semenu.menu.items.push(
43754 handler: function(a,b) {
43755 editor.insertAtCursor(this.ihtml);
43757 }, this.specialElements[i])
43769 for(var i =0; i< this.btns.length;i++) {
43770 var b = Roo.factory(this.btns[i],Roo.form);
43771 b.cls = 'x-edit-none';
43773 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43774 b.cls += ' x-init-enable';
43777 b.scope = editorcore;
43785 // disable everything...
43787 this.tb.items.each(function(item){
43790 item.id != editorcore.frameId+ '-sourceedit' &&
43791 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43797 this.rendered = true;
43799 // the all the btns;
43800 editor.on('editorevent', this.updateToolbar, this);
43801 // other toolbars need to implement this..
43802 //editor.on('editmodechange', this.updateToolbar, this);
43806 relayBtnCmd : function(btn) {
43807 this.editorcore.relayCmd(btn.cmd);
43809 // private used internally
43810 createLink : function(){
43811 Roo.log("create link?");
43812 var url = prompt(this.createLinkText, this.defaultLinkValue);
43813 if(url && url != 'http:/'+'/'){
43814 this.editorcore.relayCmd('createlink', url);
43820 * Protected method that will not generally be called directly. It triggers
43821 * a toolbar update by reading the markup state of the current selection in the editor.
43823 updateToolbar: function(){
43825 if(!this.editorcore.activated){
43826 this.editor.onFirstFocus();
43830 var btns = this.tb.items.map,
43831 doc = this.editorcore.doc,
43832 frameId = this.editorcore.frameId;
43834 if(!this.disable.font && !Roo.isSafari){
43836 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43837 if(name != this.fontSelect.dom.value){
43838 this.fontSelect.dom.value = name;
43842 if(!this.disable.format){
43843 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43844 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43845 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43847 if(!this.disable.alignments){
43848 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43849 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43850 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43852 if(!Roo.isSafari && !this.disable.lists){
43853 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43854 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43857 var ans = this.editorcore.getAllAncestors();
43858 if (this.formatCombo) {
43861 var store = this.formatCombo.store;
43862 this.formatCombo.setValue("");
43863 for (var i =0; i < ans.length;i++) {
43864 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43866 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43874 // hides menus... - so this cant be on a menu...
43875 Roo.menu.MenuMgr.hideAll();
43877 //this.editorsyncValue();
43881 createFontOptions : function(){
43882 var buf = [], fs = this.fontFamilies, ff, lc;
43886 for(var i = 0, len = fs.length; i< len; i++){
43888 lc = ff.toLowerCase();
43890 '<option value="',lc,'" style="font-family:',ff,';"',
43891 (this.defaultFont == lc ? ' selected="true">' : '>'),
43896 return buf.join('');
43899 toggleSourceEdit : function(sourceEditMode){
43901 Roo.log("toolbar toogle");
43902 if(sourceEditMode === undefined){
43903 sourceEditMode = !this.sourceEditMode;
43905 this.sourceEditMode = sourceEditMode === true;
43906 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43907 // just toggle the button?
43908 if(btn.pressed !== this.sourceEditMode){
43909 btn.toggle(this.sourceEditMode);
43913 if(sourceEditMode){
43914 Roo.log("disabling buttons");
43915 this.tb.items.each(function(item){
43916 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
43922 Roo.log("enabling buttons");
43923 if(this.editorcore.initialized){
43924 this.tb.items.each(function(item){
43930 Roo.log("calling toggole on editor");
43931 // tell the editor that it's been pressed..
43932 this.editor.toggleSourceEdit(sourceEditMode);
43936 * Object collection of toolbar tooltips for the buttons in the editor. The key
43937 * is the command id associated with that button and the value is a valid QuickTips object.
43942 title: 'Bold (Ctrl+B)',
43943 text: 'Make the selected text bold.',
43944 cls: 'x-html-editor-tip'
43947 title: 'Italic (Ctrl+I)',
43948 text: 'Make the selected text italic.',
43949 cls: 'x-html-editor-tip'
43957 title: 'Bold (Ctrl+B)',
43958 text: 'Make the selected text bold.',
43959 cls: 'x-html-editor-tip'
43962 title: 'Italic (Ctrl+I)',
43963 text: 'Make the selected text italic.',
43964 cls: 'x-html-editor-tip'
43967 title: 'Underline (Ctrl+U)',
43968 text: 'Underline the selected text.',
43969 cls: 'x-html-editor-tip'
43971 increasefontsize : {
43972 title: 'Grow Text',
43973 text: 'Increase the font size.',
43974 cls: 'x-html-editor-tip'
43976 decreasefontsize : {
43977 title: 'Shrink Text',
43978 text: 'Decrease the font size.',
43979 cls: 'x-html-editor-tip'
43982 title: 'Text Highlight Color',
43983 text: 'Change the background color of the selected text.',
43984 cls: 'x-html-editor-tip'
43987 title: 'Font Color',
43988 text: 'Change the color of the selected text.',
43989 cls: 'x-html-editor-tip'
43992 title: 'Align Text Left',
43993 text: 'Align text to the left.',
43994 cls: 'x-html-editor-tip'
43997 title: 'Center Text',
43998 text: 'Center text in the editor.',
43999 cls: 'x-html-editor-tip'
44002 title: 'Align Text Right',
44003 text: 'Align text to the right.',
44004 cls: 'x-html-editor-tip'
44006 insertunorderedlist : {
44007 title: 'Bullet List',
44008 text: 'Start a bulleted list.',
44009 cls: 'x-html-editor-tip'
44011 insertorderedlist : {
44012 title: 'Numbered List',
44013 text: 'Start a numbered list.',
44014 cls: 'x-html-editor-tip'
44017 title: 'Hyperlink',
44018 text: 'Make the selected text a hyperlink.',
44019 cls: 'x-html-editor-tip'
44022 title: 'Source Edit',
44023 text: 'Switch to source editing mode.',
44024 cls: 'x-html-editor-tip'
44028 onDestroy : function(){
44031 this.tb.items.each(function(item){
44033 item.menu.removeAll();
44035 item.menu.el.destroy();
44043 onFirstFocus: function() {
44044 this.tb.items.each(function(item){
44053 // <script type="text/javascript">
44056 * Ext JS Library 1.1.1
44057 * Copyright(c) 2006-2007, Ext JS, LLC.
44064 * @class Roo.form.HtmlEditor.ToolbarContext
44069 new Roo.form.HtmlEditor({
44072 { xtype: 'ToolbarStandard', styles : {} }
44073 { xtype: 'ToolbarContext', disable : {} }
44079 * @config : {Object} disable List of elements to disable.. (not done yet.)
44080 * @config : {Object} styles Map of styles available.
44084 Roo.form.HtmlEditor.ToolbarContext = function(config)
44087 Roo.apply(this, config);
44088 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44089 // dont call parent... till later.
44090 this.styles = this.styles || {};
44095 Roo.form.HtmlEditor.ToolbarContext.types = {
44107 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44173 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44178 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44188 style : 'fontFamily',
44189 displayField: 'display',
44190 optname : 'font-family',
44239 // should we really allow this??
44240 // should this just be
44251 style : 'fontFamily',
44252 displayField: 'display',
44253 optname : 'font-family',
44260 style : 'fontFamily',
44261 displayField: 'display',
44262 optname : 'font-family',
44269 style : 'fontFamily',
44270 displayField: 'display',
44271 optname : 'font-family',
44282 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44283 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44285 Roo.form.HtmlEditor.ToolbarContext.options = {
44287 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44288 [ 'Courier New', 'Courier New'],
44289 [ 'Tahoma', 'Tahoma'],
44290 [ 'Times New Roman,serif', 'Times'],
44291 [ 'Verdana','Verdana' ]
44295 // fixme - these need to be configurable..
44298 Roo.form.HtmlEditor.ToolbarContext.types
44301 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44308 editorcore : false,
44310 * @cfg {Object} disable List of toolbar elements to disable
44315 * @cfg {Object} styles List of styles
44316 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44318 * These must be defined in the page, so they get rendered correctly..
44329 init : function(editor)
44331 this.editor = editor;
44332 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44333 var editorcore = this.editorcore;
44335 var fid = editorcore.frameId;
44337 function btn(id, toggle, handler){
44338 var xid = fid + '-'+ id ;
44342 cls : 'x-btn-icon x-edit-'+id,
44343 enableToggle:toggle !== false,
44344 scope: editorcore, // was editor...
44345 handler:handler||editorcore.relayBtnCmd,
44346 clickEvent:'mousedown',
44347 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44351 // create a new element.
44352 var wdiv = editor.wrap.createChild({
44354 }, editor.wrap.dom.firstChild.nextSibling, true);
44356 // can we do this more than once??
44358 // stop form submits
44361 // disable everything...
44362 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44363 this.toolbars = {};
44365 for (var i in ty) {
44367 this.toolbars[i] = this.buildToolbar(ty[i],i);
44369 this.tb = this.toolbars.BODY;
44371 this.buildFooter();
44372 this.footer.show();
44373 editor.on('hide', function( ) { this.footer.hide() }, this);
44374 editor.on('show', function( ) { this.footer.show() }, this);
44377 this.rendered = true;
44379 // the all the btns;
44380 editor.on('editorevent', this.updateToolbar, this);
44381 // other toolbars need to implement this..
44382 //editor.on('editmodechange', this.updateToolbar, this);
44388 * Protected method that will not generally be called directly. It triggers
44389 * a toolbar update by reading the markup state of the current selection in the editor.
44391 updateToolbar: function(editor,ev,sel){
44394 // capture mouse up - this is handy for selecting images..
44395 // perhaps should go somewhere else...
44396 if(!this.editorcore.activated){
44397 this.editor.onFirstFocus();
44401 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44402 // selectNode - might want to handle IE?
44404 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44405 ev.target && ev.target.tagName == 'IMG') {
44406 // they have click on an image...
44407 // let's see if we can change the selection...
44410 var nodeRange = sel.ownerDocument.createRange();
44412 nodeRange.selectNode(sel);
44414 nodeRange.selectNodeContents(sel);
44416 //nodeRange.collapse(true);
44417 var s = this.editorcore.win.getSelection();
44418 s.removeAllRanges();
44419 s.addRange(nodeRange);
44423 var updateFooter = sel ? false : true;
44426 var ans = this.editorcore.getAllAncestors();
44429 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44432 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44433 sel = sel ? sel : this.editorcore.doc.body;
44434 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44437 // pick a menu that exists..
44438 var tn = sel.tagName.toUpperCase();
44439 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44441 tn = sel.tagName.toUpperCase();
44443 var lastSel = this.tb.selectedNode
44445 this.tb.selectedNode = sel;
44447 // if current menu does not match..
44448 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
44451 ///console.log("show: " + tn);
44452 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44455 this.tb.items.first().el.innerHTML = tn + ': ';
44458 // update attributes
44459 if (this.tb.fields) {
44460 this.tb.fields.each(function(e) {
44462 e.setValue(sel.style[e.stylename]);
44465 e.setValue(sel.getAttribute(e.attrname));
44469 var hasStyles = false;
44470 for(var i in this.styles) {
44477 var st = this.tb.fields.item(0);
44479 st.store.removeAll();
44482 var cn = sel.className.split(/\s+/);
44485 if (this.styles['*']) {
44487 Roo.each(this.styles['*'], function(v) {
44488 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44491 if (this.styles[tn]) {
44492 Roo.each(this.styles[tn], function(v) {
44493 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44497 st.store.loadData(avs);
44501 // flag our selected Node.
44502 this.tb.selectedNode = sel;
44505 Roo.menu.MenuMgr.hideAll();
44509 if (!updateFooter) {
44510 //this.footDisp.dom.innerHTML = '';
44513 // update the footer
44517 this.footerEls = ans.reverse();
44518 Roo.each(this.footerEls, function(a,i) {
44519 if (!a) { return; }
44520 html += html.length ? ' > ' : '';
44522 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44527 var sz = this.footDisp.up('td').getSize();
44528 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44529 this.footDisp.dom.style.marginLeft = '5px';
44531 this.footDisp.dom.style.overflow = 'hidden';
44533 this.footDisp.dom.innerHTML = html;
44535 //this.editorsyncValue();
44542 onDestroy : function(){
44545 this.tb.items.each(function(item){
44547 item.menu.removeAll();
44549 item.menu.el.destroy();
44557 onFirstFocus: function() {
44558 // need to do this for all the toolbars..
44559 this.tb.items.each(function(item){
44563 buildToolbar: function(tlist, nm)
44565 var editor = this.editor;
44566 var editorcore = this.editorcore;
44567 // create a new element.
44568 var wdiv = editor.wrap.createChild({
44570 }, editor.wrap.dom.firstChild.nextSibling, true);
44573 var tb = new Roo.Toolbar(wdiv);
44576 tb.add(nm+ ": ");
44579 for(var i in this.styles) {
44584 if (styles && styles.length) {
44586 // this needs a multi-select checkbox...
44587 tb.addField( new Roo.form.ComboBox({
44588 store: new Roo.data.SimpleStore({
44590 fields: ['val', 'selected'],
44593 name : '-roo-edit-className',
44594 attrname : 'className',
44595 displayField: 'val',
44599 triggerAction: 'all',
44600 emptyText:'Select Style',
44601 selectOnFocus:true,
44604 'select': function(c, r, i) {
44605 // initial support only for on class per el..
44606 tb.selectedNode.className = r ? r.get('val') : '';
44607 editorcore.syncValue();
44614 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44615 var tbops = tbc.options;
44617 for (var i in tlist) {
44619 var item = tlist[i];
44620 tb.add(item.title + ": ");
44623 //optname == used so you can configure the options available..
44624 var opts = item.opts ? item.opts : false;
44625 if (item.optname) {
44626 opts = tbops[item.optname];
44631 // opts == pulldown..
44632 tb.addField( new Roo.form.ComboBox({
44633 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44635 fields: ['val', 'display'],
44638 name : '-roo-edit-' + i,
44640 stylename : item.style ? item.style : false,
44641 displayField: item.displayField ? item.displayField : 'val',
44642 valueField : 'val',
44644 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44646 triggerAction: 'all',
44647 emptyText:'Select',
44648 selectOnFocus:true,
44649 width: item.width ? item.width : 130,
44651 'select': function(c, r, i) {
44653 tb.selectedNode.style[c.stylename] = r.get('val');
44656 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44665 tb.addField( new Roo.form.TextField({
44668 //allowBlank:false,
44673 tb.addField( new Roo.form.TextField({
44674 name: '-roo-edit-' + i,
44681 'change' : function(f, nv, ov) {
44682 tb.selectedNode.setAttribute(f.attrname, nv);
44695 text: 'Stylesheets',
44698 click : function ()
44700 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44708 text: 'Remove Tag',
44711 click : function ()
44714 // undo does not work.
44716 var sn = tb.selectedNode;
44718 var pn = sn.parentNode;
44720 var stn = sn.childNodes[0];
44721 var en = sn.childNodes[sn.childNodes.length - 1 ];
44722 while (sn.childNodes.length) {
44723 var node = sn.childNodes[0];
44724 sn.removeChild(node);
44726 pn.insertBefore(node, sn);
44729 pn.removeChild(sn);
44730 var range = editorcore.createRange();
44732 range.setStart(stn,0);
44733 range.setEnd(en,0); //????
44734 //range.selectNode(sel);
44737 var selection = editorcore.getSelection();
44738 selection.removeAllRanges();
44739 selection.addRange(range);
44743 //_this.updateToolbar(null, null, pn);
44744 _this.updateToolbar(null, null, null);
44745 _this.footDisp.dom.innerHTML = '';
44755 tb.el.on('click', function(e){
44756 e.preventDefault(); // what does this do?
44758 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44761 // dont need to disable them... as they will get hidden
44766 buildFooter : function()
44769 var fel = this.editor.wrap.createChild();
44770 this.footer = new Roo.Toolbar(fel);
44771 // toolbar has scrolly on left / right?
44772 var footDisp= new Roo.Toolbar.Fill();
44778 handler : function() {
44779 _t.footDisp.scrollTo('left',0,true)
44783 this.footer.add( footDisp );
44788 handler : function() {
44790 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44794 var fel = Roo.get(footDisp.el);
44795 fel.addClass('x-editor-context');
44796 this.footDispWrap = fel;
44797 this.footDispWrap.overflow = 'hidden';
44799 this.footDisp = fel.createChild();
44800 this.footDispWrap.on('click', this.onContextClick, this)
44804 onContextClick : function (ev,dom)
44806 ev.preventDefault();
44807 var cn = dom.className;
44809 if (!cn.match(/x-ed-loc-/)) {
44812 var n = cn.split('-').pop();
44813 var ans = this.footerEls;
44817 var range = this.editorcore.createRange();
44819 range.selectNodeContents(sel);
44820 //range.selectNode(sel);
44823 var selection = this.editorcore.getSelection();
44824 selection.removeAllRanges();
44825 selection.addRange(range);
44829 this.updateToolbar(null, null, sel);
44846 * Ext JS Library 1.1.1
44847 * Copyright(c) 2006-2007, Ext JS, LLC.
44849 * Originally Released Under LGPL - original licence link has changed is not relivant.
44852 * <script type="text/javascript">
44856 * @class Roo.form.BasicForm
44857 * @extends Roo.util.Observable
44858 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44860 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44861 * @param {Object} config Configuration options
44863 Roo.form.BasicForm = function(el, config){
44864 this.allItems = [];
44865 this.childForms = [];
44866 Roo.apply(this, config);
44868 * The Roo.form.Field items in this form.
44869 * @type MixedCollection
44873 this.items = new Roo.util.MixedCollection(false, function(o){
44874 return o.id || (o.id = Roo.id());
44878 * @event beforeaction
44879 * Fires before any action is performed. Return false to cancel the action.
44880 * @param {Form} this
44881 * @param {Action} action The action to be performed
44883 beforeaction: true,
44885 * @event actionfailed
44886 * Fires when an action fails.
44887 * @param {Form} this
44888 * @param {Action} action The action that failed
44890 actionfailed : true,
44892 * @event actioncomplete
44893 * Fires when an action is completed.
44894 * @param {Form} this
44895 * @param {Action} action The action that completed
44897 actioncomplete : true
44902 Roo.form.BasicForm.superclass.constructor.call(this);
44905 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44907 * @cfg {String} method
44908 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44911 * @cfg {DataReader} reader
44912 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44913 * This is optional as there is built-in support for processing JSON.
44916 * @cfg {DataReader} errorReader
44917 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44918 * This is completely optional as there is built-in support for processing JSON.
44921 * @cfg {String} url
44922 * The URL to use for form actions if one isn't supplied in the action options.
44925 * @cfg {Boolean} fileUpload
44926 * Set to true if this form is a file upload.
44930 * @cfg {Object} baseParams
44931 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44936 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44941 activeAction : null,
44944 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44945 * or setValues() data instead of when the form was first created.
44947 trackResetOnLoad : false,
44951 * childForms - used for multi-tab forms
44954 childForms : false,
44957 * allItems - full list of fields.
44963 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44964 * element by passing it or its id or mask the form itself by passing in true.
44967 waitMsgTarget : false,
44970 initEl : function(el){
44971 this.el = Roo.get(el);
44972 this.id = this.el.id || Roo.id();
44973 this.el.on('submit', this.onSubmit, this);
44974 this.el.addClass('x-form');
44978 onSubmit : function(e){
44983 * Returns true if client-side validation on the form is successful.
44986 isValid : function(){
44988 this.items.each(function(f){
44997 * Returns true if any fields in this form have changed since their original load.
45000 isDirty : function(){
45002 this.items.each(function(f){
45012 * Performs a predefined action (submit or load) or custom actions you define on this form.
45013 * @param {String} actionName The name of the action type
45014 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45015 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45016 * accept other config options):
45018 Property Type Description
45019 ---------------- --------------- ----------------------------------------------------------------------------------
45020 url String The url for the action (defaults to the form's url)
45021 method String The form method to use (defaults to the form's method, or POST if not defined)
45022 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45023 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45024 validate the form on the client (defaults to false)
45026 * @return {BasicForm} this
45028 doAction : function(action, options){
45029 if(typeof action == 'string'){
45030 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45032 if(this.fireEvent('beforeaction', this, action) !== false){
45033 this.beforeAction(action);
45034 action.run.defer(100, action);
45040 * Shortcut to do a submit action.
45041 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45042 * @return {BasicForm} this
45044 submit : function(options){
45045 this.doAction('submit', options);
45050 * Shortcut to do a load action.
45051 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45052 * @return {BasicForm} this
45054 load : function(options){
45055 this.doAction('load', options);
45060 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45061 * @param {Record} record The record to edit
45062 * @return {BasicForm} this
45064 updateRecord : function(record){
45065 record.beginEdit();
45066 var fs = record.fields;
45067 fs.each(function(f){
45068 var field = this.findField(f.name);
45070 record.set(f.name, field.getValue());
45078 * Loads an Roo.data.Record into this form.
45079 * @param {Record} record The record to load
45080 * @return {BasicForm} this
45082 loadRecord : function(record){
45083 this.setValues(record.data);
45088 beforeAction : function(action){
45089 var o = action.options;
45092 if(this.waitMsgTarget === true){
45093 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45094 }else if(this.waitMsgTarget){
45095 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45096 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45098 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45104 afterAction : function(action, success){
45105 this.activeAction = null;
45106 var o = action.options;
45108 if(this.waitMsgTarget === true){
45110 }else if(this.waitMsgTarget){
45111 this.waitMsgTarget.unmask();
45113 Roo.MessageBox.updateProgress(1);
45114 Roo.MessageBox.hide();
45121 Roo.callback(o.success, o.scope, [this, action]);
45122 this.fireEvent('actioncomplete', this, action);
45126 // failure condition..
45127 // we have a scenario where updates need confirming.
45128 // eg. if a locking scenario exists..
45129 // we look for { errors : { needs_confirm : true }} in the response.
45131 (typeof(action.result) != 'undefined') &&
45132 (typeof(action.result.errors) != 'undefined') &&
45133 (typeof(action.result.errors.needs_confirm) != 'undefined')
45136 Roo.MessageBox.confirm(
45137 "Change requires confirmation",
45138 action.result.errorMsg,
45143 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45153 Roo.callback(o.failure, o.scope, [this, action]);
45154 // show an error message if no failed handler is set..
45155 if (!this.hasListener('actionfailed')) {
45156 Roo.MessageBox.alert("Error",
45157 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45158 action.result.errorMsg :
45159 "Saving Failed, please check your entries or try again"
45163 this.fireEvent('actionfailed', this, action);
45169 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45170 * @param {String} id The value to search for
45173 findField : function(id){
45174 var field = this.items.get(id);
45176 this.items.each(function(f){
45177 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45183 return field || null;
45187 * Add a secondary form to this one,
45188 * Used to provide tabbed forms. One form is primary, with hidden values
45189 * which mirror the elements from the other forms.
45191 * @param {Roo.form.Form} form to add.
45194 addForm : function(form)
45197 if (this.childForms.indexOf(form) > -1) {
45201 this.childForms.push(form);
45203 Roo.each(form.allItems, function (fe) {
45205 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45206 if (this.findField(n)) { // already added..
45209 var add = new Roo.form.Hidden({
45212 add.render(this.el);
45219 * Mark fields in this form invalid in bulk.
45220 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45221 * @return {BasicForm} this
45223 markInvalid : function(errors){
45224 if(errors instanceof Array){
45225 for(var i = 0, len = errors.length; i < len; i++){
45226 var fieldError = errors[i];
45227 var f = this.findField(fieldError.id);
45229 f.markInvalid(fieldError.msg);
45235 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45236 field.markInvalid(errors[id]);
45240 Roo.each(this.childForms || [], function (f) {
45241 f.markInvalid(errors);
45248 * Set values for fields in this form in bulk.
45249 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45250 * @return {BasicForm} this
45252 setValues : function(values){
45253 if(values instanceof Array){ // array of objects
45254 for(var i = 0, len = values.length; i < len; i++){
45256 var f = this.findField(v.id);
45258 f.setValue(v.value);
45259 if(this.trackResetOnLoad){
45260 f.originalValue = f.getValue();
45264 }else{ // object hash
45267 if(typeof values[id] != 'function' && (field = this.findField(id))){
45269 if (field.setFromData &&
45270 field.valueField &&
45271 field.displayField &&
45272 // combos' with local stores can
45273 // be queried via setValue()
45274 // to set their value..
45275 (field.store && !field.store.isLocal)
45279 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45280 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45281 field.setFromData(sd);
45284 field.setValue(values[id]);
45288 if(this.trackResetOnLoad){
45289 field.originalValue = field.getValue();
45295 Roo.each(this.childForms || [], function (f) {
45296 f.setValues(values);
45303 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45304 * they are returned as an array.
45305 * @param {Boolean} asString
45308 getValues : function(asString){
45309 if (this.childForms) {
45310 // copy values from the child forms
45311 Roo.each(this.childForms, function (f) {
45312 this.setValues(f.getValues());
45318 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45319 if(asString === true){
45322 return Roo.urlDecode(fs);
45326 * Returns the fields in this form as an object with key/value pairs.
45327 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45330 getFieldValues : function(with_hidden)
45332 if (this.childForms) {
45333 // copy values from the child forms
45334 // should this call getFieldValues - probably not as we do not currently copy
45335 // hidden fields when we generate..
45336 Roo.each(this.childForms, function (f) {
45337 this.setValues(f.getValues());
45342 this.items.each(function(f){
45343 if (!f.getName()) {
45346 var v = f.getValue();
45347 if (f.inputType =='radio') {
45348 if (typeof(ret[f.getName()]) == 'undefined') {
45349 ret[f.getName()] = ''; // empty..
45352 if (!f.el.dom.checked) {
45356 v = f.el.dom.value;
45360 // not sure if this supported any more..
45361 if ((typeof(v) == 'object') && f.getRawValue) {
45362 v = f.getRawValue() ; // dates..
45364 // combo boxes where name != hiddenName...
45365 if (f.name != f.getName()) {
45366 ret[f.name] = f.getRawValue();
45368 ret[f.getName()] = v;
45375 * Clears all invalid messages in this form.
45376 * @return {BasicForm} this
45378 clearInvalid : function(){
45379 this.items.each(function(f){
45383 Roo.each(this.childForms || [], function (f) {
45392 * Resets this form.
45393 * @return {BasicForm} this
45395 reset : function(){
45396 this.items.each(function(f){
45400 Roo.each(this.childForms || [], function (f) {
45409 * Add Roo.form components to this form.
45410 * @param {Field} field1
45411 * @param {Field} field2 (optional)
45412 * @param {Field} etc (optional)
45413 * @return {BasicForm} this
45416 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45422 * Removes a field from the items collection (does NOT remove its markup).
45423 * @param {Field} field
45424 * @return {BasicForm} this
45426 remove : function(field){
45427 this.items.remove(field);
45432 * Looks at the fields in this form, checks them for an id attribute,
45433 * and calls applyTo on the existing dom element with that id.
45434 * @return {BasicForm} this
45436 render : function(){
45437 this.items.each(function(f){
45438 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45446 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45447 * @param {Object} values
45448 * @return {BasicForm} this
45450 applyToFields : function(o){
45451 this.items.each(function(f){
45458 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45459 * @param {Object} values
45460 * @return {BasicForm} this
45462 applyIfToFields : function(o){
45463 this.items.each(function(f){
45471 Roo.BasicForm = Roo.form.BasicForm;/*
45473 * Ext JS Library 1.1.1
45474 * Copyright(c) 2006-2007, Ext JS, LLC.
45476 * Originally Released Under LGPL - original licence link has changed is not relivant.
45479 * <script type="text/javascript">
45483 * @class Roo.form.Form
45484 * @extends Roo.form.BasicForm
45485 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45487 * @param {Object} config Configuration options
45489 Roo.form.Form = function(config){
45491 if (config.items) {
45492 xitems = config.items;
45493 delete config.items;
45497 Roo.form.Form.superclass.constructor.call(this, null, config);
45498 this.url = this.url || this.action;
45500 this.root = new Roo.form.Layout(Roo.applyIf({
45504 this.active = this.root;
45506 * Array of all the buttons that have been added to this form via {@link addButton}
45510 this.allItems = [];
45513 * @event clientvalidation
45514 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45515 * @param {Form} this
45516 * @param {Boolean} valid true if the form has passed client-side validation
45518 clientvalidation: true,
45521 * Fires when the form is rendered
45522 * @param {Roo.form.Form} form
45527 if (this.progressUrl) {
45528 // push a hidden field onto the list of fields..
45532 name : 'UPLOAD_IDENTIFIER'
45537 Roo.each(xitems, this.addxtype, this);
45543 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45545 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45548 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45551 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45553 buttonAlign:'center',
45556 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45561 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45562 * This property cascades to child containers if not set.
45567 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45568 * fires a looping event with that state. This is required to bind buttons to the valid
45569 * state using the config value formBind:true on the button.
45571 monitorValid : false,
45574 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45579 * @cfg {String} progressUrl - Url to return progress data
45582 progressUrl : false,
45585 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45586 * fields are added and the column is closed. If no fields are passed the column remains open
45587 * until end() is called.
45588 * @param {Object} config The config to pass to the column
45589 * @param {Field} field1 (optional)
45590 * @param {Field} field2 (optional)
45591 * @param {Field} etc (optional)
45592 * @return Column The column container object
45594 column : function(c){
45595 var col = new Roo.form.Column(c);
45597 if(arguments.length > 1){ // duplicate code required because of Opera
45598 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45605 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45606 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45607 * until end() is called.
45608 * @param {Object} config The config to pass to the fieldset
45609 * @param {Field} field1 (optional)
45610 * @param {Field} field2 (optional)
45611 * @param {Field} etc (optional)
45612 * @return FieldSet The fieldset container object
45614 fieldset : function(c){
45615 var fs = new Roo.form.FieldSet(c);
45617 if(arguments.length > 1){ // duplicate code required because of Opera
45618 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45625 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45626 * fields are added and the container is closed. If no fields are passed the container remains open
45627 * until end() is called.
45628 * @param {Object} config The config to pass to the Layout
45629 * @param {Field} field1 (optional)
45630 * @param {Field} field2 (optional)
45631 * @param {Field} etc (optional)
45632 * @return Layout The container object
45634 container : function(c){
45635 var l = new Roo.form.Layout(c);
45637 if(arguments.length > 1){ // duplicate code required because of Opera
45638 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45645 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45646 * @param {Object} container A Roo.form.Layout or subclass of Layout
45647 * @return {Form} this
45649 start : function(c){
45650 // cascade label info
45651 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45652 this.active.stack.push(c);
45653 c.ownerCt = this.active;
45659 * Closes the current open container
45660 * @return {Form} this
45663 if(this.active == this.root){
45666 this.active = this.active.ownerCt;
45671 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45672 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45673 * as the label of the field.
45674 * @param {Field} field1
45675 * @param {Field} field2 (optional)
45676 * @param {Field} etc. (optional)
45677 * @return {Form} this
45680 this.active.stack.push.apply(this.active.stack, arguments);
45681 this.allItems.push.apply(this.allItems,arguments);
45683 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45684 if(a[i].isFormField){
45689 Roo.form.Form.superclass.add.apply(this, r);
45699 * Find any element that has been added to a form, using it's ID or name
45700 * This can include framesets, columns etc. along with regular fields..
45701 * @param {String} id - id or name to find.
45703 * @return {Element} e - or false if nothing found.
45705 findbyId : function(id)
45711 Roo.each(this.allItems, function(f){
45712 if (f.id == id || f.name == id ){
45723 * Render this form into the passed container. This should only be called once!
45724 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45725 * @return {Form} this
45727 render : function(ct)
45733 var o = this.autoCreate || {
45735 method : this.method || 'POST',
45736 id : this.id || Roo.id()
45738 this.initEl(ct.createChild(o));
45740 this.root.render(this.el);
45744 this.items.each(function(f){
45745 f.render('x-form-el-'+f.id);
45748 if(this.buttons.length > 0){
45749 // tables are required to maintain order and for correct IE layout
45750 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45751 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45752 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45754 var tr = tb.getElementsByTagName('tr')[0];
45755 for(var i = 0, len = this.buttons.length; i < len; i++) {
45756 var b = this.buttons[i];
45757 var td = document.createElement('td');
45758 td.className = 'x-form-btn-td';
45759 b.render(tr.appendChild(td));
45762 if(this.monitorValid){ // initialize after render
45763 this.startMonitoring();
45765 this.fireEvent('rendered', this);
45770 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45771 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45772 * object or a valid Roo.DomHelper element config
45773 * @param {Function} handler The function called when the button is clicked
45774 * @param {Object} scope (optional) The scope of the handler function
45775 * @return {Roo.Button}
45777 addButton : function(config, handler, scope){
45781 minWidth: this.minButtonWidth,
45784 if(typeof config == "string"){
45787 Roo.apply(bc, config);
45789 var btn = new Roo.Button(null, bc);
45790 this.buttons.push(btn);
45795 * Adds a series of form elements (using the xtype property as the factory method.
45796 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45797 * @param {Object} config
45800 addxtype : function()
45802 var ar = Array.prototype.slice.call(arguments, 0);
45804 for(var i = 0; i < ar.length; i++) {
45806 continue; // skip -- if this happends something invalid got sent, we
45807 // should ignore it, as basically that interface element will not show up
45808 // and that should be pretty obvious!!
45811 if (Roo.form[ar[i].xtype]) {
45813 var fe = Roo.factory(ar[i], Roo.form);
45819 fe.store.form = this;
45824 this.allItems.push(fe);
45825 if (fe.items && fe.addxtype) {
45826 fe.addxtype.apply(fe, fe.items);
45836 // console.log('adding ' + ar[i].xtype);
45838 if (ar[i].xtype == 'Button') {
45839 //console.log('adding button');
45840 //console.log(ar[i]);
45841 this.addButton(ar[i]);
45842 this.allItems.push(fe);
45846 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45847 alert('end is not supported on xtype any more, use items');
45849 // //console.log('adding end');
45857 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45858 * option "monitorValid"
45860 startMonitoring : function(){
45863 Roo.TaskMgr.start({
45864 run : this.bindHandler,
45865 interval : this.monitorPoll || 200,
45872 * Stops monitoring of the valid state of this form
45874 stopMonitoring : function(){
45875 this.bound = false;
45879 bindHandler : function(){
45881 return false; // stops binding
45884 this.items.each(function(f){
45885 if(!f.isValid(true)){
45890 for(var i = 0, len = this.buttons.length; i < len; i++){
45891 var btn = this.buttons[i];
45892 if(btn.formBind === true && btn.disabled === valid){
45893 btn.setDisabled(!valid);
45896 this.fireEvent('clientvalidation', this, valid);
45910 Roo.Form = Roo.form.Form;
45913 * Ext JS Library 1.1.1
45914 * Copyright(c) 2006-2007, Ext JS, LLC.
45916 * Originally Released Under LGPL - original licence link has changed is not relivant.
45919 * <script type="text/javascript">
45922 // as we use this in bootstrap.
45923 Roo.namespace('Roo.form');
45925 * @class Roo.form.Action
45926 * Internal Class used to handle form actions
45928 * @param {Roo.form.BasicForm} el The form element or its id
45929 * @param {Object} config Configuration options
45934 // define the action interface
45935 Roo.form.Action = function(form, options){
45937 this.options = options || {};
45940 * Client Validation Failed
45943 Roo.form.Action.CLIENT_INVALID = 'client';
45945 * Server Validation Failed
45948 Roo.form.Action.SERVER_INVALID = 'server';
45950 * Connect to Server Failed
45953 Roo.form.Action.CONNECT_FAILURE = 'connect';
45955 * Reading Data from Server Failed
45958 Roo.form.Action.LOAD_FAILURE = 'load';
45960 Roo.form.Action.prototype = {
45962 failureType : undefined,
45963 response : undefined,
45964 result : undefined,
45966 // interface method
45967 run : function(options){
45971 // interface method
45972 success : function(response){
45976 // interface method
45977 handleResponse : function(response){
45981 // default connection failure
45982 failure : function(response){
45984 this.response = response;
45985 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45986 this.form.afterAction(this, false);
45989 processResponse : function(response){
45990 this.response = response;
45991 if(!response.responseText){
45994 this.result = this.handleResponse(response);
45995 return this.result;
45998 // utility functions used internally
45999 getUrl : function(appendParams){
46000 var url = this.options.url || this.form.url || this.form.el.dom.action;
46002 var p = this.getParams();
46004 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46010 getMethod : function(){
46011 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46014 getParams : function(){
46015 var bp = this.form.baseParams;
46016 var p = this.options.params;
46018 if(typeof p == "object"){
46019 p = Roo.urlEncode(Roo.applyIf(p, bp));
46020 }else if(typeof p == 'string' && bp){
46021 p += '&' + Roo.urlEncode(bp);
46024 p = Roo.urlEncode(bp);
46029 createCallback : function(){
46031 success: this.success,
46032 failure: this.failure,
46034 timeout: (this.form.timeout*1000),
46035 upload: this.form.fileUpload ? this.success : undefined
46040 Roo.form.Action.Submit = function(form, options){
46041 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46044 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46047 haveProgress : false,
46048 uploadComplete : false,
46050 // uploadProgress indicator.
46051 uploadProgress : function()
46053 if (!this.form.progressUrl) {
46057 if (!this.haveProgress) {
46058 Roo.MessageBox.progress("Uploading", "Uploading");
46060 if (this.uploadComplete) {
46061 Roo.MessageBox.hide();
46065 this.haveProgress = true;
46067 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46069 var c = new Roo.data.Connection();
46071 url : this.form.progressUrl,
46076 success : function(req){
46077 //console.log(data);
46081 rdata = Roo.decode(req.responseText)
46083 Roo.log("Invalid data from server..");
46087 if (!rdata || !rdata.success) {
46089 Roo.MessageBox.alert(Roo.encode(rdata));
46092 var data = rdata.data;
46094 if (this.uploadComplete) {
46095 Roo.MessageBox.hide();
46100 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46101 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46104 this.uploadProgress.defer(2000,this);
46107 failure: function(data) {
46108 Roo.log('progress url failed ');
46119 // run get Values on the form, so it syncs any secondary forms.
46120 this.form.getValues();
46122 var o = this.options;
46123 var method = this.getMethod();
46124 var isPost = method == 'POST';
46125 if(o.clientValidation === false || this.form.isValid()){
46127 if (this.form.progressUrl) {
46128 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46129 (new Date() * 1) + '' + Math.random());
46134 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46135 form:this.form.el.dom,
46136 url:this.getUrl(!isPost),
46138 params:isPost ? this.getParams() : null,
46139 isUpload: this.form.fileUpload
46142 this.uploadProgress();
46144 }else if (o.clientValidation !== false){ // client validation failed
46145 this.failureType = Roo.form.Action.CLIENT_INVALID;
46146 this.form.afterAction(this, false);
46150 success : function(response)
46152 this.uploadComplete= true;
46153 if (this.haveProgress) {
46154 Roo.MessageBox.hide();
46158 var result = this.processResponse(response);
46159 if(result === true || result.success){
46160 this.form.afterAction(this, true);
46164 this.form.markInvalid(result.errors);
46165 this.failureType = Roo.form.Action.SERVER_INVALID;
46167 this.form.afterAction(this, false);
46169 failure : function(response)
46171 this.uploadComplete= true;
46172 if (this.haveProgress) {
46173 Roo.MessageBox.hide();
46176 this.response = response;
46177 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46178 this.form.afterAction(this, false);
46181 handleResponse : function(response){
46182 if(this.form.errorReader){
46183 var rs = this.form.errorReader.read(response);
46186 for(var i = 0, len = rs.records.length; i < len; i++) {
46187 var r = rs.records[i];
46188 errors[i] = r.data;
46191 if(errors.length < 1){
46195 success : rs.success,
46201 ret = Roo.decode(response.responseText);
46205 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46215 Roo.form.Action.Load = function(form, options){
46216 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46217 this.reader = this.form.reader;
46220 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46225 Roo.Ajax.request(Roo.apply(
46226 this.createCallback(), {
46227 method:this.getMethod(),
46228 url:this.getUrl(false),
46229 params:this.getParams()
46233 success : function(response){
46235 var result = this.processResponse(response);
46236 if(result === true || !result.success || !result.data){
46237 this.failureType = Roo.form.Action.LOAD_FAILURE;
46238 this.form.afterAction(this, false);
46241 this.form.clearInvalid();
46242 this.form.setValues(result.data);
46243 this.form.afterAction(this, true);
46246 handleResponse : function(response){
46247 if(this.form.reader){
46248 var rs = this.form.reader.read(response);
46249 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46251 success : rs.success,
46255 return Roo.decode(response.responseText);
46259 Roo.form.Action.ACTION_TYPES = {
46260 'load' : Roo.form.Action.Load,
46261 'submit' : Roo.form.Action.Submit
46264 * Ext JS Library 1.1.1
46265 * Copyright(c) 2006-2007, Ext JS, LLC.
46267 * Originally Released Under LGPL - original licence link has changed is not relivant.
46270 * <script type="text/javascript">
46274 * @class Roo.form.Layout
46275 * @extends Roo.Component
46276 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46278 * @param {Object} config Configuration options
46280 Roo.form.Layout = function(config){
46282 if (config.items) {
46283 xitems = config.items;
46284 delete config.items;
46286 Roo.form.Layout.superclass.constructor.call(this, config);
46288 Roo.each(xitems, this.addxtype, this);
46292 Roo.extend(Roo.form.Layout, Roo.Component, {
46294 * @cfg {String/Object} autoCreate
46295 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46298 * @cfg {String/Object/Function} style
46299 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46300 * a function which returns such a specification.
46303 * @cfg {String} labelAlign
46304 * Valid values are "left," "top" and "right" (defaults to "left")
46307 * @cfg {Number} labelWidth
46308 * Fixed width in pixels of all field labels (defaults to undefined)
46311 * @cfg {Boolean} clear
46312 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46316 * @cfg {String} labelSeparator
46317 * The separator to use after field labels (defaults to ':')
46319 labelSeparator : ':',
46321 * @cfg {Boolean} hideLabels
46322 * True to suppress the display of field labels in this layout (defaults to false)
46324 hideLabels : false,
46327 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46332 onRender : function(ct, position){
46333 if(this.el){ // from markup
46334 this.el = Roo.get(this.el);
46335 }else { // generate
46336 var cfg = this.getAutoCreate();
46337 this.el = ct.createChild(cfg, position);
46340 this.el.applyStyles(this.style);
46342 if(this.labelAlign){
46343 this.el.addClass('x-form-label-'+this.labelAlign);
46345 if(this.hideLabels){
46346 this.labelStyle = "display:none";
46347 this.elementStyle = "padding-left:0;";
46349 if(typeof this.labelWidth == 'number'){
46350 this.labelStyle = "width:"+this.labelWidth+"px;";
46351 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46353 if(this.labelAlign == 'top'){
46354 this.labelStyle = "width:auto;";
46355 this.elementStyle = "padding-left:0;";
46358 var stack = this.stack;
46359 var slen = stack.length;
46361 if(!this.fieldTpl){
46362 var t = new Roo.Template(
46363 '<div class="x-form-item {5}">',
46364 '<label for="{0}" style="{2}">{1}{4}</label>',
46365 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46367 '</div><div class="x-form-clear-left"></div>'
46369 t.disableFormats = true;
46371 Roo.form.Layout.prototype.fieldTpl = t;
46373 for(var i = 0; i < slen; i++) {
46374 if(stack[i].isFormField){
46375 this.renderField(stack[i]);
46377 this.renderComponent(stack[i]);
46382 this.el.createChild({cls:'x-form-clear'});
46387 renderField : function(f){
46388 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46391 f.labelStyle||this.labelStyle||'', //2
46392 this.elementStyle||'', //3
46393 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46394 f.itemCls||this.itemCls||'' //5
46395 ], true).getPrevSibling());
46399 renderComponent : function(c){
46400 c.render(c.isLayout ? this.el : this.el.createChild());
46403 * Adds a object form elements (using the xtype property as the factory method.)
46404 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46405 * @param {Object} config
46407 addxtype : function(o)
46409 // create the lement.
46410 o.form = this.form;
46411 var fe = Roo.factory(o, Roo.form);
46412 this.form.allItems.push(fe);
46413 this.stack.push(fe);
46415 if (fe.isFormField) {
46416 this.form.items.add(fe);
46424 * @class Roo.form.Column
46425 * @extends Roo.form.Layout
46426 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46428 * @param {Object} config Configuration options
46430 Roo.form.Column = function(config){
46431 Roo.form.Column.superclass.constructor.call(this, config);
46434 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46436 * @cfg {Number/String} width
46437 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46440 * @cfg {String/Object} autoCreate
46441 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46445 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46448 onRender : function(ct, position){
46449 Roo.form.Column.superclass.onRender.call(this, ct, position);
46451 this.el.setWidth(this.width);
46458 * @class Roo.form.Row
46459 * @extends Roo.form.Layout
46460 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46462 * @param {Object} config Configuration options
46466 Roo.form.Row = function(config){
46467 Roo.form.Row.superclass.constructor.call(this, config);
46470 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46472 * @cfg {Number/String} width
46473 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46476 * @cfg {Number/String} height
46477 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46479 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46483 onRender : function(ct, position){
46484 //console.log('row render');
46486 var t = new Roo.Template(
46487 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46488 '<label for="{0}" style="{2}">{1}{4}</label>',
46489 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46493 t.disableFormats = true;
46495 Roo.form.Layout.prototype.rowTpl = t;
46497 this.fieldTpl = this.rowTpl;
46499 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46500 var labelWidth = 100;
46502 if ((this.labelAlign != 'top')) {
46503 if (typeof this.labelWidth == 'number') {
46504 labelWidth = this.labelWidth
46506 this.padWidth = 20 + labelWidth;
46510 Roo.form.Column.superclass.onRender.call(this, ct, position);
46512 this.el.setWidth(this.width);
46515 this.el.setHeight(this.height);
46520 renderField : function(f){
46521 f.fieldEl = this.fieldTpl.append(this.el, [
46522 f.id, f.fieldLabel,
46523 f.labelStyle||this.labelStyle||'',
46524 this.elementStyle||'',
46525 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46526 f.itemCls||this.itemCls||'',
46527 f.width ? f.width + this.padWidth : 160 + this.padWidth
46534 * @class Roo.form.FieldSet
46535 * @extends Roo.form.Layout
46536 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46538 * @param {Object} config Configuration options
46540 Roo.form.FieldSet = function(config){
46541 Roo.form.FieldSet.superclass.constructor.call(this, config);
46544 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46546 * @cfg {String} legend
46547 * The text to display as the legend for the FieldSet (defaults to '')
46550 * @cfg {String/Object} autoCreate
46551 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46555 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46558 onRender : function(ct, position){
46559 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46561 this.setLegend(this.legend);
46566 setLegend : function(text){
46568 this.el.child('legend').update(text);
46573 * Ext JS Library 1.1.1
46574 * Copyright(c) 2006-2007, Ext JS, LLC.
46576 * Originally Released Under LGPL - original licence link has changed is not relivant.
46579 * <script type="text/javascript">
46582 * @class Roo.form.VTypes
46583 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46586 Roo.form.VTypes = function(){
46587 // closure these in so they are only created once.
46588 var alpha = /^[a-zA-Z_]+$/;
46589 var alphanum = /^[a-zA-Z0-9_]+$/;
46590 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46591 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46593 // All these messages and functions are configurable
46596 * The function used to validate email addresses
46597 * @param {String} value The email address
46599 'email' : function(v){
46600 return email.test(v);
46603 * The error text to display when the email validation function returns false
46606 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46608 * The keystroke filter mask to be applied on email input
46611 'emailMask' : /[a-z0-9_\.\-@]/i,
46614 * The function used to validate URLs
46615 * @param {String} value The URL
46617 'url' : function(v){
46618 return url.test(v);
46621 * The error text to display when the url validation function returns false
46624 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46627 * The function used to validate alpha values
46628 * @param {String} value The value
46630 'alpha' : function(v){
46631 return alpha.test(v);
46634 * The error text to display when the alpha validation function returns false
46637 'alphaText' : 'This field should only contain letters and _',
46639 * The keystroke filter mask to be applied on alpha input
46642 'alphaMask' : /[a-z_]/i,
46645 * The function used to validate alphanumeric values
46646 * @param {String} value The value
46648 'alphanum' : function(v){
46649 return alphanum.test(v);
46652 * The error text to display when the alphanumeric validation function returns false
46655 'alphanumText' : 'This field should only contain letters, numbers and _',
46657 * The keystroke filter mask to be applied on alphanumeric input
46660 'alphanumMask' : /[a-z0-9_]/i
46662 }();//<script type="text/javascript">
46665 * @class Roo.form.FCKeditor
46666 * @extends Roo.form.TextArea
46667 * Wrapper around the FCKEditor http://www.fckeditor.net
46669 * Creates a new FCKeditor
46670 * @param {Object} config Configuration options
46672 Roo.form.FCKeditor = function(config){
46673 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46676 * @event editorinit
46677 * Fired when the editor is initialized - you can add extra handlers here..
46678 * @param {FCKeditor} this
46679 * @param {Object} the FCK object.
46686 Roo.form.FCKeditor.editors = { };
46687 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46689 //defaultAutoCreate : {
46690 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46694 * @cfg {Object} fck options - see fck manual for details.
46699 * @cfg {Object} fck toolbar set (Basic or Default)
46701 toolbarSet : 'Basic',
46703 * @cfg {Object} fck BasePath
46705 basePath : '/fckeditor/',
46713 onRender : function(ct, position)
46716 this.defaultAutoCreate = {
46718 style:"width:300px;height:60px;",
46719 autocomplete: "new-password"
46722 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46725 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46726 if(this.preventScrollbars){
46727 this.el.setStyle("overflow", "hidden");
46729 this.el.setHeight(this.growMin);
46732 //console.log('onrender' + this.getId() );
46733 Roo.form.FCKeditor.editors[this.getId()] = this;
46736 this.replaceTextarea() ;
46740 getEditor : function() {
46741 return this.fckEditor;
46744 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46745 * @param {Mixed} value The value to set
46749 setValue : function(value)
46751 //console.log('setValue: ' + value);
46753 if(typeof(value) == 'undefined') { // not sure why this is happending...
46756 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46758 //if(!this.el || !this.getEditor()) {
46759 // this.value = value;
46760 //this.setValue.defer(100,this,[value]);
46764 if(!this.getEditor()) {
46768 this.getEditor().SetData(value);
46775 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46776 * @return {Mixed} value The field value
46778 getValue : function()
46781 if (this.frame && this.frame.dom.style.display == 'none') {
46782 return Roo.form.FCKeditor.superclass.getValue.call(this);
46785 if(!this.el || !this.getEditor()) {
46787 // this.getValue.defer(100,this);
46792 var value=this.getEditor().GetData();
46793 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46794 return Roo.form.FCKeditor.superclass.getValue.call(this);
46800 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46801 * @return {Mixed} value The field value
46803 getRawValue : function()
46805 if (this.frame && this.frame.dom.style.display == 'none') {
46806 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46809 if(!this.el || !this.getEditor()) {
46810 //this.getRawValue.defer(100,this);
46817 var value=this.getEditor().GetData();
46818 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46819 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46823 setSize : function(w,h) {
46827 //if (this.frame && this.frame.dom.style.display == 'none') {
46828 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46831 //if(!this.el || !this.getEditor()) {
46832 // this.setSize.defer(100,this, [w,h]);
46838 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46840 this.frame.dom.setAttribute('width', w);
46841 this.frame.dom.setAttribute('height', h);
46842 this.frame.setSize(w,h);
46846 toggleSourceEdit : function(value) {
46850 this.el.dom.style.display = value ? '' : 'none';
46851 this.frame.dom.style.display = value ? 'none' : '';
46856 focus: function(tag)
46858 if (this.frame.dom.style.display == 'none') {
46859 return Roo.form.FCKeditor.superclass.focus.call(this);
46861 if(!this.el || !this.getEditor()) {
46862 this.focus.defer(100,this, [tag]);
46869 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46870 this.getEditor().Focus();
46872 if (!this.getEditor().Selection.GetSelection()) {
46873 this.focus.defer(100,this, [tag]);
46878 var r = this.getEditor().EditorDocument.createRange();
46879 r.setStart(tgs[0],0);
46880 r.setEnd(tgs[0],0);
46881 this.getEditor().Selection.GetSelection().removeAllRanges();
46882 this.getEditor().Selection.GetSelection().addRange(r);
46883 this.getEditor().Focus();
46890 replaceTextarea : function()
46892 if ( document.getElementById( this.getId() + '___Frame' ) )
46894 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46896 // We must check the elements firstly using the Id and then the name.
46897 var oTextarea = document.getElementById( this.getId() );
46899 var colElementsByName = document.getElementsByName( this.getId() ) ;
46901 oTextarea.style.display = 'none' ;
46903 if ( oTextarea.tabIndex ) {
46904 this.TabIndex = oTextarea.tabIndex ;
46907 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46908 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46909 this.frame = Roo.get(this.getId() + '___Frame')
46912 _getConfigHtml : function()
46916 for ( var o in this.fckconfig ) {
46917 sConfig += sConfig.length > 0 ? '&' : '';
46918 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46921 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46925 _getIFrameHtml : function()
46927 var sFile = 'fckeditor.html' ;
46928 /* no idea what this is about..
46931 if ( (/fcksource=true/i).test( window.top.location.search ) )
46932 sFile = 'fckeditor.original.html' ;
46937 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46938 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46941 var html = '<iframe id="' + this.getId() +
46942 '___Frame" src="' + sLink +
46943 '" width="' + this.width +
46944 '" height="' + this.height + '"' +
46945 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46946 ' frameborder="0" scrolling="no"></iframe>' ;
46951 _insertHtmlBefore : function( html, element )
46953 if ( element.insertAdjacentHTML ) {
46955 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46957 var oRange = document.createRange() ;
46958 oRange.setStartBefore( element ) ;
46959 var oFragment = oRange.createContextualFragment( html );
46960 element.parentNode.insertBefore( oFragment, element ) ;
46973 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46975 function FCKeditor_OnComplete(editorInstance){
46976 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46977 f.fckEditor = editorInstance;
46978 //console.log("loaded");
46979 f.fireEvent('editorinit', f, editorInstance);
46999 //<script type="text/javascript">
47001 * @class Roo.form.GridField
47002 * @extends Roo.form.Field
47003 * Embed a grid (or editable grid into a form)
47006 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47008 * xgrid.store = Roo.data.Store
47009 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47010 * xgrid.store.reader = Roo.data.JsonReader
47014 * Creates a new GridField
47015 * @param {Object} config Configuration options
47017 Roo.form.GridField = function(config){
47018 Roo.form.GridField.superclass.constructor.call(this, config);
47022 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47024 * @cfg {Number} width - used to restrict width of grid..
47028 * @cfg {Number} height - used to restrict height of grid..
47032 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47038 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47039 * {tag: "input", type: "checkbox", autocomplete: "off"})
47041 // defaultAutoCreate : { tag: 'div' },
47042 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47044 * @cfg {String} addTitle Text to include for adding a title.
47048 onResize : function(){
47049 Roo.form.Field.superclass.onResize.apply(this, arguments);
47052 initEvents : function(){
47053 // Roo.form.Checkbox.superclass.initEvents.call(this);
47054 // has no events...
47059 getResizeEl : function(){
47063 getPositionEl : function(){
47068 onRender : function(ct, position){
47070 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47071 var style = this.style;
47074 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47075 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47076 this.viewEl = this.wrap.createChild({ tag: 'div' });
47078 this.viewEl.applyStyles(style);
47081 this.viewEl.setWidth(this.width);
47084 this.viewEl.setHeight(this.height);
47086 //if(this.inputValue !== undefined){
47087 //this.setValue(this.value);
47090 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47093 this.grid.render();
47094 this.grid.getDataSource().on('remove', this.refreshValue, this);
47095 this.grid.getDataSource().on('update', this.refreshValue, this);
47096 this.grid.on('afteredit', this.refreshValue, this);
47102 * Sets the value of the item.
47103 * @param {String} either an object or a string..
47105 setValue : function(v){
47107 v = v || []; // empty set..
47108 // this does not seem smart - it really only affects memoryproxy grids..
47109 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47110 var ds = this.grid.getDataSource();
47111 // assumes a json reader..
47113 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47114 ds.loadData( data);
47116 // clear selection so it does not get stale.
47117 if (this.grid.sm) {
47118 this.grid.sm.clearSelections();
47121 Roo.form.GridField.superclass.setValue.call(this, v);
47122 this.refreshValue();
47123 // should load data in the grid really....
47127 refreshValue: function() {
47129 this.grid.getDataSource().each(function(r) {
47132 this.el.dom.value = Roo.encode(val);
47140 * Ext JS Library 1.1.1
47141 * Copyright(c) 2006-2007, Ext JS, LLC.
47143 * Originally Released Under LGPL - original licence link has changed is not relivant.
47146 * <script type="text/javascript">
47149 * @class Roo.form.DisplayField
47150 * @extends Roo.form.Field
47151 * A generic Field to display non-editable data.
47153 * Creates a new Display Field item.
47154 * @param {Object} config Configuration options
47156 Roo.form.DisplayField = function(config){
47157 Roo.form.DisplayField.superclass.constructor.call(this, config);
47161 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47162 inputType: 'hidden',
47168 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47170 focusClass : undefined,
47172 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47174 fieldClass: 'x-form-field',
47177 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47179 valueRenderer: undefined,
47183 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47184 * {tag: "input", type: "checkbox", autocomplete: "off"})
47187 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47189 onResize : function(){
47190 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47194 initEvents : function(){
47195 // Roo.form.Checkbox.superclass.initEvents.call(this);
47196 // has no events...
47201 getResizeEl : function(){
47205 getPositionEl : function(){
47210 onRender : function(ct, position){
47212 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47213 //if(this.inputValue !== undefined){
47214 this.wrap = this.el.wrap();
47216 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47218 if (this.bodyStyle) {
47219 this.viewEl.applyStyles(this.bodyStyle);
47221 //this.viewEl.setStyle('padding', '2px');
47223 this.setValue(this.value);
47228 initValue : Roo.emptyFn,
47233 onClick : function(){
47238 * Sets the checked state of the checkbox.
47239 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47241 setValue : function(v){
47243 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47244 // this might be called before we have a dom element..
47245 if (!this.viewEl) {
47248 this.viewEl.dom.innerHTML = html;
47249 Roo.form.DisplayField.superclass.setValue.call(this, v);
47259 * @class Roo.form.DayPicker
47260 * @extends Roo.form.Field
47261 * A Day picker show [M] [T] [W] ....
47263 * Creates a new Day Picker
47264 * @param {Object} config Configuration options
47266 Roo.form.DayPicker= function(config){
47267 Roo.form.DayPicker.superclass.constructor.call(this, config);
47271 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47273 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47275 focusClass : undefined,
47277 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47279 fieldClass: "x-form-field",
47282 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47283 * {tag: "input", type: "checkbox", autocomplete: "off"})
47285 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47288 actionMode : 'viewEl',
47292 inputType : 'hidden',
47295 inputElement: false, // real input element?
47296 basedOn: false, // ????
47298 isFormField: true, // not sure where this is needed!!!!
47300 onResize : function(){
47301 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47302 if(!this.boxLabel){
47303 this.el.alignTo(this.wrap, 'c-c');
47307 initEvents : function(){
47308 Roo.form.Checkbox.superclass.initEvents.call(this);
47309 this.el.on("click", this.onClick, this);
47310 this.el.on("change", this.onClick, this);
47314 getResizeEl : function(){
47318 getPositionEl : function(){
47324 onRender : function(ct, position){
47325 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47327 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47329 var r1 = '<table><tr>';
47330 var r2 = '<tr class="x-form-daypick-icons">';
47331 for (var i=0; i < 7; i++) {
47332 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47333 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47336 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47337 viewEl.select('img').on('click', this.onClick, this);
47338 this.viewEl = viewEl;
47341 // this will not work on Chrome!!!
47342 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47343 this.el.on('propertychange', this.setFromHidden, this); //ie
47351 initValue : Roo.emptyFn,
47354 * Returns the checked state of the checkbox.
47355 * @return {Boolean} True if checked, else false
47357 getValue : function(){
47358 return this.el.dom.value;
47363 onClick : function(e){
47364 //this.setChecked(!this.checked);
47365 Roo.get(e.target).toggleClass('x-menu-item-checked');
47366 this.refreshValue();
47367 //if(this.el.dom.checked != this.checked){
47368 // this.setValue(this.el.dom.checked);
47373 refreshValue : function()
47376 this.viewEl.select('img',true).each(function(e,i,n) {
47377 val += e.is(".x-menu-item-checked") ? String(n) : '';
47379 this.setValue(val, true);
47383 * Sets the checked state of the checkbox.
47384 * On is always based on a string comparison between inputValue and the param.
47385 * @param {Boolean/String} value - the value to set
47386 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47388 setValue : function(v,suppressEvent){
47389 if (!this.el.dom) {
47392 var old = this.el.dom.value ;
47393 this.el.dom.value = v;
47394 if (suppressEvent) {
47398 // update display..
47399 this.viewEl.select('img',true).each(function(e,i,n) {
47401 var on = e.is(".x-menu-item-checked");
47402 var newv = v.indexOf(String(n)) > -1;
47404 e.toggleClass('x-menu-item-checked');
47410 this.fireEvent('change', this, v, old);
47415 // handle setting of hidden value by some other method!!?!?
47416 setFromHidden: function()
47421 //console.log("SET FROM HIDDEN");
47422 //alert('setFrom hidden');
47423 this.setValue(this.el.dom.value);
47426 onDestroy : function()
47429 Roo.get(this.viewEl).remove();
47432 Roo.form.DayPicker.superclass.onDestroy.call(this);
47436 * RooJS Library 1.1.1
47437 * Copyright(c) 2008-2011 Alan Knowles
47444 * @class Roo.form.ComboCheck
47445 * @extends Roo.form.ComboBox
47446 * A combobox for multiple select items.
47448 * FIXME - could do with a reset button..
47451 * Create a new ComboCheck
47452 * @param {Object} config Configuration options
47454 Roo.form.ComboCheck = function(config){
47455 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47456 // should verify some data...
47458 // hiddenName = required..
47459 // displayField = required
47460 // valudField == required
47461 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47463 Roo.each(req, function(e) {
47464 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47465 throw "Roo.form.ComboCheck : missing value for: " + e;
47472 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47477 selectedClass: 'x-menu-item-checked',
47480 onRender : function(ct, position){
47486 var cls = 'x-combo-list';
47489 this.tpl = new Roo.Template({
47490 html : '<div class="'+cls+'-item x-menu-check-item">' +
47491 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47492 '<span>{' + this.displayField + '}</span>' +
47499 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47500 this.view.singleSelect = false;
47501 this.view.multiSelect = true;
47502 this.view.toggleSelect = true;
47503 this.pageTb.add(new Roo.Toolbar.Fill(), {
47506 handler: function()
47513 onViewOver : function(e, t){
47519 onViewClick : function(doFocus,index){
47523 select: function () {
47524 //Roo.log("SELECT CALLED");
47527 selectByValue : function(xv, scrollIntoView){
47528 var ar = this.getValueArray();
47531 Roo.each(ar, function(v) {
47532 if(v === undefined || v === null){
47535 var r = this.findRecord(this.valueField, v);
47537 sels.push(this.store.indexOf(r))
47541 this.view.select(sels);
47547 onSelect : function(record, index){
47548 // Roo.log("onselect Called");
47549 // this is only called by the clear button now..
47550 this.view.clearSelections();
47551 this.setValue('[]');
47552 if (this.value != this.valueBefore) {
47553 this.fireEvent('change', this, this.value, this.valueBefore);
47554 this.valueBefore = this.value;
47557 getValueArray : function()
47562 //Roo.log(this.value);
47563 if (typeof(this.value) == 'undefined') {
47566 var ar = Roo.decode(this.value);
47567 return ar instanceof Array ? ar : []; //?? valid?
47570 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47575 expand : function ()
47578 Roo.form.ComboCheck.superclass.expand.call(this);
47579 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47580 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47585 collapse : function(){
47586 Roo.form.ComboCheck.superclass.collapse.call(this);
47587 var sl = this.view.getSelectedIndexes();
47588 var st = this.store;
47592 Roo.each(sl, function(i) {
47594 nv.push(r.get(this.valueField));
47596 this.setValue(Roo.encode(nv));
47597 if (this.value != this.valueBefore) {
47599 this.fireEvent('change', this, this.value, this.valueBefore);
47600 this.valueBefore = this.value;
47605 setValue : function(v){
47609 var vals = this.getValueArray();
47611 Roo.each(vals, function(k) {
47612 var r = this.findRecord(this.valueField, k);
47614 tv.push(r.data[this.displayField]);
47615 }else if(this.valueNotFoundText !== undefined){
47616 tv.push( this.valueNotFoundText );
47621 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47622 this.hiddenField.value = v;
47628 * Ext JS Library 1.1.1
47629 * Copyright(c) 2006-2007, Ext JS, LLC.
47631 * Originally Released Under LGPL - original licence link has changed is not relivant.
47634 * <script type="text/javascript">
47638 * @class Roo.form.Signature
47639 * @extends Roo.form.Field
47643 * @param {Object} config Configuration options
47646 Roo.form.Signature = function(config){
47647 Roo.form.Signature.superclass.constructor.call(this, config);
47649 this.addEvents({// not in used??
47652 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47653 * @param {Roo.form.Signature} combo This combo box
47658 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47659 * @param {Roo.form.ComboBox} combo This combo box
47660 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47666 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47668 * @cfg {Object} labels Label to use when rendering a form.
47672 * confirm : "Confirm"
47677 confirm : "Confirm"
47680 * @cfg {Number} width The signature panel width (defaults to 300)
47684 * @cfg {Number} height The signature panel height (defaults to 100)
47688 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47690 allowBlank : false,
47693 // {Object} signPanel The signature SVG panel element (defaults to {})
47695 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47696 isMouseDown : false,
47697 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47698 isConfirmed : false,
47699 // {String} signatureTmp SVG mapping string (defaults to empty string)
47703 defaultAutoCreate : { // modified by initCompnoent..
47709 onRender : function(ct, position){
47711 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47713 this.wrap = this.el.wrap({
47714 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47717 this.createToolbar(this);
47718 this.signPanel = this.wrap.createChild({
47720 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47724 this.svgID = Roo.id();
47725 this.svgEl = this.signPanel.createChild({
47726 xmlns : 'http://www.w3.org/2000/svg',
47728 id : this.svgID + "-svg",
47730 height: this.height,
47731 viewBox: '0 0 '+this.width+' '+this.height,
47735 id: this.svgID + "-svg-r",
47737 height: this.height,
47742 id: this.svgID + "-svg-l",
47744 y1: (this.height*0.8), // start set the line in 80% of height
47745 x2: this.width, // end
47746 y2: (this.height*0.8), // end set the line in 80% of height
47748 'stroke-width': "1",
47749 'stroke-dasharray': "3",
47750 'shape-rendering': "crispEdges",
47751 'pointer-events': "none"
47755 id: this.svgID + "-svg-p",
47757 'stroke-width': "3",
47759 'pointer-events': 'none'
47764 this.svgBox = this.svgEl.dom.getScreenCTM();
47766 createSVG : function(){
47767 var svg = this.signPanel;
47768 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47771 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47772 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47773 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47774 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47775 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47776 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47777 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47780 isTouchEvent : function(e){
47781 return e.type.match(/^touch/);
47783 getCoords : function (e) {
47784 var pt = this.svgEl.dom.createSVGPoint();
47787 if (this.isTouchEvent(e)) {
47788 pt.x = e.targetTouches[0].clientX
47789 pt.y = e.targetTouches[0].clientY;
47791 var a = this.svgEl.dom.getScreenCTM();
47792 var b = a.inverse();
47793 var mx = pt.matrixTransform(b);
47794 return mx.x + ',' + mx.y;
47796 //mouse event headler
47797 down : function (e) {
47798 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47799 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47801 this.isMouseDown = true;
47803 e.preventDefault();
47805 move : function (e) {
47806 if (this.isMouseDown) {
47807 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47808 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47811 e.preventDefault();
47813 up : function (e) {
47814 this.isMouseDown = false;
47815 var sp = this.signatureTmp.split(' ');
47818 if(!sp[sp.length-2].match(/^L/)){
47822 this.signatureTmp = sp.join(" ");
47825 if(this.getValue() != this.signatureTmp){
47826 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47827 this.isConfirmed = false;
47829 e.preventDefault();
47833 * Protected method that will not generally be called directly. It
47834 * is called when the editor creates its toolbar. Override this method if you need to
47835 * add custom toolbar buttons.
47836 * @param {HtmlEditor} editor
47838 createToolbar : function(editor){
47839 function btn(id, toggle, handler){
47840 var xid = fid + '-'+ id ;
47844 cls : 'x-btn-icon x-edit-'+id,
47845 enableToggle:toggle !== false,
47846 scope: editor, // was editor...
47847 handler:handler||editor.relayBtnCmd,
47848 clickEvent:'mousedown',
47849 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47855 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47859 cls : ' x-signature-btn x-signature-'+id,
47860 scope: editor, // was editor...
47861 handler: this.reset,
47862 clickEvent:'mousedown',
47863 text: this.labels.clear
47870 cls : ' x-signature-btn x-signature-'+id,
47871 scope: editor, // was editor...
47872 handler: this.confirmHandler,
47873 clickEvent:'mousedown',
47874 text: this.labels.confirm
47881 * when user is clicked confirm then show this image.....
47883 * @return {String} Image Data URI
47885 getImageDataURI : function(){
47886 var svg = this.svgEl.dom.parentNode.innerHTML;
47887 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47892 * @return {Boolean} this.isConfirmed
47894 getConfirmed : function(){
47895 return this.isConfirmed;
47899 * @return {Number} this.width
47901 getWidth : function(){
47906 * @return {Number} this.height
47908 getHeight : function(){
47909 return this.height;
47912 getSignature : function(){
47913 return this.signatureTmp;
47916 reset : function(){
47917 this.signatureTmp = '';
47918 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47919 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47920 this.isConfirmed = false;
47921 Roo.form.Signature.superclass.reset.call(this);
47923 setSignature : function(s){
47924 this.signatureTmp = s;
47925 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47926 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47928 this.isConfirmed = false;
47929 Roo.form.Signature.superclass.reset.call(this);
47932 // Roo.log(this.signPanel.dom.contentWindow.up())
47935 setConfirmed : function(){
47939 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47942 confirmHandler : function(){
47943 if(!this.getSignature()){
47947 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47948 this.setValue(this.getSignature());
47949 this.isConfirmed = true;
47951 this.fireEvent('confirm', this);
47954 // Subclasses should provide the validation implementation by overriding this
47955 validateValue : function(value){
47956 if(this.allowBlank){
47960 if(this.isConfirmed){
47967 * Ext JS Library 1.1.1
47968 * Copyright(c) 2006-2007, Ext JS, LLC.
47970 * Originally Released Under LGPL - original licence link has changed is not relivant.
47973 * <script type="text/javascript">
47978 * @class Roo.form.ComboBox
47979 * @extends Roo.form.TriggerField
47980 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47982 * Create a new ComboBox.
47983 * @param {Object} config Configuration options
47985 Roo.form.Select = function(config){
47986 Roo.form.Select.superclass.constructor.call(this, config);
47990 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47992 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47995 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47996 * rendering into an Roo.Editor, defaults to false)
47999 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48000 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48003 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48006 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48007 * the dropdown list (defaults to undefined, with no header element)
48011 * @cfg {String/Roo.Template} tpl The template to use to render the output
48015 defaultAutoCreate : {tag: "select" },
48017 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48019 listWidth: undefined,
48021 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48022 * mode = 'remote' or 'text' if mode = 'local')
48024 displayField: undefined,
48026 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48027 * mode = 'remote' or 'value' if mode = 'local').
48028 * Note: use of a valueField requires the user make a selection
48029 * in order for a value to be mapped.
48031 valueField: undefined,
48035 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48036 * field's data value (defaults to the underlying DOM element's name)
48038 hiddenName: undefined,
48040 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48044 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48046 selectedClass: 'x-combo-selected',
48048 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48049 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48050 * which displays a downward arrow icon).
48052 triggerClass : 'x-form-arrow-trigger',
48054 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48058 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48059 * anchor positions (defaults to 'tl-bl')
48061 listAlign: 'tl-bl?',
48063 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48067 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48068 * query specified by the allQuery config option (defaults to 'query')
48070 triggerAction: 'query',
48072 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48073 * (defaults to 4, does not apply if editable = false)
48077 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48078 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48082 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48083 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48087 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48088 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48092 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48093 * when editable = true (defaults to false)
48095 selectOnFocus:false,
48097 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48099 queryParam: 'query',
48101 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48102 * when mode = 'remote' (defaults to 'Loading...')
48104 loadingText: 'Loading...',
48106 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48110 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48114 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48115 * traditional select (defaults to true)
48119 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48123 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48127 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48128 * listWidth has a higher value)
48132 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48133 * allow the user to set arbitrary text into the field (defaults to false)
48135 forceSelection:false,
48137 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48138 * if typeAhead = true (defaults to 250)
48140 typeAheadDelay : 250,
48142 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48143 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48145 valueNotFoundText : undefined,
48148 * @cfg {String} defaultValue The value displayed after loading the store.
48153 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48155 blockFocus : false,
48158 * @cfg {Boolean} disableClear Disable showing of clear button.
48160 disableClear : false,
48162 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48164 alwaysQuery : false,
48170 // element that contains real text value.. (when hidden is used..)
48173 onRender : function(ct, position){
48174 Roo.form.Field.prototype.onRender.call(this, ct, position);
48177 this.store.on('beforeload', this.onBeforeLoad, this);
48178 this.store.on('load', this.onLoad, this);
48179 this.store.on('loadexception', this.onLoadException, this);
48180 this.store.load({});
48188 initEvents : function(){
48189 //Roo.form.ComboBox.superclass.initEvents.call(this);
48193 onDestroy : function(){
48196 this.store.un('beforeload', this.onBeforeLoad, this);
48197 this.store.un('load', this.onLoad, this);
48198 this.store.un('loadexception', this.onLoadException, this);
48200 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48204 fireKey : function(e){
48205 if(e.isNavKeyPress() && !this.list.isVisible()){
48206 this.fireEvent("specialkey", this, e);
48211 onResize: function(w, h){
48219 * Allow or prevent the user from directly editing the field text. If false is passed,
48220 * the user will only be able to select from the items defined in the dropdown list. This method
48221 * is the runtime equivalent of setting the 'editable' config option at config time.
48222 * @param {Boolean} value True to allow the user to directly edit the field text
48224 setEditable : function(value){
48229 onBeforeLoad : function(){
48231 Roo.log("Select before load");
48234 this.innerList.update(this.loadingText ?
48235 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48236 //this.restrictHeight();
48237 this.selectedIndex = -1;
48241 onLoad : function(){
48244 var dom = this.el.dom;
48245 dom.innerHTML = '';
48246 var od = dom.ownerDocument;
48248 if (this.emptyText) {
48249 var op = od.createElement('option');
48250 op.setAttribute('value', '');
48251 op.innerHTML = String.format('{0}', this.emptyText);
48252 dom.appendChild(op);
48254 if(this.store.getCount() > 0){
48256 var vf = this.valueField;
48257 var df = this.displayField;
48258 this.store.data.each(function(r) {
48259 // which colmsn to use... testing - cdoe / title..
48260 var op = od.createElement('option');
48261 op.setAttribute('value', r.data[vf]);
48262 op.innerHTML = String.format('{0}', r.data[df]);
48263 dom.appendChild(op);
48265 if (typeof(this.defaultValue != 'undefined')) {
48266 this.setValue(this.defaultValue);
48271 //this.onEmptyResults();
48276 onLoadException : function()
48278 dom.innerHTML = '';
48280 Roo.log("Select on load exception");
48284 Roo.log(this.store.reader.jsonData);
48285 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48286 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48292 onTypeAhead : function(){
48297 onSelect : function(record, index){
48298 Roo.log('on select?');
48300 if(this.fireEvent('beforeselect', this, record, index) !== false){
48301 this.setFromData(index > -1 ? record.data : false);
48303 this.fireEvent('select', this, record, index);
48308 * Returns the currently selected field value or empty string if no value is set.
48309 * @return {String} value The selected value
48311 getValue : function(){
48312 var dom = this.el.dom;
48313 this.value = dom.options[dom.selectedIndex].value;
48319 * Clears any text/value currently set in the field
48321 clearValue : function(){
48323 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48328 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48329 * will be displayed in the field. If the value does not match the data value of an existing item,
48330 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48331 * Otherwise the field will be blank (although the value will still be set).
48332 * @param {String} value The value to match
48334 setValue : function(v){
48335 var d = this.el.dom;
48336 for (var i =0; i < d.options.length;i++) {
48337 if (v == d.options[i].value) {
48338 d.selectedIndex = i;
48346 * @property {Object} the last set data for the element
48351 * Sets the value of the field based on a object which is related to the record format for the store.
48352 * @param {Object} value the value to set as. or false on reset?
48354 setFromData : function(o){
48355 Roo.log('setfrom data?');
48361 reset : function(){
48365 findRecord : function(prop, value){
48370 if(this.store.getCount() > 0){
48371 this.store.each(function(r){
48372 if(r.data[prop] == value){
48382 getName: function()
48384 // returns hidden if it's set..
48385 if (!this.rendered) {return ''};
48386 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48394 onEmptyResults : function(){
48395 Roo.log('empty results');
48400 * Returns true if the dropdown list is expanded, else false.
48402 isExpanded : function(){
48407 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48408 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48409 * @param {String} value The data value of the item to select
48410 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48411 * selected item if it is not currently in view (defaults to true)
48412 * @return {Boolean} True if the value matched an item in the list, else false
48414 selectByValue : function(v, scrollIntoView){
48415 Roo.log('select By Value');
48418 if(v !== undefined && v !== null){
48419 var r = this.findRecord(this.valueField || this.displayField, v);
48421 this.select(this.store.indexOf(r), scrollIntoView);
48429 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48430 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48431 * @param {Number} index The zero-based index of the list item to select
48432 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48433 * selected item if it is not currently in view (defaults to true)
48435 select : function(index, scrollIntoView){
48436 Roo.log('select ');
48439 this.selectedIndex = index;
48440 this.view.select(index);
48441 if(scrollIntoView !== false){
48442 var el = this.view.getNode(index);
48444 this.innerList.scrollChildIntoView(el, false);
48452 validateBlur : function(){
48459 initQuery : function(){
48460 this.doQuery(this.getRawValue());
48464 doForce : function(){
48465 if(this.el.dom.value.length > 0){
48466 this.el.dom.value =
48467 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48473 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48474 * query allowing the query action to be canceled if needed.
48475 * @param {String} query The SQL query to execute
48476 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48477 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48478 * saved in the current store (defaults to false)
48480 doQuery : function(q, forceAll){
48482 Roo.log('doQuery?');
48483 if(q === undefined || q === null){
48488 forceAll: forceAll,
48492 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48496 forceAll = qe.forceAll;
48497 if(forceAll === true || (q.length >= this.minChars)){
48498 if(this.lastQuery != q || this.alwaysQuery){
48499 this.lastQuery = q;
48500 if(this.mode == 'local'){
48501 this.selectedIndex = -1;
48503 this.store.clearFilter();
48505 this.store.filter(this.displayField, q);
48509 this.store.baseParams[this.queryParam] = q;
48511 params: this.getParams(q)
48516 this.selectedIndex = -1;
48523 getParams : function(q){
48525 //p[this.queryParam] = q;
48528 p.limit = this.pageSize;
48534 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48536 collapse : function(){
48541 collapseIf : function(e){
48546 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48548 expand : function(){
48556 * @cfg {Boolean} grow
48560 * @cfg {Number} growMin
48564 * @cfg {Number} growMax
48572 setWidth : function()
48576 getResizeEl : function(){
48579 });//<script type="text/javasscript">
48583 * @class Roo.DDView
48584 * A DnD enabled version of Roo.View.
48585 * @param {Element/String} container The Element in which to create the View.
48586 * @param {String} tpl The template string used to create the markup for each element of the View
48587 * @param {Object} config The configuration properties. These include all the config options of
48588 * {@link Roo.View} plus some specific to this class.<br>
48590 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48591 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48593 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48594 .x-view-drag-insert-above {
48595 border-top:1px dotted #3366cc;
48597 .x-view-drag-insert-below {
48598 border-bottom:1px dotted #3366cc;
48604 Roo.DDView = function(container, tpl, config) {
48605 Roo.DDView.superclass.constructor.apply(this, arguments);
48606 this.getEl().setStyle("outline", "0px none");
48607 this.getEl().unselectable();
48608 if (this.dragGroup) {
48609 this.setDraggable(this.dragGroup.split(","));
48611 if (this.dropGroup) {
48612 this.setDroppable(this.dropGroup.split(","));
48614 if (this.deletable) {
48615 this.setDeletable();
48617 this.isDirtyFlag = false;
48623 Roo.extend(Roo.DDView, Roo.View, {
48624 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48625 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48626 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48627 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48631 reset: Roo.emptyFn,
48633 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48635 validate: function() {
48639 destroy: function() {
48640 this.purgeListeners();
48641 this.getEl.removeAllListeners();
48642 this.getEl().remove();
48643 if (this.dragZone) {
48644 if (this.dragZone.destroy) {
48645 this.dragZone.destroy();
48648 if (this.dropZone) {
48649 if (this.dropZone.destroy) {
48650 this.dropZone.destroy();
48655 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48656 getName: function() {
48660 /** Loads the View from a JSON string representing the Records to put into the Store. */
48661 setValue: function(v) {
48663 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48666 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48667 this.store.proxy = new Roo.data.MemoryProxy(data);
48671 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48672 getValue: function() {
48674 this.store.each(function(rec) {
48675 result += rec.id + ',';
48677 return result.substr(0, result.length - 1) + ')';
48680 getIds: function() {
48681 var i = 0, result = new Array(this.store.getCount());
48682 this.store.each(function(rec) {
48683 result[i++] = rec.id;
48688 isDirty: function() {
48689 return this.isDirtyFlag;
48693 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48694 * whole Element becomes the target, and this causes the drop gesture to append.
48696 getTargetFromEvent : function(e) {
48697 var target = e.getTarget();
48698 while ((target !== null) && (target.parentNode != this.el.dom)) {
48699 target = target.parentNode;
48702 target = this.el.dom.lastChild || this.el.dom;
48708 * Create the drag data which consists of an object which has the property "ddel" as
48709 * the drag proxy element.
48711 getDragData : function(e) {
48712 var target = this.findItemFromChild(e.getTarget());
48714 this.handleSelection(e);
48715 var selNodes = this.getSelectedNodes();
48718 copy: this.copy || (this.allowCopy && e.ctrlKey),
48722 var selectedIndices = this.getSelectedIndexes();
48723 for (var i = 0; i < selectedIndices.length; i++) {
48724 dragData.records.push(this.store.getAt(selectedIndices[i]));
48726 if (selNodes.length == 1) {
48727 dragData.ddel = target.cloneNode(true); // the div element
48729 var div = document.createElement('div'); // create the multi element drag "ghost"
48730 div.className = 'multi-proxy';
48731 for (var i = 0, len = selNodes.length; i < len; i++) {
48732 div.appendChild(selNodes[i].cloneNode(true));
48734 dragData.ddel = div;
48736 //console.log(dragData)
48737 //console.log(dragData.ddel.innerHTML)
48740 //console.log('nodragData')
48744 /** Specify to which ddGroup items in this DDView may be dragged. */
48745 setDraggable: function(ddGroup) {
48746 if (ddGroup instanceof Array) {
48747 Roo.each(ddGroup, this.setDraggable, this);
48750 if (this.dragZone) {
48751 this.dragZone.addToGroup(ddGroup);
48753 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48754 containerScroll: true,
48758 // Draggability implies selection. DragZone's mousedown selects the element.
48759 if (!this.multiSelect) { this.singleSelect = true; }
48761 // Wire the DragZone's handlers up to methods in *this*
48762 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48766 /** Specify from which ddGroup this DDView accepts drops. */
48767 setDroppable: function(ddGroup) {
48768 if (ddGroup instanceof Array) {
48769 Roo.each(ddGroup, this.setDroppable, this);
48772 if (this.dropZone) {
48773 this.dropZone.addToGroup(ddGroup);
48775 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48776 containerScroll: true,
48780 // Wire the DropZone's handlers up to methods in *this*
48781 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48782 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48783 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48784 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48785 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48789 /** Decide whether to drop above or below a View node. */
48790 getDropPoint : function(e, n, dd){
48791 if (n == this.el.dom) { return "above"; }
48792 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48793 var c = t + (b - t) / 2;
48794 var y = Roo.lib.Event.getPageY(e);
48802 onNodeEnter : function(n, dd, e, data){
48806 onNodeOver : function(n, dd, e, data){
48807 var pt = this.getDropPoint(e, n, dd);
48808 // set the insert point style on the target node
48809 var dragElClass = this.dropNotAllowed;
48812 if (pt == "above"){
48813 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48814 targetElClass = "x-view-drag-insert-above";
48816 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48817 targetElClass = "x-view-drag-insert-below";
48819 if (this.lastInsertClass != targetElClass){
48820 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48821 this.lastInsertClass = targetElClass;
48824 return dragElClass;
48827 onNodeOut : function(n, dd, e, data){
48828 this.removeDropIndicators(n);
48831 onNodeDrop : function(n, dd, e, data){
48832 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48835 var pt = this.getDropPoint(e, n, dd);
48836 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48837 if (pt == "below") { insertAt++; }
48838 for (var i = 0; i < data.records.length; i++) {
48839 var r = data.records[i];
48840 var dup = this.store.getById(r.id);
48841 if (dup && (dd != this.dragZone)) {
48842 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48845 this.store.insert(insertAt++, r.copy());
48847 data.source.isDirtyFlag = true;
48849 this.store.insert(insertAt++, r);
48851 this.isDirtyFlag = true;
48854 this.dragZone.cachedTarget = null;
48858 removeDropIndicators : function(n){
48860 Roo.fly(n).removeClass([
48861 "x-view-drag-insert-above",
48862 "x-view-drag-insert-below"]);
48863 this.lastInsertClass = "_noclass";
48868 * Utility method. Add a delete option to the DDView's context menu.
48869 * @param {String} imageUrl The URL of the "delete" icon image.
48871 setDeletable: function(imageUrl) {
48872 if (!this.singleSelect && !this.multiSelect) {
48873 this.singleSelect = true;
48875 var c = this.getContextMenu();
48876 this.contextMenu.on("itemclick", function(item) {
48879 this.remove(this.getSelectedIndexes());
48883 this.contextMenu.add({
48890 /** Return the context menu for this DDView. */
48891 getContextMenu: function() {
48892 if (!this.contextMenu) {
48893 // Create the View's context menu
48894 this.contextMenu = new Roo.menu.Menu({
48895 id: this.id + "-contextmenu"
48897 this.el.on("contextmenu", this.showContextMenu, this);
48899 return this.contextMenu;
48902 disableContextMenu: function() {
48903 if (this.contextMenu) {
48904 this.el.un("contextmenu", this.showContextMenu, this);
48908 showContextMenu: function(e, item) {
48909 item = this.findItemFromChild(e.getTarget());
48912 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48913 this.contextMenu.showAt(e.getXY());
48918 * Remove {@link Roo.data.Record}s at the specified indices.
48919 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48921 remove: function(selectedIndices) {
48922 selectedIndices = [].concat(selectedIndices);
48923 for (var i = 0; i < selectedIndices.length; i++) {
48924 var rec = this.store.getAt(selectedIndices[i]);
48925 this.store.remove(rec);
48930 * Double click fires the event, but also, if this is draggable, and there is only one other
48931 * related DropZone, it transfers the selected node.
48933 onDblClick : function(e){
48934 var item = this.findItemFromChild(e.getTarget());
48936 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48939 if (this.dragGroup) {
48940 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48941 while (targets.indexOf(this.dropZone) > -1) {
48942 targets.remove(this.dropZone);
48944 if (targets.length == 1) {
48945 this.dragZone.cachedTarget = null;
48946 var el = Roo.get(targets[0].getEl());
48947 var box = el.getBox(true);
48948 targets[0].onNodeDrop(el.dom, {
48950 xy: [box.x, box.y + box.height - 1]
48951 }, null, this.getDragData(e));
48957 handleSelection: function(e) {
48958 this.dragZone.cachedTarget = null;
48959 var item = this.findItemFromChild(e.getTarget());
48961 this.clearSelections(true);
48964 if (item && (this.multiSelect || this.singleSelect)){
48965 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48966 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48967 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48968 this.unselect(item);
48970 this.select(item, this.multiSelect && e.ctrlKey);
48971 this.lastSelection = item;
48976 onItemClick : function(item, index, e){
48977 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48983 unselect : function(nodeInfo, suppressEvent){
48984 var node = this.getNode(nodeInfo);
48985 if(node && this.isSelected(node)){
48986 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48987 Roo.fly(node).removeClass(this.selectedClass);
48988 this.selections.remove(node);
48989 if(!suppressEvent){
48990 this.fireEvent("selectionchange", this, this.selections);
48998 * Ext JS Library 1.1.1
48999 * Copyright(c) 2006-2007, Ext JS, LLC.
49001 * Originally Released Under LGPL - original licence link has changed is not relivant.
49004 * <script type="text/javascript">
49008 * @class Roo.LayoutManager
49009 * @extends Roo.util.Observable
49010 * Base class for layout managers.
49012 Roo.LayoutManager = function(container, config){
49013 Roo.LayoutManager.superclass.constructor.call(this);
49014 this.el = Roo.get(container);
49015 // ie scrollbar fix
49016 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49017 document.body.scroll = "no";
49018 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49019 this.el.position('relative');
49021 this.id = this.el.id;
49022 this.el.addClass("x-layout-container");
49023 /** false to disable window resize monitoring @type Boolean */
49024 this.monitorWindowResize = true;
49029 * Fires when a layout is performed.
49030 * @param {Roo.LayoutManager} this
49034 * @event regionresized
49035 * Fires when the user resizes a region.
49036 * @param {Roo.LayoutRegion} region The resized region
49037 * @param {Number} newSize The new size (width for east/west, height for north/south)
49039 "regionresized" : true,
49041 * @event regioncollapsed
49042 * Fires when a region is collapsed.
49043 * @param {Roo.LayoutRegion} region The collapsed region
49045 "regioncollapsed" : true,
49047 * @event regionexpanded
49048 * Fires when a region is expanded.
49049 * @param {Roo.LayoutRegion} region The expanded region
49051 "regionexpanded" : true
49053 this.updating = false;
49054 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49057 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49059 * Returns true if this layout is currently being updated
49060 * @return {Boolean}
49062 isUpdating : function(){
49063 return this.updating;
49067 * Suspend the LayoutManager from doing auto-layouts while
49068 * making multiple add or remove calls
49070 beginUpdate : function(){
49071 this.updating = true;
49075 * Restore auto-layouts and optionally disable the manager from performing a layout
49076 * @param {Boolean} noLayout true to disable a layout update
49078 endUpdate : function(noLayout){
49079 this.updating = false;
49085 layout: function(){
49089 onRegionResized : function(region, newSize){
49090 this.fireEvent("regionresized", region, newSize);
49094 onRegionCollapsed : function(region){
49095 this.fireEvent("regioncollapsed", region);
49098 onRegionExpanded : function(region){
49099 this.fireEvent("regionexpanded", region);
49103 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49104 * performs box-model adjustments.
49105 * @return {Object} The size as an object {width: (the width), height: (the height)}
49107 getViewSize : function(){
49109 if(this.el.dom != document.body){
49110 size = this.el.getSize();
49112 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49114 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49115 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49120 * Returns the Element this layout is bound to.
49121 * @return {Roo.Element}
49123 getEl : function(){
49128 * Returns the specified region.
49129 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49130 * @return {Roo.LayoutRegion}
49132 getRegion : function(target){
49133 return this.regions[target.toLowerCase()];
49136 onWindowResize : function(){
49137 if(this.monitorWindowResize){
49143 * Ext JS Library 1.1.1
49144 * Copyright(c) 2006-2007, Ext JS, LLC.
49146 * Originally Released Under LGPL - original licence link has changed is not relivant.
49149 * <script type="text/javascript">
49152 * @class Roo.BorderLayout
49153 * @extends Roo.LayoutManager
49154 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49155 * please see: <br><br>
49156 * <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>
49157 * <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>
49160 var layout = new Roo.BorderLayout(document.body, {
49194 preferredTabWidth: 150
49199 var CP = Roo.ContentPanel;
49201 layout.beginUpdate();
49202 layout.add("north", new CP("north", "North"));
49203 layout.add("south", new CP("south", {title: "South", closable: true}));
49204 layout.add("west", new CP("west", {title: "West"}));
49205 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49206 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49207 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49208 layout.getRegion("center").showPanel("center1");
49209 layout.endUpdate();
49212 <b>The container the layout is rendered into can be either the body element or any other element.
49213 If it is not the body element, the container needs to either be an absolute positioned element,
49214 or you will need to add "position:relative" to the css of the container. You will also need to specify
49215 the container size if it is not the body element.</b>
49218 * Create a new BorderLayout
49219 * @param {String/HTMLElement/Element} container The container this layout is bound to
49220 * @param {Object} config Configuration options
49222 Roo.BorderLayout = function(container, config){
49223 config = config || {};
49224 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49225 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49226 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49227 var target = this.factory.validRegions[i];
49228 if(config[target]){
49229 this.addRegion(target, config[target]);
49234 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49236 * Creates and adds a new region if it doesn't already exist.
49237 * @param {String} target The target region key (north, south, east, west or center).
49238 * @param {Object} config The regions config object
49239 * @return {BorderLayoutRegion} The new region
49241 addRegion : function(target, config){
49242 if(!this.regions[target]){
49243 var r = this.factory.create(target, this, config);
49244 this.bindRegion(target, r);
49246 return this.regions[target];
49250 bindRegion : function(name, r){
49251 this.regions[name] = r;
49252 r.on("visibilitychange", this.layout, this);
49253 r.on("paneladded", this.layout, this);
49254 r.on("panelremoved", this.layout, this);
49255 r.on("invalidated", this.layout, this);
49256 r.on("resized", this.onRegionResized, this);
49257 r.on("collapsed", this.onRegionCollapsed, this);
49258 r.on("expanded", this.onRegionExpanded, this);
49262 * Performs a layout update.
49264 layout : function(){
49265 if(this.updating) return;
49266 var size = this.getViewSize();
49267 var w = size.width;
49268 var h = size.height;
49273 //var x = 0, y = 0;
49275 var rs = this.regions;
49276 var north = rs["north"];
49277 var south = rs["south"];
49278 var west = rs["west"];
49279 var east = rs["east"];
49280 var center = rs["center"];
49281 //if(this.hideOnLayout){ // not supported anymore
49282 //c.el.setStyle("display", "none");
49284 if(north && north.isVisible()){
49285 var b = north.getBox();
49286 var m = north.getMargins();
49287 b.width = w - (m.left+m.right);
49290 centerY = b.height + b.y + m.bottom;
49291 centerH -= centerY;
49292 north.updateBox(this.safeBox(b));
49294 if(south && south.isVisible()){
49295 var b = south.getBox();
49296 var m = south.getMargins();
49297 b.width = w - (m.left+m.right);
49299 var totalHeight = (b.height + m.top + m.bottom);
49300 b.y = h - totalHeight + m.top;
49301 centerH -= totalHeight;
49302 south.updateBox(this.safeBox(b));
49304 if(west && west.isVisible()){
49305 var b = west.getBox();
49306 var m = west.getMargins();
49307 b.height = centerH - (m.top+m.bottom);
49309 b.y = centerY + m.top;
49310 var totalWidth = (b.width + m.left + m.right);
49311 centerX += totalWidth;
49312 centerW -= totalWidth;
49313 west.updateBox(this.safeBox(b));
49315 if(east && east.isVisible()){
49316 var b = east.getBox();
49317 var m = east.getMargins();
49318 b.height = centerH - (m.top+m.bottom);
49319 var totalWidth = (b.width + m.left + m.right);
49320 b.x = w - totalWidth + m.left;
49321 b.y = centerY + m.top;
49322 centerW -= totalWidth;
49323 east.updateBox(this.safeBox(b));
49326 var m = center.getMargins();
49328 x: centerX + m.left,
49329 y: centerY + m.top,
49330 width: centerW - (m.left+m.right),
49331 height: centerH - (m.top+m.bottom)
49333 //if(this.hideOnLayout){
49334 //center.el.setStyle("display", "block");
49336 center.updateBox(this.safeBox(centerBox));
49339 this.fireEvent("layout", this);
49343 safeBox : function(box){
49344 box.width = Math.max(0, box.width);
49345 box.height = Math.max(0, box.height);
49350 * Adds a ContentPanel (or subclass) to this layout.
49351 * @param {String} target The target region key (north, south, east, west or center).
49352 * @param {Roo.ContentPanel} panel The panel to add
49353 * @return {Roo.ContentPanel} The added panel
49355 add : function(target, panel){
49357 target = target.toLowerCase();
49358 return this.regions[target].add(panel);
49362 * Remove a ContentPanel (or subclass) to this layout.
49363 * @param {String} target The target region key (north, south, east, west or center).
49364 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49365 * @return {Roo.ContentPanel} The removed panel
49367 remove : function(target, panel){
49368 target = target.toLowerCase();
49369 return this.regions[target].remove(panel);
49373 * Searches all regions for a panel with the specified id
49374 * @param {String} panelId
49375 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49377 findPanel : function(panelId){
49378 var rs = this.regions;
49379 for(var target in rs){
49380 if(typeof rs[target] != "function"){
49381 var p = rs[target].getPanel(panelId);
49391 * Searches all regions for a panel with the specified id and activates (shows) it.
49392 * @param {String/ContentPanel} panelId The panels id or the panel itself
49393 * @return {Roo.ContentPanel} The shown panel or null
49395 showPanel : function(panelId) {
49396 var rs = this.regions;
49397 for(var target in rs){
49398 var r = rs[target];
49399 if(typeof r != "function"){
49400 if(r.hasPanel(panelId)){
49401 return r.showPanel(panelId);
49409 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49410 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49412 restoreState : function(provider){
49414 provider = Roo.state.Manager;
49416 var sm = new Roo.LayoutStateManager();
49417 sm.init(this, provider);
49421 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49422 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49423 * a valid ContentPanel config object. Example:
49425 // Create the main layout
49426 var layout = new Roo.BorderLayout('main-ct', {
49437 // Create and add multiple ContentPanels at once via configs
49440 id: 'source-files',
49442 title:'Ext Source Files',
49455 * @param {Object} regions An object containing ContentPanel configs by region name
49457 batchAdd : function(regions){
49458 this.beginUpdate();
49459 for(var rname in regions){
49460 var lr = this.regions[rname];
49462 this.addTypedPanels(lr, regions[rname]);
49469 addTypedPanels : function(lr, ps){
49470 if(typeof ps == 'string'){
49471 lr.add(new Roo.ContentPanel(ps));
49473 else if(ps instanceof Array){
49474 for(var i =0, len = ps.length; i < len; i++){
49475 this.addTypedPanels(lr, ps[i]);
49478 else if(!ps.events){ // raw config?
49480 delete ps.el; // prevent conflict
49481 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49483 else { // panel object assumed!
49488 * Adds a xtype elements to the layout.
49492 xtype : 'ContentPanel',
49499 xtype : 'NestedLayoutPanel',
49505 items : [ ... list of content panels or nested layout panels.. ]
49509 * @param {Object} cfg Xtype definition of item to add.
49511 addxtype : function(cfg)
49513 // basically accepts a pannel...
49514 // can accept a layout region..!?!?
49515 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49517 if (!cfg.xtype.match(/Panel$/)) {
49522 if (typeof(cfg.region) == 'undefined') {
49523 Roo.log("Failed to add Panel, region was not set");
49527 var region = cfg.region;
49533 xitems = cfg.items;
49540 case 'ContentPanel': // ContentPanel (el, cfg)
49541 case 'ScrollPanel': // ContentPanel (el, cfg)
49543 if(cfg.autoCreate) {
49544 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49546 var el = this.el.createChild();
49547 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49550 this.add(region, ret);
49554 case 'TreePanel': // our new panel!
49555 cfg.el = this.el.createChild();
49556 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49557 this.add(region, ret);
49560 case 'NestedLayoutPanel':
49561 // create a new Layout (which is a Border Layout...
49562 var el = this.el.createChild();
49563 var clayout = cfg.layout;
49565 clayout.items = clayout.items || [];
49566 // replace this exitems with the clayout ones..
49567 xitems = clayout.items;
49570 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49571 cfg.background = false;
49573 var layout = new Roo.BorderLayout(el, clayout);
49575 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49576 //console.log('adding nested layout panel ' + cfg.toSource());
49577 this.add(region, ret);
49578 nb = {}; /// find first...
49583 // needs grid and region
49585 //var el = this.getRegion(region).el.createChild();
49586 var el = this.el.createChild();
49587 // create the grid first...
49589 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49591 if (region == 'center' && this.active ) {
49592 cfg.background = false;
49594 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49596 this.add(region, ret);
49597 if (cfg.background) {
49598 ret.on('activate', function(gp) {
49599 if (!gp.grid.rendered) {
49614 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49616 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49617 this.add(region, ret);
49620 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49624 // GridPanel (grid, cfg)
49627 this.beginUpdate();
49631 Roo.each(xitems, function(i) {
49632 region = nb && i.region ? i.region : false;
49634 var add = ret.addxtype(i);
49637 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49638 if (!i.background) {
49639 abn[region] = nb[region] ;
49646 // make the last non-background panel active..
49647 //if (nb) { Roo.log(abn); }
49650 for(var r in abn) {
49651 region = this.getRegion(r);
49653 // tried using nb[r], but it does not work..
49655 region.showPanel(abn[r]);
49666 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49667 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49668 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49669 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49672 var CP = Roo.ContentPanel;
49674 var layout = Roo.BorderLayout.create({
49678 panels: [new CP("north", "North")]
49687 panels: [new CP("west", {title: "West"})]
49696 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49705 panels: [new CP("south", {title: "South", closable: true})]
49712 preferredTabWidth: 150,
49714 new CP("center1", {title: "Close Me", closable: true}),
49715 new CP("center2", {title: "Center Panel", closable: false})
49720 layout.getRegion("center").showPanel("center1");
49725 Roo.BorderLayout.create = function(config, targetEl){
49726 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49727 layout.beginUpdate();
49728 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49729 for(var j = 0, jlen = regions.length; j < jlen; j++){
49730 var lr = regions[j];
49731 if(layout.regions[lr] && config[lr].panels){
49732 var r = layout.regions[lr];
49733 var ps = config[lr].panels;
49734 layout.addTypedPanels(r, ps);
49737 layout.endUpdate();
49742 Roo.BorderLayout.RegionFactory = {
49744 validRegions : ["north","south","east","west","center"],
49747 create : function(target, mgr, config){
49748 target = target.toLowerCase();
49749 if(config.lightweight || config.basic){
49750 return new Roo.BasicLayoutRegion(mgr, config, target);
49754 return new Roo.NorthLayoutRegion(mgr, config);
49756 return new Roo.SouthLayoutRegion(mgr, config);
49758 return new Roo.EastLayoutRegion(mgr, config);
49760 return new Roo.WestLayoutRegion(mgr, config);
49762 return new Roo.CenterLayoutRegion(mgr, config);
49764 throw 'Layout region "'+target+'" not supported.';
49768 * Ext JS Library 1.1.1
49769 * Copyright(c) 2006-2007, Ext JS, LLC.
49771 * Originally Released Under LGPL - original licence link has changed is not relivant.
49774 * <script type="text/javascript">
49778 * @class Roo.BasicLayoutRegion
49779 * @extends Roo.util.Observable
49780 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49781 * and does not have a titlebar, tabs or any other features. All it does is size and position
49782 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49784 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49786 this.position = pos;
49789 * @scope Roo.BasicLayoutRegion
49793 * @event beforeremove
49794 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49795 * @param {Roo.LayoutRegion} this
49796 * @param {Roo.ContentPanel} panel The panel
49797 * @param {Object} e The cancel event object
49799 "beforeremove" : true,
49801 * @event invalidated
49802 * Fires when the layout for this region is changed.
49803 * @param {Roo.LayoutRegion} this
49805 "invalidated" : true,
49807 * @event visibilitychange
49808 * Fires when this region is shown or hidden
49809 * @param {Roo.LayoutRegion} this
49810 * @param {Boolean} visibility true or false
49812 "visibilitychange" : true,
49814 * @event paneladded
49815 * Fires when a panel is added.
49816 * @param {Roo.LayoutRegion} this
49817 * @param {Roo.ContentPanel} panel The panel
49819 "paneladded" : true,
49821 * @event panelremoved
49822 * Fires when a panel is removed.
49823 * @param {Roo.LayoutRegion} this
49824 * @param {Roo.ContentPanel} panel The panel
49826 "panelremoved" : true,
49829 * Fires when this region is collapsed.
49830 * @param {Roo.LayoutRegion} this
49832 "collapsed" : true,
49835 * Fires when this region is expanded.
49836 * @param {Roo.LayoutRegion} this
49841 * Fires when this region is slid into view.
49842 * @param {Roo.LayoutRegion} this
49844 "slideshow" : true,
49847 * Fires when this region slides out of view.
49848 * @param {Roo.LayoutRegion} this
49850 "slidehide" : true,
49852 * @event panelactivated
49853 * Fires when a panel is activated.
49854 * @param {Roo.LayoutRegion} this
49855 * @param {Roo.ContentPanel} panel The activated panel
49857 "panelactivated" : true,
49860 * Fires when the user resizes this region.
49861 * @param {Roo.LayoutRegion} this
49862 * @param {Number} newSize The new size (width for east/west, height for north/south)
49866 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49867 this.panels = new Roo.util.MixedCollection();
49868 this.panels.getKey = this.getPanelId.createDelegate(this);
49870 this.activePanel = null;
49871 // ensure listeners are added...
49873 if (config.listeners || config.events) {
49874 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49875 listeners : config.listeners || {},
49876 events : config.events || {}
49880 if(skipConfig !== true){
49881 this.applyConfig(config);
49885 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49886 getPanelId : function(p){
49890 applyConfig : function(config){
49891 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49892 this.config = config;
49897 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49898 * the width, for horizontal (north, south) the height.
49899 * @param {Number} newSize The new width or height
49901 resizeTo : function(newSize){
49902 var el = this.el ? this.el :
49903 (this.activePanel ? this.activePanel.getEl() : null);
49905 switch(this.position){
49908 el.setWidth(newSize);
49909 this.fireEvent("resized", this, newSize);
49913 el.setHeight(newSize);
49914 this.fireEvent("resized", this, newSize);
49920 getBox : function(){
49921 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49924 getMargins : function(){
49925 return this.margins;
49928 updateBox : function(box){
49930 var el = this.activePanel.getEl();
49931 el.dom.style.left = box.x + "px";
49932 el.dom.style.top = box.y + "px";
49933 this.activePanel.setSize(box.width, box.height);
49937 * Returns the container element for this region.
49938 * @return {Roo.Element}
49940 getEl : function(){
49941 return this.activePanel;
49945 * Returns true if this region is currently visible.
49946 * @return {Boolean}
49948 isVisible : function(){
49949 return this.activePanel ? true : false;
49952 setActivePanel : function(panel){
49953 panel = this.getPanel(panel);
49954 if(this.activePanel && this.activePanel != panel){
49955 this.activePanel.setActiveState(false);
49956 this.activePanel.getEl().setLeftTop(-10000,-10000);
49958 this.activePanel = panel;
49959 panel.setActiveState(true);
49961 panel.setSize(this.box.width, this.box.height);
49963 this.fireEvent("panelactivated", this, panel);
49964 this.fireEvent("invalidated");
49968 * Show the specified panel.
49969 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49970 * @return {Roo.ContentPanel} The shown panel or null
49972 showPanel : function(panel){
49973 if(panel = this.getPanel(panel)){
49974 this.setActivePanel(panel);
49980 * Get the active panel for this region.
49981 * @return {Roo.ContentPanel} The active panel or null
49983 getActivePanel : function(){
49984 return this.activePanel;
49988 * Add the passed ContentPanel(s)
49989 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49990 * @return {Roo.ContentPanel} The panel added (if only one was added)
49992 add : function(panel){
49993 if(arguments.length > 1){
49994 for(var i = 0, len = arguments.length; i < len; i++) {
49995 this.add(arguments[i]);
49999 if(this.hasPanel(panel)){
50000 this.showPanel(panel);
50003 var el = panel.getEl();
50004 if(el.dom.parentNode != this.mgr.el.dom){
50005 this.mgr.el.dom.appendChild(el.dom);
50007 if(panel.setRegion){
50008 panel.setRegion(this);
50010 this.panels.add(panel);
50011 el.setStyle("position", "absolute");
50012 if(!panel.background){
50013 this.setActivePanel(panel);
50014 if(this.config.initialSize && this.panels.getCount()==1){
50015 this.resizeTo(this.config.initialSize);
50018 this.fireEvent("paneladded", this, panel);
50023 * Returns true if the panel is in this region.
50024 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50025 * @return {Boolean}
50027 hasPanel : function(panel){
50028 if(typeof panel == "object"){ // must be panel obj
50029 panel = panel.getId();
50031 return this.getPanel(panel) ? true : false;
50035 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50036 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50037 * @param {Boolean} preservePanel Overrides the config preservePanel option
50038 * @return {Roo.ContentPanel} The panel that was removed
50040 remove : function(panel, preservePanel){
50041 panel = this.getPanel(panel);
50046 this.fireEvent("beforeremove", this, panel, e);
50047 if(e.cancel === true){
50050 var panelId = panel.getId();
50051 this.panels.removeKey(panelId);
50056 * Returns the panel specified or null if it's not in this region.
50057 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50058 * @return {Roo.ContentPanel}
50060 getPanel : function(id){
50061 if(typeof id == "object"){ // must be panel obj
50064 return this.panels.get(id);
50068 * Returns this regions position (north/south/east/west/center).
50071 getPosition: function(){
50072 return this.position;
50076 * Ext JS Library 1.1.1
50077 * Copyright(c) 2006-2007, Ext JS, LLC.
50079 * Originally Released Under LGPL - original licence link has changed is not relivant.
50082 * <script type="text/javascript">
50086 * @class Roo.LayoutRegion
50087 * @extends Roo.BasicLayoutRegion
50088 * This class represents a region in a layout manager.
50089 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50090 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50091 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50092 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50093 * @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})
50094 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50095 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50096 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50097 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50098 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50099 * @cfg {String} title The title for the region (overrides panel titles)
50100 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50101 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50102 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50103 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50104 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50105 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50106 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50107 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50108 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50109 * @cfg {Boolean} showPin True to show a pin button
50110 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50111 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50112 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50113 * @cfg {Number} width For East/West panels
50114 * @cfg {Number} height For North/South panels
50115 * @cfg {Boolean} split To show the splitter
50116 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50118 Roo.LayoutRegion = function(mgr, config, pos){
50119 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50120 var dh = Roo.DomHelper;
50121 /** This region's container element
50122 * @type Roo.Element */
50123 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50124 /** This region's title element
50125 * @type Roo.Element */
50127 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50128 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50129 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50131 this.titleEl.enableDisplayMode();
50132 /** This region's title text element
50133 * @type HTMLElement */
50134 this.titleTextEl = this.titleEl.dom.firstChild;
50135 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50136 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50137 this.closeBtn.enableDisplayMode();
50138 this.closeBtn.on("click", this.closeClicked, this);
50139 this.closeBtn.hide();
50141 this.createBody(config);
50142 this.visible = true;
50143 this.collapsed = false;
50145 if(config.hideWhenEmpty){
50147 this.on("paneladded", this.validateVisibility, this);
50148 this.on("panelremoved", this.validateVisibility, this);
50150 this.applyConfig(config);
50153 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50155 createBody : function(){
50156 /** This region's body element
50157 * @type Roo.Element */
50158 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50161 applyConfig : function(c){
50162 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50163 var dh = Roo.DomHelper;
50164 if(c.titlebar !== false){
50165 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50166 this.collapseBtn.on("click", this.collapse, this);
50167 this.collapseBtn.enableDisplayMode();
50169 if(c.showPin === true || this.showPin){
50170 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50171 this.stickBtn.enableDisplayMode();
50172 this.stickBtn.on("click", this.expand, this);
50173 this.stickBtn.hide();
50176 /** This region's collapsed element
50177 * @type Roo.Element */
50178 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50179 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50181 if(c.floatable !== false){
50182 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50183 this.collapsedEl.on("click", this.collapseClick, this);
50186 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50187 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50188 id: "message", unselectable: "on", style:{"float":"left"}});
50189 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50191 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50192 this.expandBtn.on("click", this.expand, this);
50194 if(this.collapseBtn){
50195 this.collapseBtn.setVisible(c.collapsible == true);
50197 this.cmargins = c.cmargins || this.cmargins ||
50198 (this.position == "west" || this.position == "east" ?
50199 {top: 0, left: 2, right:2, bottom: 0} :
50200 {top: 2, left: 0, right:0, bottom: 2});
50201 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50202 this.bottomTabs = c.tabPosition != "top";
50203 this.autoScroll = c.autoScroll || false;
50204 if(this.autoScroll){
50205 this.bodyEl.setStyle("overflow", "auto");
50207 this.bodyEl.setStyle("overflow", "hidden");
50209 //if(c.titlebar !== false){
50210 if((!c.titlebar && !c.title) || c.titlebar === false){
50211 this.titleEl.hide();
50213 this.titleEl.show();
50215 this.titleTextEl.innerHTML = c.title;
50219 this.duration = c.duration || .30;
50220 this.slideDuration = c.slideDuration || .45;
50223 this.collapse(true);
50230 * Returns true if this region is currently visible.
50231 * @return {Boolean}
50233 isVisible : function(){
50234 return this.visible;
50238 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50239 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50241 setCollapsedTitle : function(title){
50242 title = title || " ";
50243 if(this.collapsedTitleTextEl){
50244 this.collapsedTitleTextEl.innerHTML = title;
50248 getBox : function(){
50250 if(!this.collapsed){
50251 b = this.el.getBox(false, true);
50253 b = this.collapsedEl.getBox(false, true);
50258 getMargins : function(){
50259 return this.collapsed ? this.cmargins : this.margins;
50262 highlight : function(){
50263 this.el.addClass("x-layout-panel-dragover");
50266 unhighlight : function(){
50267 this.el.removeClass("x-layout-panel-dragover");
50270 updateBox : function(box){
50272 if(!this.collapsed){
50273 this.el.dom.style.left = box.x + "px";
50274 this.el.dom.style.top = box.y + "px";
50275 this.updateBody(box.width, box.height);
50277 this.collapsedEl.dom.style.left = box.x + "px";
50278 this.collapsedEl.dom.style.top = box.y + "px";
50279 this.collapsedEl.setSize(box.width, box.height);
50282 this.tabs.autoSizeTabs();
50286 updateBody : function(w, h){
50288 this.el.setWidth(w);
50289 w -= this.el.getBorderWidth("rl");
50290 if(this.config.adjustments){
50291 w += this.config.adjustments[0];
50295 this.el.setHeight(h);
50296 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50297 h -= this.el.getBorderWidth("tb");
50298 if(this.config.adjustments){
50299 h += this.config.adjustments[1];
50301 this.bodyEl.setHeight(h);
50303 h = this.tabs.syncHeight(h);
50306 if(this.panelSize){
50307 w = w !== null ? w : this.panelSize.width;
50308 h = h !== null ? h : this.panelSize.height;
50310 if(this.activePanel){
50311 var el = this.activePanel.getEl();
50312 w = w !== null ? w : el.getWidth();
50313 h = h !== null ? h : el.getHeight();
50314 this.panelSize = {width: w, height: h};
50315 this.activePanel.setSize(w, h);
50317 if(Roo.isIE && this.tabs){
50318 this.tabs.el.repaint();
50323 * Returns the container element for this region.
50324 * @return {Roo.Element}
50326 getEl : function(){
50331 * Hides this region.
50334 if(!this.collapsed){
50335 this.el.dom.style.left = "-2000px";
50338 this.collapsedEl.dom.style.left = "-2000px";
50339 this.collapsedEl.hide();
50341 this.visible = false;
50342 this.fireEvent("visibilitychange", this, false);
50346 * Shows this region if it was previously hidden.
50349 if(!this.collapsed){
50352 this.collapsedEl.show();
50354 this.visible = true;
50355 this.fireEvent("visibilitychange", this, true);
50358 closeClicked : function(){
50359 if(this.activePanel){
50360 this.remove(this.activePanel);
50364 collapseClick : function(e){
50366 e.stopPropagation();
50369 e.stopPropagation();
50375 * Collapses this region.
50376 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50378 collapse : function(skipAnim){
50379 if(this.collapsed) return;
50380 this.collapsed = true;
50382 this.split.el.hide();
50384 if(this.config.animate && skipAnim !== true){
50385 this.fireEvent("invalidated", this);
50386 this.animateCollapse();
50388 this.el.setLocation(-20000,-20000);
50390 this.collapsedEl.show();
50391 this.fireEvent("collapsed", this);
50392 this.fireEvent("invalidated", this);
50396 animateCollapse : function(){
50401 * Expands this region if it was previously collapsed.
50402 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50403 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50405 expand : function(e, skipAnim){
50406 if(e) e.stopPropagation();
50407 if(!this.collapsed || this.el.hasActiveFx()) return;
50409 this.afterSlideIn();
50412 this.collapsed = false;
50413 if(this.config.animate && skipAnim !== true){
50414 this.animateExpand();
50418 this.split.el.show();
50420 this.collapsedEl.setLocation(-2000,-2000);
50421 this.collapsedEl.hide();
50422 this.fireEvent("invalidated", this);
50423 this.fireEvent("expanded", this);
50427 animateExpand : function(){
50431 initTabs : function()
50433 this.bodyEl.setStyle("overflow", "hidden");
50434 var ts = new Roo.TabPanel(
50437 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50438 disableTooltips: this.config.disableTabTips,
50439 toolbar : this.config.toolbar
50442 if(this.config.hideTabs){
50443 ts.stripWrap.setDisplayed(false);
50446 ts.resizeTabs = this.config.resizeTabs === true;
50447 ts.minTabWidth = this.config.minTabWidth || 40;
50448 ts.maxTabWidth = this.config.maxTabWidth || 250;
50449 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50450 ts.monitorResize = false;
50451 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50452 ts.bodyEl.addClass('x-layout-tabs-body');
50453 this.panels.each(this.initPanelAsTab, this);
50456 initPanelAsTab : function(panel){
50457 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50458 this.config.closeOnTab && panel.isClosable());
50459 if(panel.tabTip !== undefined){
50460 ti.setTooltip(panel.tabTip);
50462 ti.on("activate", function(){
50463 this.setActivePanel(panel);
50465 if(this.config.closeOnTab){
50466 ti.on("beforeclose", function(t, e){
50468 this.remove(panel);
50474 updatePanelTitle : function(panel, title){
50475 if(this.activePanel == panel){
50476 this.updateTitle(title);
50479 var ti = this.tabs.getTab(panel.getEl().id);
50481 if(panel.tabTip !== undefined){
50482 ti.setTooltip(panel.tabTip);
50487 updateTitle : function(title){
50488 if(this.titleTextEl && !this.config.title){
50489 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50493 setActivePanel : function(panel){
50494 panel = this.getPanel(panel);
50495 if(this.activePanel && this.activePanel != panel){
50496 this.activePanel.setActiveState(false);
50498 this.activePanel = panel;
50499 panel.setActiveState(true);
50500 if(this.panelSize){
50501 panel.setSize(this.panelSize.width, this.panelSize.height);
50504 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50506 this.updateTitle(panel.getTitle());
50508 this.fireEvent("invalidated", this);
50510 this.fireEvent("panelactivated", this, panel);
50514 * Shows the specified panel.
50515 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50516 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50518 showPanel : function(panel)
50520 panel = this.getPanel(panel);
50523 var tab = this.tabs.getTab(panel.getEl().id);
50524 if(tab.isHidden()){
50525 this.tabs.unhideTab(tab.id);
50529 this.setActivePanel(panel);
50536 * Get the active panel for this region.
50537 * @return {Roo.ContentPanel} The active panel or null
50539 getActivePanel : function(){
50540 return this.activePanel;
50543 validateVisibility : function(){
50544 if(this.panels.getCount() < 1){
50545 this.updateTitle(" ");
50546 this.closeBtn.hide();
50549 if(!this.isVisible()){
50556 * Adds the passed ContentPanel(s) to this region.
50557 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50558 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50560 add : function(panel){
50561 if(arguments.length > 1){
50562 for(var i = 0, len = arguments.length; i < len; i++) {
50563 this.add(arguments[i]);
50567 if(this.hasPanel(panel)){
50568 this.showPanel(panel);
50571 panel.setRegion(this);
50572 this.panels.add(panel);
50573 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50574 this.bodyEl.dom.appendChild(panel.getEl().dom);
50575 if(panel.background !== true){
50576 this.setActivePanel(panel);
50578 this.fireEvent("paneladded", this, panel);
50584 this.initPanelAsTab(panel);
50586 if(panel.background !== true){
50587 this.tabs.activate(panel.getEl().id);
50589 this.fireEvent("paneladded", this, panel);
50594 * Hides the tab for the specified panel.
50595 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50597 hidePanel : function(panel){
50598 if(this.tabs && (panel = this.getPanel(panel))){
50599 this.tabs.hideTab(panel.getEl().id);
50604 * Unhides the tab for a previously hidden panel.
50605 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50607 unhidePanel : function(panel){
50608 if(this.tabs && (panel = this.getPanel(panel))){
50609 this.tabs.unhideTab(panel.getEl().id);
50613 clearPanels : function(){
50614 while(this.panels.getCount() > 0){
50615 this.remove(this.panels.first());
50620 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50621 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50622 * @param {Boolean} preservePanel Overrides the config preservePanel option
50623 * @return {Roo.ContentPanel} The panel that was removed
50625 remove : function(panel, preservePanel){
50626 panel = this.getPanel(panel);
50631 this.fireEvent("beforeremove", this, panel, e);
50632 if(e.cancel === true){
50635 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50636 var panelId = panel.getId();
50637 this.panels.removeKey(panelId);
50639 document.body.appendChild(panel.getEl().dom);
50642 this.tabs.removeTab(panel.getEl().id);
50643 }else if (!preservePanel){
50644 this.bodyEl.dom.removeChild(panel.getEl().dom);
50646 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50647 var p = this.panels.first();
50648 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50649 tempEl.appendChild(p.getEl().dom);
50650 this.bodyEl.update("");
50651 this.bodyEl.dom.appendChild(p.getEl().dom);
50653 this.updateTitle(p.getTitle());
50655 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50656 this.setActivePanel(p);
50658 panel.setRegion(null);
50659 if(this.activePanel == panel){
50660 this.activePanel = null;
50662 if(this.config.autoDestroy !== false && preservePanel !== true){
50663 try{panel.destroy();}catch(e){}
50665 this.fireEvent("panelremoved", this, panel);
50670 * Returns the TabPanel component used by this region
50671 * @return {Roo.TabPanel}
50673 getTabs : function(){
50677 createTool : function(parentEl, className){
50678 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50679 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50680 btn.addClassOnOver("x-layout-tools-button-over");
50685 * Ext JS Library 1.1.1
50686 * Copyright(c) 2006-2007, Ext JS, LLC.
50688 * Originally Released Under LGPL - original licence link has changed is not relivant.
50691 * <script type="text/javascript">
50697 * @class Roo.SplitLayoutRegion
50698 * @extends Roo.LayoutRegion
50699 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50701 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50702 this.cursor = cursor;
50703 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50706 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50707 splitTip : "Drag to resize.",
50708 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50709 useSplitTips : false,
50711 applyConfig : function(config){
50712 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50715 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50716 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50717 /** The SplitBar for this region
50718 * @type Roo.SplitBar */
50719 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50720 this.split.on("moved", this.onSplitMove, this);
50721 this.split.useShim = config.useShim === true;
50722 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50723 if(this.useSplitTips){
50724 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50726 if(config.collapsible){
50727 this.split.el.on("dblclick", this.collapse, this);
50730 if(typeof config.minSize != "undefined"){
50731 this.split.minSize = config.minSize;
50733 if(typeof config.maxSize != "undefined"){
50734 this.split.maxSize = config.maxSize;
50736 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50737 this.hideSplitter();
50742 getHMaxSize : function(){
50743 var cmax = this.config.maxSize || 10000;
50744 var center = this.mgr.getRegion("center");
50745 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50748 getVMaxSize : function(){
50749 var cmax = this.config.maxSize || 10000;
50750 var center = this.mgr.getRegion("center");
50751 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50754 onSplitMove : function(split, newSize){
50755 this.fireEvent("resized", this, newSize);
50759 * Returns the {@link Roo.SplitBar} for this region.
50760 * @return {Roo.SplitBar}
50762 getSplitBar : function(){
50767 this.hideSplitter();
50768 Roo.SplitLayoutRegion.superclass.hide.call(this);
50771 hideSplitter : function(){
50773 this.split.el.setLocation(-2000,-2000);
50774 this.split.el.hide();
50780 this.split.el.show();
50782 Roo.SplitLayoutRegion.superclass.show.call(this);
50785 beforeSlide: function(){
50786 if(Roo.isGecko){// firefox overflow auto bug workaround
50787 this.bodyEl.clip();
50788 if(this.tabs) this.tabs.bodyEl.clip();
50789 if(this.activePanel){
50790 this.activePanel.getEl().clip();
50792 if(this.activePanel.beforeSlide){
50793 this.activePanel.beforeSlide();
50799 afterSlide : function(){
50800 if(Roo.isGecko){// firefox overflow auto bug workaround
50801 this.bodyEl.unclip();
50802 if(this.tabs) this.tabs.bodyEl.unclip();
50803 if(this.activePanel){
50804 this.activePanel.getEl().unclip();
50805 if(this.activePanel.afterSlide){
50806 this.activePanel.afterSlide();
50812 initAutoHide : function(){
50813 if(this.autoHide !== false){
50814 if(!this.autoHideHd){
50815 var st = new Roo.util.DelayedTask(this.slideIn, this);
50816 this.autoHideHd = {
50817 "mouseout": function(e){
50818 if(!e.within(this.el, true)){
50822 "mouseover" : function(e){
50828 this.el.on(this.autoHideHd);
50832 clearAutoHide : function(){
50833 if(this.autoHide !== false){
50834 this.el.un("mouseout", this.autoHideHd.mouseout);
50835 this.el.un("mouseover", this.autoHideHd.mouseover);
50839 clearMonitor : function(){
50840 Roo.get(document).un("click", this.slideInIf, this);
50843 // these names are backwards but not changed for compat
50844 slideOut : function(){
50845 if(this.isSlid || this.el.hasActiveFx()){
50848 this.isSlid = true;
50849 if(this.collapseBtn){
50850 this.collapseBtn.hide();
50852 this.closeBtnState = this.closeBtn.getStyle('display');
50853 this.closeBtn.hide();
50855 this.stickBtn.show();
50858 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50859 this.beforeSlide();
50860 this.el.setStyle("z-index", 10001);
50861 this.el.slideIn(this.getSlideAnchor(), {
50862 callback: function(){
50864 this.initAutoHide();
50865 Roo.get(document).on("click", this.slideInIf, this);
50866 this.fireEvent("slideshow", this);
50873 afterSlideIn : function(){
50874 this.clearAutoHide();
50875 this.isSlid = false;
50876 this.clearMonitor();
50877 this.el.setStyle("z-index", "");
50878 if(this.collapseBtn){
50879 this.collapseBtn.show();
50881 this.closeBtn.setStyle('display', this.closeBtnState);
50883 this.stickBtn.hide();
50885 this.fireEvent("slidehide", this);
50888 slideIn : function(cb){
50889 if(!this.isSlid || this.el.hasActiveFx()){
50893 this.isSlid = false;
50894 this.beforeSlide();
50895 this.el.slideOut(this.getSlideAnchor(), {
50896 callback: function(){
50897 this.el.setLeftTop(-10000, -10000);
50899 this.afterSlideIn();
50907 slideInIf : function(e){
50908 if(!e.within(this.el)){
50913 animateCollapse : function(){
50914 this.beforeSlide();
50915 this.el.setStyle("z-index", 20000);
50916 var anchor = this.getSlideAnchor();
50917 this.el.slideOut(anchor, {
50918 callback : function(){
50919 this.el.setStyle("z-index", "");
50920 this.collapsedEl.slideIn(anchor, {duration:.3});
50922 this.el.setLocation(-10000,-10000);
50924 this.fireEvent("collapsed", this);
50931 animateExpand : function(){
50932 this.beforeSlide();
50933 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50934 this.el.setStyle("z-index", 20000);
50935 this.collapsedEl.hide({
50938 this.el.slideIn(this.getSlideAnchor(), {
50939 callback : function(){
50940 this.el.setStyle("z-index", "");
50943 this.split.el.show();
50945 this.fireEvent("invalidated", this);
50946 this.fireEvent("expanded", this);
50974 getAnchor : function(){
50975 return this.anchors[this.position];
50978 getCollapseAnchor : function(){
50979 return this.canchors[this.position];
50982 getSlideAnchor : function(){
50983 return this.sanchors[this.position];
50986 getAlignAdj : function(){
50987 var cm = this.cmargins;
50988 switch(this.position){
51004 getExpandAdj : function(){
51005 var c = this.collapsedEl, cm = this.cmargins;
51006 switch(this.position){
51008 return [-(cm.right+c.getWidth()+cm.left), 0];
51011 return [cm.right+c.getWidth()+cm.left, 0];
51014 return [0, -(cm.top+cm.bottom+c.getHeight())];
51017 return [0, cm.top+cm.bottom+c.getHeight()];
51023 * Ext JS Library 1.1.1
51024 * Copyright(c) 2006-2007, Ext JS, LLC.
51026 * Originally Released Under LGPL - original licence link has changed is not relivant.
51029 * <script type="text/javascript">
51032 * These classes are private internal classes
51034 Roo.CenterLayoutRegion = function(mgr, config){
51035 Roo.LayoutRegion.call(this, mgr, config, "center");
51036 this.visible = true;
51037 this.minWidth = config.minWidth || 20;
51038 this.minHeight = config.minHeight || 20;
51041 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51043 // center panel can't be hidden
51047 // center panel can't be hidden
51050 getMinWidth: function(){
51051 return this.minWidth;
51054 getMinHeight: function(){
51055 return this.minHeight;
51060 Roo.NorthLayoutRegion = function(mgr, config){
51061 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51063 this.split.placement = Roo.SplitBar.TOP;
51064 this.split.orientation = Roo.SplitBar.VERTICAL;
51065 this.split.el.addClass("x-layout-split-v");
51067 var size = config.initialSize || config.height;
51068 if(typeof size != "undefined"){
51069 this.el.setHeight(size);
51072 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51073 orientation: Roo.SplitBar.VERTICAL,
51074 getBox : function(){
51075 if(this.collapsed){
51076 return this.collapsedEl.getBox();
51078 var box = this.el.getBox();
51080 box.height += this.split.el.getHeight();
51085 updateBox : function(box){
51086 if(this.split && !this.collapsed){
51087 box.height -= this.split.el.getHeight();
51088 this.split.el.setLeft(box.x);
51089 this.split.el.setTop(box.y+box.height);
51090 this.split.el.setWidth(box.width);
51092 if(this.collapsed){
51093 this.updateBody(box.width, null);
51095 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51099 Roo.SouthLayoutRegion = function(mgr, config){
51100 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51102 this.split.placement = Roo.SplitBar.BOTTOM;
51103 this.split.orientation = Roo.SplitBar.VERTICAL;
51104 this.split.el.addClass("x-layout-split-v");
51106 var size = config.initialSize || config.height;
51107 if(typeof size != "undefined"){
51108 this.el.setHeight(size);
51111 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51112 orientation: Roo.SplitBar.VERTICAL,
51113 getBox : function(){
51114 if(this.collapsed){
51115 return this.collapsedEl.getBox();
51117 var box = this.el.getBox();
51119 var sh = this.split.el.getHeight();
51126 updateBox : function(box){
51127 if(this.split && !this.collapsed){
51128 var sh = this.split.el.getHeight();
51131 this.split.el.setLeft(box.x);
51132 this.split.el.setTop(box.y-sh);
51133 this.split.el.setWidth(box.width);
51135 if(this.collapsed){
51136 this.updateBody(box.width, null);
51138 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51142 Roo.EastLayoutRegion = function(mgr, config){
51143 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51145 this.split.placement = Roo.SplitBar.RIGHT;
51146 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51147 this.split.el.addClass("x-layout-split-h");
51149 var size = config.initialSize || config.width;
51150 if(typeof size != "undefined"){
51151 this.el.setWidth(size);
51154 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51155 orientation: Roo.SplitBar.HORIZONTAL,
51156 getBox : function(){
51157 if(this.collapsed){
51158 return this.collapsedEl.getBox();
51160 var box = this.el.getBox();
51162 var sw = this.split.el.getWidth();
51169 updateBox : function(box){
51170 if(this.split && !this.collapsed){
51171 var sw = this.split.el.getWidth();
51173 this.split.el.setLeft(box.x);
51174 this.split.el.setTop(box.y);
51175 this.split.el.setHeight(box.height);
51178 if(this.collapsed){
51179 this.updateBody(null, box.height);
51181 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51185 Roo.WestLayoutRegion = function(mgr, config){
51186 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51188 this.split.placement = Roo.SplitBar.LEFT;
51189 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51190 this.split.el.addClass("x-layout-split-h");
51192 var size = config.initialSize || config.width;
51193 if(typeof size != "undefined"){
51194 this.el.setWidth(size);
51197 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51198 orientation: Roo.SplitBar.HORIZONTAL,
51199 getBox : function(){
51200 if(this.collapsed){
51201 return this.collapsedEl.getBox();
51203 var box = this.el.getBox();
51205 box.width += this.split.el.getWidth();
51210 updateBox : function(box){
51211 if(this.split && !this.collapsed){
51212 var sw = this.split.el.getWidth();
51214 this.split.el.setLeft(box.x+box.width);
51215 this.split.el.setTop(box.y);
51216 this.split.el.setHeight(box.height);
51218 if(this.collapsed){
51219 this.updateBody(null, box.height);
51221 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51226 * Ext JS Library 1.1.1
51227 * Copyright(c) 2006-2007, Ext JS, LLC.
51229 * Originally Released Under LGPL - original licence link has changed is not relivant.
51232 * <script type="text/javascript">
51237 * Private internal class for reading and applying state
51239 Roo.LayoutStateManager = function(layout){
51240 // default empty state
51249 Roo.LayoutStateManager.prototype = {
51250 init : function(layout, provider){
51251 this.provider = provider;
51252 var state = provider.get(layout.id+"-layout-state");
51254 var wasUpdating = layout.isUpdating();
51256 layout.beginUpdate();
51258 for(var key in state){
51259 if(typeof state[key] != "function"){
51260 var rstate = state[key];
51261 var r = layout.getRegion(key);
51264 r.resizeTo(rstate.size);
51266 if(rstate.collapsed == true){
51269 r.expand(null, true);
51275 layout.endUpdate();
51277 this.state = state;
51279 this.layout = layout;
51280 layout.on("regionresized", this.onRegionResized, this);
51281 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51282 layout.on("regionexpanded", this.onRegionExpanded, this);
51285 storeState : function(){
51286 this.provider.set(this.layout.id+"-layout-state", this.state);
51289 onRegionResized : function(region, newSize){
51290 this.state[region.getPosition()].size = newSize;
51294 onRegionCollapsed : function(region){
51295 this.state[region.getPosition()].collapsed = true;
51299 onRegionExpanded : function(region){
51300 this.state[region.getPosition()].collapsed = false;
51305 * Ext JS Library 1.1.1
51306 * Copyright(c) 2006-2007, Ext JS, LLC.
51308 * Originally Released Under LGPL - original licence link has changed is not relivant.
51311 * <script type="text/javascript">
51314 * @class Roo.ContentPanel
51315 * @extends Roo.util.Observable
51316 * A basic ContentPanel element.
51317 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51318 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51319 * @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
51320 * @cfg {Boolean} closable True if the panel can be closed/removed
51321 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51322 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51323 * @cfg {Toolbar} toolbar A toolbar for this panel
51324 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51325 * @cfg {String} title The title for this panel
51326 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51327 * @cfg {String} url Calls {@link #setUrl} with this value
51328 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51329 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51330 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51331 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51334 * Create a new ContentPanel.
51335 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51336 * @param {String/Object} config A string to set only the title or a config object
51337 * @param {String} content (optional) Set the HTML content for this panel
51338 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51340 Roo.ContentPanel = function(el, config, content){
51344 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51348 if (config && config.parentLayout) {
51349 el = config.parentLayout.el.createChild();
51352 if(el.autoCreate){ // xtype is available if this is called from factory
51356 this.el = Roo.get(el);
51357 if(!this.el && config && config.autoCreate){
51358 if(typeof config.autoCreate == "object"){
51359 if(!config.autoCreate.id){
51360 config.autoCreate.id = config.id||el;
51362 this.el = Roo.DomHelper.append(document.body,
51363 config.autoCreate, true);
51365 this.el = Roo.DomHelper.append(document.body,
51366 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51369 this.closable = false;
51370 this.loaded = false;
51371 this.active = false;
51372 if(typeof config == "string"){
51373 this.title = config;
51375 Roo.apply(this, config);
51378 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51379 this.wrapEl = this.el.wrap();
51380 this.toolbar.container = this.el.insertSibling(false, 'before');
51381 this.toolbar = new Roo.Toolbar(this.toolbar);
51384 // xtype created footer. - not sure if will work as we normally have to render first..
51385 if (this.footer && !this.footer.el && this.footer.xtype) {
51386 if (!this.wrapEl) {
51387 this.wrapEl = this.el.wrap();
51390 this.footer.container = this.wrapEl.createChild();
51392 this.footer = Roo.factory(this.footer, Roo);
51397 this.resizeEl = Roo.get(this.resizeEl, true);
51399 this.resizeEl = this.el;
51401 // handle view.xtype
51409 * Fires when this panel is activated.
51410 * @param {Roo.ContentPanel} this
51414 * @event deactivate
51415 * Fires when this panel is activated.
51416 * @param {Roo.ContentPanel} this
51418 "deactivate" : true,
51422 * Fires when this panel is resized if fitToFrame is true.
51423 * @param {Roo.ContentPanel} this
51424 * @param {Number} width The width after any component adjustments
51425 * @param {Number} height The height after any component adjustments
51431 * Fires when this tab is created
51432 * @param {Roo.ContentPanel} this
51443 if(this.autoScroll){
51444 this.resizeEl.setStyle("overflow", "auto");
51446 // fix randome scrolling
51447 this.el.on('scroll', function() {
51448 Roo.log('fix random scolling');
51449 this.scrollTo('top',0);
51452 content = content || this.content;
51454 this.setContent(content);
51456 if(config && config.url){
51457 this.setUrl(this.url, this.params, this.loadOnce);
51462 Roo.ContentPanel.superclass.constructor.call(this);
51464 if (this.view && typeof(this.view.xtype) != 'undefined') {
51465 this.view.el = this.el.appendChild(document.createElement("div"));
51466 this.view = Roo.factory(this.view);
51467 this.view.render && this.view.render(false, '');
51471 this.fireEvent('render', this);
51474 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51476 setRegion : function(region){
51477 this.region = region;
51479 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51481 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51486 * Returns the toolbar for this Panel if one was configured.
51487 * @return {Roo.Toolbar}
51489 getToolbar : function(){
51490 return this.toolbar;
51493 setActiveState : function(active){
51494 this.active = active;
51496 this.fireEvent("deactivate", this);
51498 this.fireEvent("activate", this);
51502 * Updates this panel's element
51503 * @param {String} content The new content
51504 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51506 setContent : function(content, loadScripts){
51507 this.el.update(content, loadScripts);
51510 ignoreResize : function(w, h){
51511 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51514 this.lastSize = {width: w, height: h};
51519 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51520 * @return {Roo.UpdateManager} The UpdateManager
51522 getUpdateManager : function(){
51523 return this.el.getUpdateManager();
51526 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51527 * @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:
51530 url: "your-url.php",
51531 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51532 callback: yourFunction,
51533 scope: yourObject, //(optional scope)
51536 text: "Loading...",
51541 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51542 * 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.
51543 * @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}
51544 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51545 * @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.
51546 * @return {Roo.ContentPanel} this
51549 var um = this.el.getUpdateManager();
51550 um.update.apply(um, arguments);
51556 * 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.
51557 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51558 * @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)
51559 * @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)
51560 * @return {Roo.UpdateManager} The UpdateManager
51562 setUrl : function(url, params, loadOnce){
51563 if(this.refreshDelegate){
51564 this.removeListener("activate", this.refreshDelegate);
51566 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51567 this.on("activate", this.refreshDelegate);
51568 return this.el.getUpdateManager();
51571 _handleRefresh : function(url, params, loadOnce){
51572 if(!loadOnce || !this.loaded){
51573 var updater = this.el.getUpdateManager();
51574 updater.update(url, params, this._setLoaded.createDelegate(this));
51578 _setLoaded : function(){
51579 this.loaded = true;
51583 * Returns this panel's id
51586 getId : function(){
51591 * Returns this panel's element - used by regiosn to add.
51592 * @return {Roo.Element}
51594 getEl : function(){
51595 return this.wrapEl || this.el;
51598 adjustForComponents : function(width, height)
51600 //Roo.log('adjustForComponents ');
51601 if(this.resizeEl != this.el){
51602 width -= this.el.getFrameWidth('lr');
51603 height -= this.el.getFrameWidth('tb');
51606 var te = this.toolbar.getEl();
51607 height -= te.getHeight();
51608 te.setWidth(width);
51611 var te = this.footer.getEl();
51612 Roo.log("footer:" + te.getHeight());
51614 height -= te.getHeight();
51615 te.setWidth(width);
51619 if(this.adjustments){
51620 width += this.adjustments[0];
51621 height += this.adjustments[1];
51623 return {"width": width, "height": height};
51626 setSize : function(width, height){
51627 if(this.fitToFrame && !this.ignoreResize(width, height)){
51628 if(this.fitContainer && this.resizeEl != this.el){
51629 this.el.setSize(width, height);
51631 var size = this.adjustForComponents(width, height);
51632 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51633 this.fireEvent('resize', this, size.width, size.height);
51638 * Returns this panel's title
51641 getTitle : function(){
51646 * Set this panel's title
51647 * @param {String} title
51649 setTitle : function(title){
51650 this.title = title;
51652 this.region.updatePanelTitle(this, title);
51657 * Returns true is this panel was configured to be closable
51658 * @return {Boolean}
51660 isClosable : function(){
51661 return this.closable;
51664 beforeSlide : function(){
51666 this.resizeEl.clip();
51669 afterSlide : function(){
51671 this.resizeEl.unclip();
51675 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51676 * Will fail silently if the {@link #setUrl} method has not been called.
51677 * This does not activate the panel, just updates its content.
51679 refresh : function(){
51680 if(this.refreshDelegate){
51681 this.loaded = false;
51682 this.refreshDelegate();
51687 * Destroys this panel
51689 destroy : function(){
51690 this.el.removeAllListeners();
51691 var tempEl = document.createElement("span");
51692 tempEl.appendChild(this.el.dom);
51693 tempEl.innerHTML = "";
51699 * form - if the content panel contains a form - this is a reference to it.
51700 * @type {Roo.form.Form}
51704 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51705 * This contains a reference to it.
51711 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51721 * @param {Object} cfg Xtype definition of item to add.
51724 addxtype : function(cfg) {
51726 if (cfg.xtype.match(/^Form$/)) {
51729 //if (this.footer) {
51730 // el = this.footer.container.insertSibling(false, 'before');
51732 el = this.el.createChild();
51735 this.form = new Roo.form.Form(cfg);
51738 if ( this.form.allItems.length) this.form.render(el.dom);
51741 // should only have one of theses..
51742 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51743 // views.. should not be just added - used named prop 'view''
51745 cfg.el = this.el.appendChild(document.createElement("div"));
51748 var ret = new Roo.factory(cfg);
51750 ret.render && ret.render(false, ''); // render blank..
51759 * @class Roo.GridPanel
51760 * @extends Roo.ContentPanel
51762 * Create a new GridPanel.
51763 * @param {Roo.grid.Grid} grid The grid for this panel
51764 * @param {String/Object} config A string to set only the panel's title, or a config object
51766 Roo.GridPanel = function(grid, config){
51769 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51770 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51772 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51774 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51777 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51779 // xtype created footer. - not sure if will work as we normally have to render first..
51780 if (this.footer && !this.footer.el && this.footer.xtype) {
51782 this.footer.container = this.grid.getView().getFooterPanel(true);
51783 this.footer.dataSource = this.grid.dataSource;
51784 this.footer = Roo.factory(this.footer, Roo);
51788 grid.monitorWindowResize = false; // turn off autosizing
51789 grid.autoHeight = false;
51790 grid.autoWidth = false;
51792 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51795 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51796 getId : function(){
51797 return this.grid.id;
51801 * Returns the grid for this panel
51802 * @return {Roo.grid.Grid}
51804 getGrid : function(){
51808 setSize : function(width, height){
51809 if(!this.ignoreResize(width, height)){
51810 var grid = this.grid;
51811 var size = this.adjustForComponents(width, height);
51812 grid.getGridEl().setSize(size.width, size.height);
51817 beforeSlide : function(){
51818 this.grid.getView().scroller.clip();
51821 afterSlide : function(){
51822 this.grid.getView().scroller.unclip();
51825 destroy : function(){
51826 this.grid.destroy();
51828 Roo.GridPanel.superclass.destroy.call(this);
51834 * @class Roo.NestedLayoutPanel
51835 * @extends Roo.ContentPanel
51837 * Create a new NestedLayoutPanel.
51840 * @param {Roo.BorderLayout} layout The layout for this panel
51841 * @param {String/Object} config A string to set only the title or a config object
51843 Roo.NestedLayoutPanel = function(layout, config)
51845 // construct with only one argument..
51846 /* FIXME - implement nicer consturctors
51847 if (layout.layout) {
51849 layout = config.layout;
51850 delete config.layout;
51852 if (layout.xtype && !layout.getEl) {
51853 // then layout needs constructing..
51854 layout = Roo.factory(layout, Roo);
51859 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51861 layout.monitorWindowResize = false; // turn off autosizing
51862 this.layout = layout;
51863 this.layout.getEl().addClass("x-layout-nested-layout");
51870 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51872 setSize : function(width, height){
51873 if(!this.ignoreResize(width, height)){
51874 var size = this.adjustForComponents(width, height);
51875 var el = this.layout.getEl();
51876 el.setSize(size.width, size.height);
51877 var touch = el.dom.offsetWidth;
51878 this.layout.layout();
51879 // ie requires a double layout on the first pass
51880 if(Roo.isIE && !this.initialized){
51881 this.initialized = true;
51882 this.layout.layout();
51887 // activate all subpanels if not currently active..
51889 setActiveState : function(active){
51890 this.active = active;
51892 this.fireEvent("deactivate", this);
51896 this.fireEvent("activate", this);
51897 // not sure if this should happen before or after..
51898 if (!this.layout) {
51899 return; // should not happen..
51902 for (var r in this.layout.regions) {
51903 reg = this.layout.getRegion(r);
51904 if (reg.getActivePanel()) {
51905 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51906 reg.setActivePanel(reg.getActivePanel());
51909 if (!reg.panels.length) {
51912 reg.showPanel(reg.getPanel(0));
51921 * Returns the nested BorderLayout for this panel
51922 * @return {Roo.BorderLayout}
51924 getLayout : function(){
51925 return this.layout;
51929 * Adds a xtype elements to the layout of the nested panel
51933 xtype : 'ContentPanel',
51940 xtype : 'NestedLayoutPanel',
51946 items : [ ... list of content panels or nested layout panels.. ]
51950 * @param {Object} cfg Xtype definition of item to add.
51952 addxtype : function(cfg) {
51953 return this.layout.addxtype(cfg);
51958 Roo.ScrollPanel = function(el, config, content){
51959 config = config || {};
51960 config.fitToFrame = true;
51961 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51963 this.el.dom.style.overflow = "hidden";
51964 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51965 this.el.removeClass("x-layout-inactive-content");
51966 this.el.on("mousewheel", this.onWheel, this);
51968 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51969 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51970 up.unselectable(); down.unselectable();
51971 up.on("click", this.scrollUp, this);
51972 down.on("click", this.scrollDown, this);
51973 up.addClassOnOver("x-scroller-btn-over");
51974 down.addClassOnOver("x-scroller-btn-over");
51975 up.addClassOnClick("x-scroller-btn-click");
51976 down.addClassOnClick("x-scroller-btn-click");
51977 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51979 this.resizeEl = this.el;
51980 this.el = wrap; this.up = up; this.down = down;
51983 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51985 wheelIncrement : 5,
51986 scrollUp : function(){
51987 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51990 scrollDown : function(){
51991 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51994 afterScroll : function(){
51995 var el = this.resizeEl;
51996 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51997 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51998 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52001 setSize : function(){
52002 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52003 this.afterScroll();
52006 onWheel : function(e){
52007 var d = e.getWheelDelta();
52008 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52009 this.afterScroll();
52013 setContent : function(content, loadScripts){
52014 this.resizeEl.update(content, loadScripts);
52028 * @class Roo.TreePanel
52029 * @extends Roo.ContentPanel
52031 * Create a new TreePanel. - defaults to fit/scoll contents.
52032 * @param {String/Object} config A string to set only the panel's title, or a config object
52033 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52035 Roo.TreePanel = function(config){
52036 var el = config.el;
52037 var tree = config.tree;
52038 delete config.tree;
52039 delete config.el; // hopefull!
52041 // wrapper for IE7 strict & safari scroll issue
52043 var treeEl = el.createChild();
52044 config.resizeEl = treeEl;
52048 Roo.TreePanel.superclass.constructor.call(this, el, config);
52051 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52052 //console.log(tree);
52053 this.on('activate', function()
52055 if (this.tree.rendered) {
52058 //console.log('render tree');
52059 this.tree.render();
52061 // this should not be needed.. - it's actually the 'el' that resizes?
52062 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52064 //this.on('resize', function (cp, w, h) {
52065 // this.tree.innerCt.setWidth(w);
52066 // this.tree.innerCt.setHeight(h);
52067 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52074 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52091 * Ext JS Library 1.1.1
52092 * Copyright(c) 2006-2007, Ext JS, LLC.
52094 * Originally Released Under LGPL - original licence link has changed is not relivant.
52097 * <script type="text/javascript">
52102 * @class Roo.ReaderLayout
52103 * @extends Roo.BorderLayout
52104 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52105 * center region containing two nested regions (a top one for a list view and one for item preview below),
52106 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52107 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52108 * expedites the setup of the overall layout and regions for this common application style.
52111 var reader = new Roo.ReaderLayout();
52112 var CP = Roo.ContentPanel; // shortcut for adding
52114 reader.beginUpdate();
52115 reader.add("north", new CP("north", "North"));
52116 reader.add("west", new CP("west", {title: "West"}));
52117 reader.add("east", new CP("east", {title: "East"}));
52119 reader.regions.listView.add(new CP("listView", "List"));
52120 reader.regions.preview.add(new CP("preview", "Preview"));
52121 reader.endUpdate();
52124 * Create a new ReaderLayout
52125 * @param {Object} config Configuration options
52126 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52127 * document.body if omitted)
52129 Roo.ReaderLayout = function(config, renderTo){
52130 var c = config || {size:{}};
52131 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52132 north: c.north !== false ? Roo.apply({
52136 }, c.north) : false,
52137 west: c.west !== false ? Roo.apply({
52145 margins:{left:5,right:0,bottom:5,top:5},
52146 cmargins:{left:5,right:5,bottom:5,top:5}
52147 }, c.west) : false,
52148 east: c.east !== false ? Roo.apply({
52156 margins:{left:0,right:5,bottom:5,top:5},
52157 cmargins:{left:5,right:5,bottom:5,top:5}
52158 }, c.east) : false,
52159 center: Roo.apply({
52160 tabPosition: 'top',
52164 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52168 this.el.addClass('x-reader');
52170 this.beginUpdate();
52172 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52173 south: c.preview !== false ? Roo.apply({
52180 cmargins:{top:5,left:0, right:0, bottom:0}
52181 }, c.preview) : false,
52182 center: Roo.apply({
52188 this.add('center', new Roo.NestedLayoutPanel(inner,
52189 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52193 this.regions.preview = inner.getRegion('south');
52194 this.regions.listView = inner.getRegion('center');
52197 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52199 * Ext JS Library 1.1.1
52200 * Copyright(c) 2006-2007, Ext JS, LLC.
52202 * Originally Released Under LGPL - original licence link has changed is not relivant.
52205 * <script type="text/javascript">
52209 * @class Roo.grid.Grid
52210 * @extends Roo.util.Observable
52211 * This class represents the primary interface of a component based grid control.
52212 * <br><br>Usage:<pre><code>
52213 var grid = new Roo.grid.Grid("my-container-id", {
52216 selModel: mySelectionModel,
52217 autoSizeColumns: true,
52218 monitorWindowResize: false,
52219 trackMouseOver: true
52224 * <b>Common Problems:</b><br/>
52225 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52226 * element will correct this<br/>
52227 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52228 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52229 * are unpredictable.<br/>
52230 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52231 * grid to calculate dimensions/offsets.<br/>
52233 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52234 * The container MUST have some type of size defined for the grid to fill. The container will be
52235 * automatically set to position relative if it isn't already.
52236 * @param {Object} config A config object that sets properties on this grid.
52238 Roo.grid.Grid = function(container, config){
52239 // initialize the container
52240 this.container = Roo.get(container);
52241 this.container.update("");
52242 this.container.setStyle("overflow", "hidden");
52243 this.container.addClass('x-grid-container');
52245 this.id = this.container.id;
52247 Roo.apply(this, config);
52248 // check and correct shorthanded configs
52250 this.dataSource = this.ds;
52254 this.colModel = this.cm;
52258 this.selModel = this.sm;
52262 if (this.selModel) {
52263 this.selModel = Roo.factory(this.selModel, Roo.grid);
52264 this.sm = this.selModel;
52265 this.sm.xmodule = this.xmodule || false;
52267 if (typeof(this.colModel.config) == 'undefined') {
52268 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52269 this.cm = this.colModel;
52270 this.cm.xmodule = this.xmodule || false;
52272 if (this.dataSource) {
52273 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52274 this.ds = this.dataSource;
52275 this.ds.xmodule = this.xmodule || false;
52282 this.container.setWidth(this.width);
52286 this.container.setHeight(this.height);
52293 * The raw click event for the entire grid.
52294 * @param {Roo.EventObject} e
52299 * The raw dblclick event for the entire grid.
52300 * @param {Roo.EventObject} e
52304 * @event contextmenu
52305 * The raw contextmenu event for the entire grid.
52306 * @param {Roo.EventObject} e
52308 "contextmenu" : true,
52311 * The raw mousedown event for the entire grid.
52312 * @param {Roo.EventObject} e
52314 "mousedown" : true,
52317 * The raw mouseup event for the entire grid.
52318 * @param {Roo.EventObject} e
52323 * The raw mouseover event for the entire grid.
52324 * @param {Roo.EventObject} e
52326 "mouseover" : true,
52329 * The raw mouseout event for the entire grid.
52330 * @param {Roo.EventObject} e
52335 * The raw keypress event for the entire grid.
52336 * @param {Roo.EventObject} e
52341 * The raw keydown event for the entire grid.
52342 * @param {Roo.EventObject} e
52350 * Fires when a cell is clicked
52351 * @param {Grid} this
52352 * @param {Number} rowIndex
52353 * @param {Number} columnIndex
52354 * @param {Roo.EventObject} e
52356 "cellclick" : true,
52358 * @event celldblclick
52359 * Fires when a cell is double clicked
52360 * @param {Grid} this
52361 * @param {Number} rowIndex
52362 * @param {Number} columnIndex
52363 * @param {Roo.EventObject} e
52365 "celldblclick" : true,
52368 * Fires when a row is clicked
52369 * @param {Grid} this
52370 * @param {Number} rowIndex
52371 * @param {Roo.EventObject} e
52375 * @event rowdblclick
52376 * Fires when a row is double clicked
52377 * @param {Grid} this
52378 * @param {Number} rowIndex
52379 * @param {Roo.EventObject} e
52381 "rowdblclick" : true,
52383 * @event headerclick
52384 * Fires when a header is clicked
52385 * @param {Grid} this
52386 * @param {Number} columnIndex
52387 * @param {Roo.EventObject} e
52389 "headerclick" : true,
52391 * @event headerdblclick
52392 * Fires when a header cell is double clicked
52393 * @param {Grid} this
52394 * @param {Number} columnIndex
52395 * @param {Roo.EventObject} e
52397 "headerdblclick" : true,
52399 * @event rowcontextmenu
52400 * Fires when a row is right clicked
52401 * @param {Grid} this
52402 * @param {Number} rowIndex
52403 * @param {Roo.EventObject} e
52405 "rowcontextmenu" : true,
52407 * @event cellcontextmenu
52408 * Fires when a cell is right clicked
52409 * @param {Grid} this
52410 * @param {Number} rowIndex
52411 * @param {Number} cellIndex
52412 * @param {Roo.EventObject} e
52414 "cellcontextmenu" : true,
52416 * @event headercontextmenu
52417 * Fires when a header is right clicked
52418 * @param {Grid} this
52419 * @param {Number} columnIndex
52420 * @param {Roo.EventObject} e
52422 "headercontextmenu" : true,
52424 * @event bodyscroll
52425 * Fires when the body element is scrolled
52426 * @param {Number} scrollLeft
52427 * @param {Number} scrollTop
52429 "bodyscroll" : true,
52431 * @event columnresize
52432 * Fires when the user resizes a column
52433 * @param {Number} columnIndex
52434 * @param {Number} newSize
52436 "columnresize" : true,
52438 * @event columnmove
52439 * Fires when the user moves a column
52440 * @param {Number} oldIndex
52441 * @param {Number} newIndex
52443 "columnmove" : true,
52446 * Fires when row(s) start being dragged
52447 * @param {Grid} this
52448 * @param {Roo.GridDD} dd The drag drop object
52449 * @param {event} e The raw browser event
52451 "startdrag" : true,
52454 * Fires when a drag operation is complete
52455 * @param {Grid} this
52456 * @param {Roo.GridDD} dd The drag drop object
52457 * @param {event} e The raw browser event
52462 * Fires when dragged row(s) are dropped on a valid DD target
52463 * @param {Grid} this
52464 * @param {Roo.GridDD} dd The drag drop object
52465 * @param {String} targetId The target drag drop object
52466 * @param {event} e The raw browser event
52471 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52472 * @param {Grid} this
52473 * @param {Roo.GridDD} dd The drag drop object
52474 * @param {String} targetId The target drag drop object
52475 * @param {event} e The raw browser event
52480 * Fires when the dragged row(s) first cross another DD target while being dragged
52481 * @param {Grid} this
52482 * @param {Roo.GridDD} dd The drag drop object
52483 * @param {String} targetId The target drag drop object
52484 * @param {event} e The raw browser event
52486 "dragenter" : true,
52489 * Fires when the dragged row(s) leave another DD target while being dragged
52490 * @param {Grid} this
52491 * @param {Roo.GridDD} dd The drag drop object
52492 * @param {String} targetId The target drag drop object
52493 * @param {event} e The raw browser event
52498 * Fires when a row is rendered, so you can change add a style to it.
52499 * @param {GridView} gridview The grid view
52500 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52506 * Fires when the grid is rendered
52507 * @param {Grid} grid
52512 Roo.grid.Grid.superclass.constructor.call(this);
52514 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52517 * @cfg {String} ddGroup - drag drop group.
52521 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52523 minColumnWidth : 25,
52526 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52527 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52528 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52530 autoSizeColumns : false,
52533 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52535 autoSizeHeaders : true,
52538 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52540 monitorWindowResize : true,
52543 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52544 * rows measured to get a columns size. Default is 0 (all rows).
52546 maxRowsToMeasure : 0,
52549 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52551 trackMouseOver : true,
52554 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52558 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52560 enableDragDrop : false,
52563 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52565 enableColumnMove : true,
52568 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52570 enableColumnHide : true,
52573 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52575 enableRowHeightSync : false,
52578 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52583 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52585 autoHeight : false,
52588 * @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.
52590 autoExpandColumn : false,
52593 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52596 autoExpandMin : 50,
52599 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52601 autoExpandMax : 1000,
52604 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52609 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52613 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52623 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52624 * of a fixed width. Default is false.
52627 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52630 * Called once after all setup has been completed and the grid is ready to be rendered.
52631 * @return {Roo.grid.Grid} this
52633 render : function()
52635 var c = this.container;
52636 // try to detect autoHeight/width mode
52637 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52638 this.autoHeight = true;
52640 var view = this.getView();
52643 c.on("click", this.onClick, this);
52644 c.on("dblclick", this.onDblClick, this);
52645 c.on("contextmenu", this.onContextMenu, this);
52646 c.on("keydown", this.onKeyDown, this);
52648 c.on("touchstart", this.onTouchStart, this);
52651 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52653 this.getSelectionModel().init(this);
52658 this.loadMask = new Roo.LoadMask(this.container,
52659 Roo.apply({store:this.dataSource}, this.loadMask));
52663 if (this.toolbar && this.toolbar.xtype) {
52664 this.toolbar.container = this.getView().getHeaderPanel(true);
52665 this.toolbar = new Roo.Toolbar(this.toolbar);
52667 if (this.footer && this.footer.xtype) {
52668 this.footer.dataSource = this.getDataSource();
52669 this.footer.container = this.getView().getFooterPanel(true);
52670 this.footer = Roo.factory(this.footer, Roo);
52672 if (this.dropTarget && this.dropTarget.xtype) {
52673 delete this.dropTarget.xtype;
52674 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52678 this.rendered = true;
52679 this.fireEvent('render', this);
52684 * Reconfigures the grid to use a different Store and Column Model.
52685 * The View will be bound to the new objects and refreshed.
52686 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52687 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52689 reconfigure : function(dataSource, colModel){
52691 this.loadMask.destroy();
52692 this.loadMask = new Roo.LoadMask(this.container,
52693 Roo.apply({store:dataSource}, this.loadMask));
52695 this.view.bind(dataSource, colModel);
52696 this.dataSource = dataSource;
52697 this.colModel = colModel;
52698 this.view.refresh(true);
52702 onKeyDown : function(e){
52703 this.fireEvent("keydown", e);
52707 * Destroy this grid.
52708 * @param {Boolean} removeEl True to remove the element
52710 destroy : function(removeEl, keepListeners){
52712 this.loadMask.destroy();
52714 var c = this.container;
52715 c.removeAllListeners();
52716 this.view.destroy();
52717 this.colModel.purgeListeners();
52718 if(!keepListeners){
52719 this.purgeListeners();
52722 if(removeEl === true){
52728 processEvent : function(name, e){
52729 // does this fire select???
52730 //Roo.log('grid:processEvent ' + name);
52732 if (name != 'touchstart' ) {
52733 this.fireEvent(name, e);
52736 var t = e.getTarget();
52738 var header = v.findHeaderIndex(t);
52739 if(header !== false){
52740 var ename = name == 'touchstart' ? 'click' : name;
52742 this.fireEvent("header" + ename, this, header, e);
52744 var row = v.findRowIndex(t);
52745 var cell = v.findCellIndex(t);
52746 if (name == 'touchstart') {
52747 // first touch is always a click.
52748 // hopefull this happens after selection is updated.?
52751 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52752 var cs = this.selModel.getSelectedCell();
52753 if (row == cs[0] && cell == cs[1]){
52757 if (typeof(this.selModel.getSelections) != 'undefined') {
52758 var cs = this.selModel.getSelections();
52759 var ds = this.dataSource;
52760 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52771 this.fireEvent("row" + name, this, row, e);
52772 if(cell !== false){
52773 this.fireEvent("cell" + name, this, row, cell, e);
52780 onClick : function(e){
52781 this.processEvent("click", e);
52784 onTouchStart : function(e){
52785 this.processEvent("touchstart", e);
52789 onContextMenu : function(e, t){
52790 this.processEvent("contextmenu", e);
52794 onDblClick : function(e){
52795 this.processEvent("dblclick", e);
52799 walkCells : function(row, col, step, fn, scope){
52800 var cm = this.colModel, clen = cm.getColumnCount();
52801 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52813 if(fn.call(scope || this, row, col, cm) === true){
52831 if(fn.call(scope || this, row, col, cm) === true){
52843 getSelections : function(){
52844 return this.selModel.getSelections();
52848 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52849 * but if manual update is required this method will initiate it.
52851 autoSize : function(){
52853 this.view.layout();
52854 if(this.view.adjustForScroll){
52855 this.view.adjustForScroll();
52861 * Returns the grid's underlying element.
52862 * @return {Element} The element
52864 getGridEl : function(){
52865 return this.container;
52868 // private for compatibility, overridden by editor grid
52869 stopEditing : function(){},
52872 * Returns the grid's SelectionModel.
52873 * @return {SelectionModel}
52875 getSelectionModel : function(){
52876 if(!this.selModel){
52877 this.selModel = new Roo.grid.RowSelectionModel();
52879 return this.selModel;
52883 * Returns the grid's DataSource.
52884 * @return {DataSource}
52886 getDataSource : function(){
52887 return this.dataSource;
52891 * Returns the grid's ColumnModel.
52892 * @return {ColumnModel}
52894 getColumnModel : function(){
52895 return this.colModel;
52899 * Returns the grid's GridView object.
52900 * @return {GridView}
52902 getView : function(){
52904 this.view = new Roo.grid.GridView(this.viewConfig);
52909 * Called to get grid's drag proxy text, by default returns this.ddText.
52912 getDragDropText : function(){
52913 var count = this.selModel.getCount();
52914 return String.format(this.ddText, count, count == 1 ? '' : 's');
52918 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52919 * %0 is replaced with the number of selected rows.
52922 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52924 * Ext JS Library 1.1.1
52925 * Copyright(c) 2006-2007, Ext JS, LLC.
52927 * Originally Released Under LGPL - original licence link has changed is not relivant.
52930 * <script type="text/javascript">
52933 Roo.grid.AbstractGridView = function(){
52937 "beforerowremoved" : true,
52938 "beforerowsinserted" : true,
52939 "beforerefresh" : true,
52940 "rowremoved" : true,
52941 "rowsinserted" : true,
52942 "rowupdated" : true,
52945 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52948 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52949 rowClass : "x-grid-row",
52950 cellClass : "x-grid-cell",
52951 tdClass : "x-grid-td",
52952 hdClass : "x-grid-hd",
52953 splitClass : "x-grid-hd-split",
52955 init: function(grid){
52957 var cid = this.grid.getGridEl().id;
52958 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52959 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52960 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52961 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52964 getColumnRenderers : function(){
52965 var renderers = [];
52966 var cm = this.grid.colModel;
52967 var colCount = cm.getColumnCount();
52968 for(var i = 0; i < colCount; i++){
52969 renderers[i] = cm.getRenderer(i);
52974 getColumnIds : function(){
52976 var cm = this.grid.colModel;
52977 var colCount = cm.getColumnCount();
52978 for(var i = 0; i < colCount; i++){
52979 ids[i] = cm.getColumnId(i);
52984 getDataIndexes : function(){
52985 if(!this.indexMap){
52986 this.indexMap = this.buildIndexMap();
52988 return this.indexMap.colToData;
52991 getColumnIndexByDataIndex : function(dataIndex){
52992 if(!this.indexMap){
52993 this.indexMap = this.buildIndexMap();
52995 return this.indexMap.dataToCol[dataIndex];
52999 * Set a css style for a column dynamically.
53000 * @param {Number} colIndex The index of the column
53001 * @param {String} name The css property name
53002 * @param {String} value The css value
53004 setCSSStyle : function(colIndex, name, value){
53005 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53006 Roo.util.CSS.updateRule(selector, name, value);
53009 generateRules : function(cm){
53010 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53011 Roo.util.CSS.removeStyleSheet(rulesId);
53012 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53013 var cid = cm.getColumnId(i);
53014 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53015 this.tdSelector, cid, " {\n}\n",
53016 this.hdSelector, cid, " {\n}\n",
53017 this.splitSelector, cid, " {\n}\n");
53019 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53023 * Ext JS Library 1.1.1
53024 * Copyright(c) 2006-2007, Ext JS, LLC.
53026 * Originally Released Under LGPL - original licence link has changed is not relivant.
53029 * <script type="text/javascript">
53033 // This is a support class used internally by the Grid components
53034 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53036 this.view = grid.getView();
53037 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53038 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53040 this.setHandleElId(Roo.id(hd));
53041 this.setOuterHandleElId(Roo.id(hd2));
53043 this.scroll = false;
53045 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53047 getDragData : function(e){
53048 var t = Roo.lib.Event.getTarget(e);
53049 var h = this.view.findHeaderCell(t);
53051 return {ddel: h.firstChild, header:h};
53056 onInitDrag : function(e){
53057 this.view.headersDisabled = true;
53058 var clone = this.dragData.ddel.cloneNode(true);
53059 clone.id = Roo.id();
53060 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53061 this.proxy.update(clone);
53065 afterValidDrop : function(){
53067 setTimeout(function(){
53068 v.headersDisabled = false;
53072 afterInvalidDrop : function(){
53074 setTimeout(function(){
53075 v.headersDisabled = false;
53081 * Ext JS Library 1.1.1
53082 * Copyright(c) 2006-2007, Ext JS, LLC.
53084 * Originally Released Under LGPL - original licence link has changed is not relivant.
53087 * <script type="text/javascript">
53090 // This is a support class used internally by the Grid components
53091 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53093 this.view = grid.getView();
53094 // split the proxies so they don't interfere with mouse events
53095 this.proxyTop = Roo.DomHelper.append(document.body, {
53096 cls:"col-move-top", html:" "
53098 this.proxyBottom = Roo.DomHelper.append(document.body, {
53099 cls:"col-move-bottom", html:" "
53101 this.proxyTop.hide = this.proxyBottom.hide = function(){
53102 this.setLeftTop(-100,-100);
53103 this.setStyle("visibility", "hidden");
53105 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53106 // temporarily disabled
53107 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53108 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53110 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53111 proxyOffsets : [-4, -9],
53112 fly: Roo.Element.fly,
53114 getTargetFromEvent : function(e){
53115 var t = Roo.lib.Event.getTarget(e);
53116 var cindex = this.view.findCellIndex(t);
53117 if(cindex !== false){
53118 return this.view.getHeaderCell(cindex);
53123 nextVisible : function(h){
53124 var v = this.view, cm = this.grid.colModel;
53127 if(!cm.isHidden(v.getCellIndex(h))){
53135 prevVisible : function(h){
53136 var v = this.view, cm = this.grid.colModel;
53139 if(!cm.isHidden(v.getCellIndex(h))){
53147 positionIndicator : function(h, n, e){
53148 var x = Roo.lib.Event.getPageX(e);
53149 var r = Roo.lib.Dom.getRegion(n.firstChild);
53150 var px, pt, py = r.top + this.proxyOffsets[1];
53151 if((r.right - x) <= (r.right-r.left)/2){
53152 px = r.right+this.view.borderWidth;
53158 var oldIndex = this.view.getCellIndex(h);
53159 var newIndex = this.view.getCellIndex(n);
53161 if(this.grid.colModel.isFixed(newIndex)){
53165 var locked = this.grid.colModel.isLocked(newIndex);
53170 if(oldIndex < newIndex){
53173 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53176 px += this.proxyOffsets[0];
53177 this.proxyTop.setLeftTop(px, py);
53178 this.proxyTop.show();
53179 if(!this.bottomOffset){
53180 this.bottomOffset = this.view.mainHd.getHeight();
53182 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53183 this.proxyBottom.show();
53187 onNodeEnter : function(n, dd, e, data){
53188 if(data.header != n){
53189 this.positionIndicator(data.header, n, e);
53193 onNodeOver : function(n, dd, e, data){
53194 var result = false;
53195 if(data.header != n){
53196 result = this.positionIndicator(data.header, n, e);
53199 this.proxyTop.hide();
53200 this.proxyBottom.hide();
53202 return result ? this.dropAllowed : this.dropNotAllowed;
53205 onNodeOut : function(n, dd, e, data){
53206 this.proxyTop.hide();
53207 this.proxyBottom.hide();
53210 onNodeDrop : function(n, dd, e, data){
53211 var h = data.header;
53213 var cm = this.grid.colModel;
53214 var x = Roo.lib.Event.getPageX(e);
53215 var r = Roo.lib.Dom.getRegion(n.firstChild);
53216 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53217 var oldIndex = this.view.getCellIndex(h);
53218 var newIndex = this.view.getCellIndex(n);
53219 var locked = cm.isLocked(newIndex);
53223 if(oldIndex < newIndex){
53226 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53229 cm.setLocked(oldIndex, locked, true);
53230 cm.moveColumn(oldIndex, newIndex);
53231 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53239 * Ext JS Library 1.1.1
53240 * Copyright(c) 2006-2007, Ext JS, LLC.
53242 * Originally Released Under LGPL - original licence link has changed is not relivant.
53245 * <script type="text/javascript">
53249 * @class Roo.grid.GridView
53250 * @extends Roo.util.Observable
53253 * @param {Object} config
53255 Roo.grid.GridView = function(config){
53256 Roo.grid.GridView.superclass.constructor.call(this);
53259 Roo.apply(this, config);
53262 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53264 unselectable : 'unselectable="on"',
53265 unselectableCls : 'x-unselectable',
53268 rowClass : "x-grid-row",
53270 cellClass : "x-grid-col",
53272 tdClass : "x-grid-td",
53274 hdClass : "x-grid-hd",
53276 splitClass : "x-grid-split",
53278 sortClasses : ["sort-asc", "sort-desc"],
53280 enableMoveAnim : false,
53284 dh : Roo.DomHelper,
53286 fly : Roo.Element.fly,
53288 css : Roo.util.CSS,
53294 scrollIncrement : 22,
53296 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53298 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53300 bind : function(ds, cm){
53302 this.ds.un("load", this.onLoad, this);
53303 this.ds.un("datachanged", this.onDataChange, this);
53304 this.ds.un("add", this.onAdd, this);
53305 this.ds.un("remove", this.onRemove, this);
53306 this.ds.un("update", this.onUpdate, this);
53307 this.ds.un("clear", this.onClear, this);
53310 ds.on("load", this.onLoad, this);
53311 ds.on("datachanged", this.onDataChange, this);
53312 ds.on("add", this.onAdd, this);
53313 ds.on("remove", this.onRemove, this);
53314 ds.on("update", this.onUpdate, this);
53315 ds.on("clear", this.onClear, this);
53320 this.cm.un("widthchange", this.onColWidthChange, this);
53321 this.cm.un("headerchange", this.onHeaderChange, this);
53322 this.cm.un("hiddenchange", this.onHiddenChange, this);
53323 this.cm.un("columnmoved", this.onColumnMove, this);
53324 this.cm.un("columnlockchange", this.onColumnLock, this);
53327 this.generateRules(cm);
53328 cm.on("widthchange", this.onColWidthChange, this);
53329 cm.on("headerchange", this.onHeaderChange, this);
53330 cm.on("hiddenchange", this.onHiddenChange, this);
53331 cm.on("columnmoved", this.onColumnMove, this);
53332 cm.on("columnlockchange", this.onColumnLock, this);
53337 init: function(grid){
53338 Roo.grid.GridView.superclass.init.call(this, grid);
53340 this.bind(grid.dataSource, grid.colModel);
53342 grid.on("headerclick", this.handleHeaderClick, this);
53344 if(grid.trackMouseOver){
53345 grid.on("mouseover", this.onRowOver, this);
53346 grid.on("mouseout", this.onRowOut, this);
53348 grid.cancelTextSelection = function(){};
53349 this.gridId = grid.id;
53351 var tpls = this.templates || {};
53354 tpls.master = new Roo.Template(
53355 '<div class="x-grid" hidefocus="true">',
53356 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53357 '<div class="x-grid-topbar"></div>',
53358 '<div class="x-grid-scroller"><div></div></div>',
53359 '<div class="x-grid-locked">',
53360 '<div class="x-grid-header">{lockedHeader}</div>',
53361 '<div class="x-grid-body">{lockedBody}</div>',
53363 '<div class="x-grid-viewport">',
53364 '<div class="x-grid-header">{header}</div>',
53365 '<div class="x-grid-body">{body}</div>',
53367 '<div class="x-grid-bottombar"></div>',
53369 '<div class="x-grid-resize-proxy"> </div>',
53372 tpls.master.disableformats = true;
53376 tpls.header = new Roo.Template(
53377 '<table border="0" cellspacing="0" cellpadding="0">',
53378 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53381 tpls.header.disableformats = true;
53383 tpls.header.compile();
53386 tpls.hcell = new Roo.Template(
53387 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53388 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53391 tpls.hcell.disableFormats = true;
53393 tpls.hcell.compile();
53396 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53397 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53398 tpls.hsplit.disableFormats = true;
53400 tpls.hsplit.compile();
53403 tpls.body = new Roo.Template(
53404 '<table border="0" cellspacing="0" cellpadding="0">',
53405 "<tbody>{rows}</tbody>",
53408 tpls.body.disableFormats = true;
53410 tpls.body.compile();
53413 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53414 tpls.row.disableFormats = true;
53416 tpls.row.compile();
53419 tpls.cell = new Roo.Template(
53420 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53421 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53422 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53425 tpls.cell.disableFormats = true;
53427 tpls.cell.compile();
53429 this.templates = tpls;
53432 // remap these for backwards compat
53433 onColWidthChange : function(){
53434 this.updateColumns.apply(this, arguments);
53436 onHeaderChange : function(){
53437 this.updateHeaders.apply(this, arguments);
53439 onHiddenChange : function(){
53440 this.handleHiddenChange.apply(this, arguments);
53442 onColumnMove : function(){
53443 this.handleColumnMove.apply(this, arguments);
53445 onColumnLock : function(){
53446 this.handleLockChange.apply(this, arguments);
53449 onDataChange : function(){
53451 this.updateHeaderSortState();
53454 onClear : function(){
53458 onUpdate : function(ds, record){
53459 this.refreshRow(record);
53462 refreshRow : function(record){
53463 var ds = this.ds, index;
53464 if(typeof record == 'number'){
53466 record = ds.getAt(index);
53468 index = ds.indexOf(record);
53470 this.insertRows(ds, index, index, true);
53471 this.onRemove(ds, record, index+1, true);
53472 this.syncRowHeights(index, index);
53474 this.fireEvent("rowupdated", this, index, record);
53477 onAdd : function(ds, records, index){
53478 this.insertRows(ds, index, index + (records.length-1));
53481 onRemove : function(ds, record, index, isUpdate){
53482 if(isUpdate !== true){
53483 this.fireEvent("beforerowremoved", this, index, record);
53485 var bt = this.getBodyTable(), lt = this.getLockedTable();
53486 if(bt.rows[index]){
53487 bt.firstChild.removeChild(bt.rows[index]);
53489 if(lt.rows[index]){
53490 lt.firstChild.removeChild(lt.rows[index]);
53492 if(isUpdate !== true){
53493 this.stripeRows(index);
53494 this.syncRowHeights(index, index);
53496 this.fireEvent("rowremoved", this, index, record);
53500 onLoad : function(){
53501 this.scrollToTop();
53505 * Scrolls the grid to the top
53507 scrollToTop : function(){
53509 this.scroller.dom.scrollTop = 0;
53515 * Gets a panel in the header of the grid that can be used for toolbars etc.
53516 * After modifying the contents of this panel a call to grid.autoSize() may be
53517 * required to register any changes in size.
53518 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53519 * @return Roo.Element
53521 getHeaderPanel : function(doShow){
53523 this.headerPanel.show();
53525 return this.headerPanel;
53529 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53530 * After modifying the contents of this panel a call to grid.autoSize() may be
53531 * required to register any changes in size.
53532 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53533 * @return Roo.Element
53535 getFooterPanel : function(doShow){
53537 this.footerPanel.show();
53539 return this.footerPanel;
53542 initElements : function(){
53543 var E = Roo.Element;
53544 var el = this.grid.getGridEl().dom.firstChild;
53545 var cs = el.childNodes;
53547 this.el = new E(el);
53549 this.focusEl = new E(el.firstChild);
53550 this.focusEl.swallowEvent("click", true);
53552 this.headerPanel = new E(cs[1]);
53553 this.headerPanel.enableDisplayMode("block");
53555 this.scroller = new E(cs[2]);
53556 this.scrollSizer = new E(this.scroller.dom.firstChild);
53558 this.lockedWrap = new E(cs[3]);
53559 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53560 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53562 this.mainWrap = new E(cs[4]);
53563 this.mainHd = new E(this.mainWrap.dom.firstChild);
53564 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53566 this.footerPanel = new E(cs[5]);
53567 this.footerPanel.enableDisplayMode("block");
53569 this.resizeProxy = new E(cs[6]);
53571 this.headerSelector = String.format(
53572 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53573 this.lockedHd.id, this.mainHd.id
53576 this.splitterSelector = String.format(
53577 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53578 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53581 idToCssName : function(s)
53583 return s.replace(/[^a-z0-9]+/ig, '-');
53586 getHeaderCell : function(index){
53587 return Roo.DomQuery.select(this.headerSelector)[index];
53590 getHeaderCellMeasure : function(index){
53591 return this.getHeaderCell(index).firstChild;
53594 getHeaderCellText : function(index){
53595 return this.getHeaderCell(index).firstChild.firstChild;
53598 getLockedTable : function(){
53599 return this.lockedBody.dom.firstChild;
53602 getBodyTable : function(){
53603 return this.mainBody.dom.firstChild;
53606 getLockedRow : function(index){
53607 return this.getLockedTable().rows[index];
53610 getRow : function(index){
53611 return this.getBodyTable().rows[index];
53614 getRowComposite : function(index){
53616 this.rowEl = new Roo.CompositeElementLite();
53618 var els = [], lrow, mrow;
53619 if(lrow = this.getLockedRow(index)){
53622 if(mrow = this.getRow(index)){
53625 this.rowEl.elements = els;
53629 * Gets the 'td' of the cell
53631 * @param {Integer} rowIndex row to select
53632 * @param {Integer} colIndex column to select
53636 getCell : function(rowIndex, colIndex){
53637 var locked = this.cm.getLockedCount();
53639 if(colIndex < locked){
53640 source = this.lockedBody.dom.firstChild;
53642 source = this.mainBody.dom.firstChild;
53643 colIndex -= locked;
53645 return source.rows[rowIndex].childNodes[colIndex];
53648 getCellText : function(rowIndex, colIndex){
53649 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53652 getCellBox : function(cell){
53653 var b = this.fly(cell).getBox();
53654 if(Roo.isOpera){ // opera fails to report the Y
53655 b.y = cell.offsetTop + this.mainBody.getY();
53660 getCellIndex : function(cell){
53661 var id = String(cell.className).match(this.cellRE);
53663 return parseInt(id[1], 10);
53668 findHeaderIndex : function(n){
53669 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53670 return r ? this.getCellIndex(r) : false;
53673 findHeaderCell : function(n){
53674 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53675 return r ? r : false;
53678 findRowIndex : function(n){
53682 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53683 return r ? r.rowIndex : false;
53686 findCellIndex : function(node){
53687 var stop = this.el.dom;
53688 while(node && node != stop){
53689 if(this.findRE.test(node.className)){
53690 return this.getCellIndex(node);
53692 node = node.parentNode;
53697 getColumnId : function(index){
53698 return this.cm.getColumnId(index);
53701 getSplitters : function()
53703 if(this.splitterSelector){
53704 return Roo.DomQuery.select(this.splitterSelector);
53710 getSplitter : function(index){
53711 return this.getSplitters()[index];
53714 onRowOver : function(e, t){
53716 if((row = this.findRowIndex(t)) !== false){
53717 this.getRowComposite(row).addClass("x-grid-row-over");
53721 onRowOut : function(e, t){
53723 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53724 this.getRowComposite(row).removeClass("x-grid-row-over");
53728 renderHeaders : function(){
53730 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53731 var cb = [], lb = [], sb = [], lsb = [], p = {};
53732 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53733 p.cellId = "x-grid-hd-0-" + i;
53734 p.splitId = "x-grid-csplit-0-" + i;
53735 p.id = cm.getColumnId(i);
53736 p.title = cm.getColumnTooltip(i) || "";
53737 p.value = cm.getColumnHeader(i) || "";
53738 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53739 if(!cm.isLocked(i)){
53740 cb[cb.length] = ct.apply(p);
53741 sb[sb.length] = st.apply(p);
53743 lb[lb.length] = ct.apply(p);
53744 lsb[lsb.length] = st.apply(p);
53747 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53748 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53751 updateHeaders : function(){
53752 var html = this.renderHeaders();
53753 this.lockedHd.update(html[0]);
53754 this.mainHd.update(html[1]);
53758 * Focuses the specified row.
53759 * @param {Number} row The row index
53761 focusRow : function(row)
53763 //Roo.log('GridView.focusRow');
53764 var x = this.scroller.dom.scrollLeft;
53765 this.focusCell(row, 0, false);
53766 this.scroller.dom.scrollLeft = x;
53770 * Focuses the specified cell.
53771 * @param {Number} row The row index
53772 * @param {Number} col The column index
53773 * @param {Boolean} hscroll false to disable horizontal scrolling
53775 focusCell : function(row, col, hscroll)
53777 //Roo.log('GridView.focusCell');
53778 var el = this.ensureVisible(row, col, hscroll);
53779 this.focusEl.alignTo(el, "tl-tl");
53781 this.focusEl.focus();
53783 this.focusEl.focus.defer(1, this.focusEl);
53788 * Scrolls the specified cell into view
53789 * @param {Number} row The row index
53790 * @param {Number} col The column index
53791 * @param {Boolean} hscroll false to disable horizontal scrolling
53793 ensureVisible : function(row, col, hscroll)
53795 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53796 //return null; //disable for testing.
53797 if(typeof row != "number"){
53798 row = row.rowIndex;
53800 if(row < 0 && row >= this.ds.getCount()){
53803 col = (col !== undefined ? col : 0);
53804 var cm = this.grid.colModel;
53805 while(cm.isHidden(col)){
53809 var el = this.getCell(row, col);
53813 var c = this.scroller.dom;
53815 var ctop = parseInt(el.offsetTop, 10);
53816 var cleft = parseInt(el.offsetLeft, 10);
53817 var cbot = ctop + el.offsetHeight;
53818 var cright = cleft + el.offsetWidth;
53820 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53821 var stop = parseInt(c.scrollTop, 10);
53822 var sleft = parseInt(c.scrollLeft, 10);
53823 var sbot = stop + ch;
53824 var sright = sleft + c.clientWidth;
53826 Roo.log('GridView.ensureVisible:' +
53828 ' c.clientHeight:' + c.clientHeight +
53829 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53837 c.scrollTop = ctop;
53838 //Roo.log("set scrolltop to ctop DISABLE?");
53839 }else if(cbot > sbot){
53840 //Roo.log("set scrolltop to cbot-ch");
53841 c.scrollTop = cbot-ch;
53844 if(hscroll !== false){
53846 c.scrollLeft = cleft;
53847 }else if(cright > sright){
53848 c.scrollLeft = cright-c.clientWidth;
53855 updateColumns : function(){
53856 this.grid.stopEditing();
53857 var cm = this.grid.colModel, colIds = this.getColumnIds();
53858 //var totalWidth = cm.getTotalWidth();
53860 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53861 //if(cm.isHidden(i)) continue;
53862 var w = cm.getColumnWidth(i);
53863 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53864 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53866 this.updateSplitters();
53869 generateRules : function(cm){
53870 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53871 Roo.util.CSS.removeStyleSheet(rulesId);
53872 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53873 var cid = cm.getColumnId(i);
53875 if(cm.config[i].align){
53876 align = 'text-align:'+cm.config[i].align+';';
53879 if(cm.isHidden(i)){
53880 hidden = 'display:none;';
53882 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53884 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53885 this.hdSelector, cid, " {\n", align, width, "}\n",
53886 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53887 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53889 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53892 updateSplitters : function(){
53893 var cm = this.cm, s = this.getSplitters();
53894 if(s){ // splitters not created yet
53895 var pos = 0, locked = true;
53896 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53897 if(cm.isHidden(i)) continue;
53898 var w = cm.getColumnWidth(i); // make sure it's a number
53899 if(!cm.isLocked(i) && locked){
53904 s[i].style.left = (pos-this.splitOffset) + "px";
53909 handleHiddenChange : function(colModel, colIndex, hidden){
53911 this.hideColumn(colIndex);
53913 this.unhideColumn(colIndex);
53917 hideColumn : function(colIndex){
53918 var cid = this.getColumnId(colIndex);
53919 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53920 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53922 this.updateHeaders();
53924 this.updateSplitters();
53928 unhideColumn : function(colIndex){
53929 var cid = this.getColumnId(colIndex);
53930 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53931 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53934 this.updateHeaders();
53936 this.updateSplitters();
53940 insertRows : function(dm, firstRow, lastRow, isUpdate){
53941 if(firstRow == 0 && lastRow == dm.getCount()-1){
53945 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53947 var s = this.getScrollState();
53948 var markup = this.renderRows(firstRow, lastRow);
53949 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53950 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53951 this.restoreScroll(s);
53953 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53954 this.syncRowHeights(firstRow, lastRow);
53955 this.stripeRows(firstRow);
53961 bufferRows : function(markup, target, index){
53962 var before = null, trows = target.rows, tbody = target.tBodies[0];
53963 if(index < trows.length){
53964 before = trows[index];
53966 var b = document.createElement("div");
53967 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53968 var rows = b.firstChild.rows;
53969 for(var i = 0, len = rows.length; i < len; i++){
53971 tbody.insertBefore(rows[0], before);
53973 tbody.appendChild(rows[0]);
53980 deleteRows : function(dm, firstRow, lastRow){
53981 if(dm.getRowCount()<1){
53982 this.fireEvent("beforerefresh", this);
53983 this.mainBody.update("");
53984 this.lockedBody.update("");
53985 this.fireEvent("refresh", this);
53987 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53988 var bt = this.getBodyTable();
53989 var tbody = bt.firstChild;
53990 var rows = bt.rows;
53991 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53992 tbody.removeChild(rows[firstRow]);
53994 this.stripeRows(firstRow);
53995 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53999 updateRows : function(dataSource, firstRow, lastRow){
54000 var s = this.getScrollState();
54002 this.restoreScroll(s);
54005 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54009 this.updateHeaderSortState();
54012 getScrollState : function(){
54014 var sb = this.scroller.dom;
54015 return {left: sb.scrollLeft, top: sb.scrollTop};
54018 stripeRows : function(startRow){
54019 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54022 startRow = startRow || 0;
54023 var rows = this.getBodyTable().rows;
54024 var lrows = this.getLockedTable().rows;
54025 var cls = ' x-grid-row-alt ';
54026 for(var i = startRow, len = rows.length; i < len; i++){
54027 var row = rows[i], lrow = lrows[i];
54028 var isAlt = ((i+1) % 2 == 0);
54029 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54030 if(isAlt == hasAlt){
54034 row.className += " x-grid-row-alt";
54036 row.className = row.className.replace("x-grid-row-alt", "");
54039 lrow.className = row.className;
54044 restoreScroll : function(state){
54045 //Roo.log('GridView.restoreScroll');
54046 var sb = this.scroller.dom;
54047 sb.scrollLeft = state.left;
54048 sb.scrollTop = state.top;
54052 syncScroll : function(){
54053 //Roo.log('GridView.syncScroll');
54054 var sb = this.scroller.dom;
54055 var sh = this.mainHd.dom;
54056 var bs = this.mainBody.dom;
54057 var lv = this.lockedBody.dom;
54058 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54059 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54062 handleScroll : function(e){
54064 var sb = this.scroller.dom;
54065 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54069 handleWheel : function(e){
54070 var d = e.getWheelDelta();
54071 this.scroller.dom.scrollTop -= d*22;
54072 // set this here to prevent jumpy scrolling on large tables
54073 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54077 renderRows : function(startRow, endRow){
54078 // pull in all the crap needed to render rows
54079 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54080 var colCount = cm.getColumnCount();
54082 if(ds.getCount() < 1){
54086 // build a map for all the columns
54088 for(var i = 0; i < colCount; i++){
54089 var name = cm.getDataIndex(i);
54091 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54092 renderer : cm.getRenderer(i),
54093 id : cm.getColumnId(i),
54094 locked : cm.isLocked(i)
54098 startRow = startRow || 0;
54099 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54101 // records to render
54102 var rs = ds.getRange(startRow, endRow);
54104 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54107 // As much as I hate to duplicate code, this was branched because FireFox really hates
54108 // [].join("") on strings. The performance difference was substantial enough to
54109 // branch this function
54110 doRender : Roo.isGecko ?
54111 function(cs, rs, ds, startRow, colCount, stripe){
54112 var ts = this.templates, ct = ts.cell, rt = ts.row;
54114 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54116 var hasListener = this.grid.hasListener('rowclass');
54118 for(var j = 0, len = rs.length; j < len; j++){
54119 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54120 for(var i = 0; i < colCount; i++){
54122 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54124 p.css = p.attr = "";
54125 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54126 if(p.value == undefined || p.value === "") p.value = " ";
54127 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54128 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54130 var markup = ct.apply(p);
54138 if(stripe && ((rowIndex+1) % 2 == 0)){
54139 alt.push("x-grid-row-alt")
54142 alt.push( " x-grid-dirty-row");
54145 if(this.getRowClass){
54146 alt.push(this.getRowClass(r, rowIndex));
54152 rowIndex : rowIndex,
54155 this.grid.fireEvent('rowclass', this, rowcfg);
54156 alt.push(rowcfg.rowClass);
54158 rp.alt = alt.join(" ");
54159 lbuf+= rt.apply(rp);
54161 buf+= rt.apply(rp);
54163 return [lbuf, buf];
54165 function(cs, rs, ds, startRow, colCount, stripe){
54166 var ts = this.templates, ct = ts.cell, rt = ts.row;
54168 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54169 var hasListener = this.grid.hasListener('rowclass');
54172 for(var j = 0, len = rs.length; j < len; j++){
54173 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54174 for(var i = 0; i < colCount; i++){
54176 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54178 p.css = p.attr = "";
54179 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54180 if(p.value == undefined || p.value === "") p.value = " ";
54181 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54182 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54185 var markup = ct.apply(p);
54187 cb[cb.length] = markup;
54189 lcb[lcb.length] = markup;
54193 if(stripe && ((rowIndex+1) % 2 == 0)){
54194 alt.push( "x-grid-row-alt");
54197 alt.push(" x-grid-dirty-row");
54200 if(this.getRowClass){
54201 alt.push( this.getRowClass(r, rowIndex));
54207 rowIndex : rowIndex,
54210 this.grid.fireEvent('rowclass', this, rowcfg);
54211 alt.push(rowcfg.rowClass);
54213 rp.alt = alt.join(" ");
54214 rp.cells = lcb.join("");
54215 lbuf[lbuf.length] = rt.apply(rp);
54216 rp.cells = cb.join("");
54217 buf[buf.length] = rt.apply(rp);
54219 return [lbuf.join(""), buf.join("")];
54222 renderBody : function(){
54223 var markup = this.renderRows();
54224 var bt = this.templates.body;
54225 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54229 * Refreshes the grid
54230 * @param {Boolean} headersToo
54232 refresh : function(headersToo){
54233 this.fireEvent("beforerefresh", this);
54234 this.grid.stopEditing();
54235 var result = this.renderBody();
54236 this.lockedBody.update(result[0]);
54237 this.mainBody.update(result[1]);
54238 if(headersToo === true){
54239 this.updateHeaders();
54240 this.updateColumns();
54241 this.updateSplitters();
54242 this.updateHeaderSortState();
54244 this.syncRowHeights();
54246 this.fireEvent("refresh", this);
54249 handleColumnMove : function(cm, oldIndex, newIndex){
54250 this.indexMap = null;
54251 var s = this.getScrollState();
54252 this.refresh(true);
54253 this.restoreScroll(s);
54254 this.afterMove(newIndex);
54257 afterMove : function(colIndex){
54258 if(this.enableMoveAnim && Roo.enableFx){
54259 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54261 // if multisort - fix sortOrder, and reload..
54262 if (this.grid.dataSource.multiSort) {
54263 // the we can call sort again..
54264 var dm = this.grid.dataSource;
54265 var cm = this.grid.colModel;
54267 for(var i = 0; i < cm.config.length; i++ ) {
54269 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54270 continue; // dont' bother, it's not in sort list or being set.
54273 so.push(cm.config[i].dataIndex);
54276 dm.load(dm.lastOptions);
54283 updateCell : function(dm, rowIndex, dataIndex){
54284 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54285 if(typeof colIndex == "undefined"){ // not present in grid
54288 var cm = this.grid.colModel;
54289 var cell = this.getCell(rowIndex, colIndex);
54290 var cellText = this.getCellText(rowIndex, colIndex);
54293 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54294 id : cm.getColumnId(colIndex),
54295 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54297 var renderer = cm.getRenderer(colIndex);
54298 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54299 if(typeof val == "undefined" || val === "") val = " ";
54300 cellText.innerHTML = val;
54301 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54302 this.syncRowHeights(rowIndex, rowIndex);
54305 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54307 if(this.grid.autoSizeHeaders){
54308 var h = this.getHeaderCellMeasure(colIndex);
54309 maxWidth = Math.max(maxWidth, h.scrollWidth);
54312 if(this.cm.isLocked(colIndex)){
54313 tb = this.getLockedTable();
54316 tb = this.getBodyTable();
54317 index = colIndex - this.cm.getLockedCount();
54320 var rows = tb.rows;
54321 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54322 for(var i = 0; i < stopIndex; i++){
54323 var cell = rows[i].childNodes[index].firstChild;
54324 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54327 return maxWidth + /*margin for error in IE*/ 5;
54330 * Autofit a column to its content.
54331 * @param {Number} colIndex
54332 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54334 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54335 if(this.cm.isHidden(colIndex)){
54336 return; // can't calc a hidden column
54339 var cid = this.cm.getColumnId(colIndex);
54340 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54341 if(this.grid.autoSizeHeaders){
54342 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54345 var newWidth = this.calcColumnWidth(colIndex);
54346 this.cm.setColumnWidth(colIndex,
54347 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54348 if(!suppressEvent){
54349 this.grid.fireEvent("columnresize", colIndex, newWidth);
54354 * Autofits all columns to their content and then expands to fit any extra space in the grid
54356 autoSizeColumns : function(){
54357 var cm = this.grid.colModel;
54358 var colCount = cm.getColumnCount();
54359 for(var i = 0; i < colCount; i++){
54360 this.autoSizeColumn(i, true, true);
54362 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54365 this.updateColumns();
54371 * Autofits all columns to the grid's width proportionate with their current size
54372 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54374 fitColumns : function(reserveScrollSpace){
54375 var cm = this.grid.colModel;
54376 var colCount = cm.getColumnCount();
54380 for (i = 0; i < colCount; i++){
54381 if(!cm.isHidden(i) && !cm.isFixed(i)){
54382 w = cm.getColumnWidth(i);
54388 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54389 if(reserveScrollSpace){
54392 var frac = (avail - cm.getTotalWidth())/width;
54393 while (cols.length){
54396 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54398 this.updateColumns();
54402 onRowSelect : function(rowIndex){
54403 var row = this.getRowComposite(rowIndex);
54404 row.addClass("x-grid-row-selected");
54407 onRowDeselect : function(rowIndex){
54408 var row = this.getRowComposite(rowIndex);
54409 row.removeClass("x-grid-row-selected");
54412 onCellSelect : function(row, col){
54413 var cell = this.getCell(row, col);
54415 Roo.fly(cell).addClass("x-grid-cell-selected");
54419 onCellDeselect : function(row, col){
54420 var cell = this.getCell(row, col);
54422 Roo.fly(cell).removeClass("x-grid-cell-selected");
54426 updateHeaderSortState : function(){
54428 // sort state can be single { field: xxx, direction : yyy}
54429 // or { xxx=>ASC , yyy : DESC ..... }
54432 if (!this.ds.multiSort) {
54433 var state = this.ds.getSortState();
54437 mstate[state.field] = state.direction;
54438 // FIXME... - this is not used here.. but might be elsewhere..
54439 this.sortState = state;
54442 mstate = this.ds.sortToggle;
54444 //remove existing sort classes..
54446 var sc = this.sortClasses;
54447 var hds = this.el.select(this.headerSelector).removeClass(sc);
54449 for(var f in mstate) {
54451 var sortColumn = this.cm.findColumnIndex(f);
54453 if(sortColumn != -1){
54454 var sortDir = mstate[f];
54455 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54464 handleHeaderClick : function(g, index,e){
54466 Roo.log("header click");
54469 // touch events on header are handled by context
54470 this.handleHdCtx(g,index,e);
54475 if(this.headersDisabled){
54478 var dm = g.dataSource, cm = g.colModel;
54479 if(!cm.isSortable(index)){
54484 if (dm.multiSort) {
54485 // update the sortOrder
54487 for(var i = 0; i < cm.config.length; i++ ) {
54489 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54490 continue; // dont' bother, it's not in sort list or being set.
54493 so.push(cm.config[i].dataIndex);
54499 dm.sort(cm.getDataIndex(index));
54503 destroy : function(){
54505 this.colMenu.removeAll();
54506 Roo.menu.MenuMgr.unregister(this.colMenu);
54507 this.colMenu.getEl().remove();
54508 delete this.colMenu;
54511 this.hmenu.removeAll();
54512 Roo.menu.MenuMgr.unregister(this.hmenu);
54513 this.hmenu.getEl().remove();
54516 if(this.grid.enableColumnMove){
54517 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54519 for(var dd in dds){
54520 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54521 var elid = dds[dd].dragElId;
54523 Roo.get(elid).remove();
54524 } else if(dds[dd].config.isTarget){
54525 dds[dd].proxyTop.remove();
54526 dds[dd].proxyBottom.remove();
54529 if(Roo.dd.DDM.locationCache[dd]){
54530 delete Roo.dd.DDM.locationCache[dd];
54533 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54536 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54537 this.bind(null, null);
54538 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54541 handleLockChange : function(){
54542 this.refresh(true);
54545 onDenyColumnLock : function(){
54549 onDenyColumnHide : function(){
54553 handleHdMenuClick : function(item){
54554 var index = this.hdCtxIndex;
54555 var cm = this.cm, ds = this.ds;
54558 ds.sort(cm.getDataIndex(index), "ASC");
54561 ds.sort(cm.getDataIndex(index), "DESC");
54564 var lc = cm.getLockedCount();
54565 if(cm.getColumnCount(true) <= lc+1){
54566 this.onDenyColumnLock();
54570 cm.setLocked(index, true, true);
54571 cm.moveColumn(index, lc);
54572 this.grid.fireEvent("columnmove", index, lc);
54574 cm.setLocked(index, true);
54578 var lc = cm.getLockedCount();
54579 if((lc-1) != index){
54580 cm.setLocked(index, false, true);
54581 cm.moveColumn(index, lc-1);
54582 this.grid.fireEvent("columnmove", index, lc-1);
54584 cm.setLocked(index, false);
54587 case 'wider': // used to expand cols on touch..
54589 var cw = cm.getColumnWidth(index);
54590 cw += (item.id == 'wider' ? 1 : -1) * 50;
54591 cw = Math.max(0, cw);
54592 cw = Math.min(cw,4000);
54593 cm.setColumnWidth(index, cw);
54597 index = cm.getIndexById(item.id.substr(4));
54599 if(item.checked && cm.getColumnCount(true) <= 1){
54600 this.onDenyColumnHide();
54603 cm.setHidden(index, item.checked);
54609 beforeColMenuShow : function(){
54610 var cm = this.cm, colCount = cm.getColumnCount();
54611 this.colMenu.removeAll();
54612 for(var i = 0; i < colCount; i++){
54613 this.colMenu.add(new Roo.menu.CheckItem({
54614 id: "col-"+cm.getColumnId(i),
54615 text: cm.getColumnHeader(i),
54616 checked: !cm.isHidden(i),
54622 handleHdCtx : function(g, index, e){
54624 var hd = this.getHeaderCell(index);
54625 this.hdCtxIndex = index;
54626 var ms = this.hmenu.items, cm = this.cm;
54627 ms.get("asc").setDisabled(!cm.isSortable(index));
54628 ms.get("desc").setDisabled(!cm.isSortable(index));
54629 if(this.grid.enableColLock !== false){
54630 ms.get("lock").setDisabled(cm.isLocked(index));
54631 ms.get("unlock").setDisabled(!cm.isLocked(index));
54633 this.hmenu.show(hd, "tl-bl");
54636 handleHdOver : function(e){
54637 var hd = this.findHeaderCell(e.getTarget());
54638 if(hd && !this.headersDisabled){
54639 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54640 this.fly(hd).addClass("x-grid-hd-over");
54645 handleHdOut : function(e){
54646 var hd = this.findHeaderCell(e.getTarget());
54648 this.fly(hd).removeClass("x-grid-hd-over");
54652 handleSplitDblClick : function(e, t){
54653 var i = this.getCellIndex(t);
54654 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54655 this.autoSizeColumn(i, true);
54660 render : function(){
54663 var colCount = cm.getColumnCount();
54665 if(this.grid.monitorWindowResize === true){
54666 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54668 var header = this.renderHeaders();
54669 var body = this.templates.body.apply({rows:""});
54670 var html = this.templates.master.apply({
54673 lockedHeader: header[0],
54677 //this.updateColumns();
54679 this.grid.getGridEl().dom.innerHTML = html;
54681 this.initElements();
54683 // a kludge to fix the random scolling effect in webkit
54684 this.el.on("scroll", function() {
54685 this.el.dom.scrollTop=0; // hopefully not recursive..
54688 this.scroller.on("scroll", this.handleScroll, this);
54689 this.lockedBody.on("mousewheel", this.handleWheel, this);
54690 this.mainBody.on("mousewheel", this.handleWheel, this);
54692 this.mainHd.on("mouseover", this.handleHdOver, this);
54693 this.mainHd.on("mouseout", this.handleHdOut, this);
54694 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54695 {delegate: "."+this.splitClass});
54697 this.lockedHd.on("mouseover", this.handleHdOver, this);
54698 this.lockedHd.on("mouseout", this.handleHdOut, this);
54699 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54700 {delegate: "."+this.splitClass});
54702 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54703 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54706 this.updateSplitters();
54708 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54709 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54710 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54713 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54714 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54716 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54717 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54719 if(this.grid.enableColLock !== false){
54720 this.hmenu.add('-',
54721 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54722 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54726 this.hmenu.add('-',
54727 {id:"wider", text: this.columnsWiderText},
54728 {id:"narrow", text: this.columnsNarrowText }
54734 if(this.grid.enableColumnHide !== false){
54736 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54737 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54738 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54740 this.hmenu.add('-',
54741 {id:"columns", text: this.columnsText, menu: this.colMenu}
54744 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54746 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54749 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54750 this.dd = new Roo.grid.GridDragZone(this.grid, {
54751 ddGroup : this.grid.ddGroup || 'GridDD'
54757 for(var i = 0; i < colCount; i++){
54758 if(cm.isHidden(i)){
54759 this.hideColumn(i);
54761 if(cm.config[i].align){
54762 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54763 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54767 this.updateHeaderSortState();
54769 this.beforeInitialResize();
54772 // two part rendering gives faster view to the user
54773 this.renderPhase2.defer(1, this);
54776 renderPhase2 : function(){
54777 // render the rows now
54779 if(this.grid.autoSizeColumns){
54780 this.autoSizeColumns();
54784 beforeInitialResize : function(){
54788 onColumnSplitterMoved : function(i, w){
54789 this.userResized = true;
54790 var cm = this.grid.colModel;
54791 cm.setColumnWidth(i, w, true);
54792 var cid = cm.getColumnId(i);
54793 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54794 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54795 this.updateSplitters();
54797 this.grid.fireEvent("columnresize", i, w);
54800 syncRowHeights : function(startIndex, endIndex){
54801 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54802 startIndex = startIndex || 0;
54803 var mrows = this.getBodyTable().rows;
54804 var lrows = this.getLockedTable().rows;
54805 var len = mrows.length-1;
54806 endIndex = Math.min(endIndex || len, len);
54807 for(var i = startIndex; i <= endIndex; i++){
54808 var m = mrows[i], l = lrows[i];
54809 var h = Math.max(m.offsetHeight, l.offsetHeight);
54810 m.style.height = l.style.height = h + "px";
54815 layout : function(initialRender, is2ndPass){
54817 var auto = g.autoHeight;
54818 var scrollOffset = 16;
54819 var c = g.getGridEl(), cm = this.cm,
54820 expandCol = g.autoExpandColumn,
54822 //c.beginMeasure();
54824 if(!c.dom.offsetWidth){ // display:none?
54826 this.lockedWrap.show();
54827 this.mainWrap.show();
54832 var hasLock = this.cm.isLocked(0);
54834 var tbh = this.headerPanel.getHeight();
54835 var bbh = this.footerPanel.getHeight();
54838 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54839 var newHeight = ch + c.getBorderWidth("tb");
54841 newHeight = Math.min(g.maxHeight, newHeight);
54843 c.setHeight(newHeight);
54847 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54850 var s = this.scroller;
54852 var csize = c.getSize(true);
54854 this.el.setSize(csize.width, csize.height);
54856 this.headerPanel.setWidth(csize.width);
54857 this.footerPanel.setWidth(csize.width);
54859 var hdHeight = this.mainHd.getHeight();
54860 var vw = csize.width;
54861 var vh = csize.height - (tbh + bbh);
54865 var bt = this.getBodyTable();
54866 var ltWidth = hasLock ?
54867 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54869 var scrollHeight = bt.offsetHeight;
54870 var scrollWidth = ltWidth + bt.offsetWidth;
54871 var vscroll = false, hscroll = false;
54873 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54875 var lw = this.lockedWrap, mw = this.mainWrap;
54876 var lb = this.lockedBody, mb = this.mainBody;
54878 setTimeout(function(){
54879 var t = s.dom.offsetTop;
54880 var w = s.dom.clientWidth,
54881 h = s.dom.clientHeight;
54884 lw.setSize(ltWidth, h);
54886 mw.setLeftTop(ltWidth, t);
54887 mw.setSize(w-ltWidth, h);
54889 lb.setHeight(h-hdHeight);
54890 mb.setHeight(h-hdHeight);
54892 if(is2ndPass !== true && !gv.userResized && expandCol){
54893 // high speed resize without full column calculation
54895 var ci = cm.getIndexById(expandCol);
54897 ci = cm.findColumnIndex(expandCol);
54899 ci = Math.max(0, ci); // make sure it's got at least the first col.
54900 var expandId = cm.getColumnId(ci);
54901 var tw = cm.getTotalWidth(false);
54902 var currentWidth = cm.getColumnWidth(ci);
54903 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54904 if(currentWidth != cw){
54905 cm.setColumnWidth(ci, cw, true);
54906 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54907 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54908 gv.updateSplitters();
54909 gv.layout(false, true);
54921 onWindowResize : function(){
54922 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54928 appendFooter : function(parentEl){
54932 sortAscText : "Sort Ascending",
54933 sortDescText : "Sort Descending",
54934 lockText : "Lock Column",
54935 unlockText : "Unlock Column",
54936 columnsText : "Columns",
54938 columnsWiderText : "Wider",
54939 columnsNarrowText : "Thinner"
54943 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54944 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54945 this.proxy.el.addClass('x-grid3-col-dd');
54948 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54949 handleMouseDown : function(e){
54953 callHandleMouseDown : function(e){
54954 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54959 * Ext JS Library 1.1.1
54960 * Copyright(c) 2006-2007, Ext JS, LLC.
54962 * Originally Released Under LGPL - original licence link has changed is not relivant.
54965 * <script type="text/javascript">
54969 // This is a support class used internally by the Grid components
54970 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54972 this.view = grid.getView();
54973 this.proxy = this.view.resizeProxy;
54974 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54975 "gridSplitters" + this.grid.getGridEl().id, {
54976 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54978 this.setHandleElId(Roo.id(hd));
54979 this.setOuterHandleElId(Roo.id(hd2));
54980 this.scroll = false;
54982 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54983 fly: Roo.Element.fly,
54985 b4StartDrag : function(x, y){
54986 this.view.headersDisabled = true;
54987 this.proxy.setHeight(this.view.mainWrap.getHeight());
54988 var w = this.cm.getColumnWidth(this.cellIndex);
54989 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54990 this.resetConstraints();
54991 this.setXConstraint(minw, 1000);
54992 this.setYConstraint(0, 0);
54993 this.minX = x - minw;
54994 this.maxX = x + 1000;
54996 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55000 handleMouseDown : function(e){
55001 ev = Roo.EventObject.setEvent(e);
55002 var t = this.fly(ev.getTarget());
55003 if(t.hasClass("x-grid-split")){
55004 this.cellIndex = this.view.getCellIndex(t.dom);
55005 this.split = t.dom;
55006 this.cm = this.grid.colModel;
55007 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55008 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55013 endDrag : function(e){
55014 this.view.headersDisabled = false;
55015 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55016 var diff = endX - this.startPos;
55017 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55020 autoOffset : function(){
55021 this.setDelta(0,0);
55025 * Ext JS Library 1.1.1
55026 * Copyright(c) 2006-2007, Ext JS, LLC.
55028 * Originally Released Under LGPL - original licence link has changed is not relivant.
55031 * <script type="text/javascript">
55035 // This is a support class used internally by the Grid components
55036 Roo.grid.GridDragZone = function(grid, config){
55037 this.view = grid.getView();
55038 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55039 if(this.view.lockedBody){
55040 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55041 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55043 this.scroll = false;
55045 this.ddel = document.createElement('div');
55046 this.ddel.className = 'x-grid-dd-wrap';
55049 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55050 ddGroup : "GridDD",
55052 getDragData : function(e){
55053 var t = Roo.lib.Event.getTarget(e);
55054 var rowIndex = this.view.findRowIndex(t);
55055 var sm = this.grid.selModel;
55057 //Roo.log(rowIndex);
55059 if (sm.getSelectedCell) {
55060 // cell selection..
55061 if (!sm.getSelectedCell()) {
55064 if (rowIndex != sm.getSelectedCell()[0]) {
55070 if(rowIndex !== false){
55075 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55077 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55080 if (e.hasModifier()){
55081 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55084 Roo.log("getDragData");
55089 rowIndex: rowIndex,
55090 selections:sm.getSelections ? sm.getSelections() : (
55091 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55098 onInitDrag : function(e){
55099 var data = this.dragData;
55100 this.ddel.innerHTML = this.grid.getDragDropText();
55101 this.proxy.update(this.ddel);
55102 // fire start drag?
55105 afterRepair : function(){
55106 this.dragging = false;
55109 getRepairXY : function(e, data){
55113 onEndDrag : function(data, e){
55117 onValidDrop : function(dd, e, id){
55122 beforeInvalidDrop : function(e, id){
55127 * Ext JS Library 1.1.1
55128 * Copyright(c) 2006-2007, Ext JS, LLC.
55130 * Originally Released Under LGPL - original licence link has changed is not relivant.
55133 * <script type="text/javascript">
55138 * @class Roo.grid.ColumnModel
55139 * @extends Roo.util.Observable
55140 * This is the default implementation of a ColumnModel used by the Grid. It defines
55141 * the columns in the grid.
55144 var colModel = new Roo.grid.ColumnModel([
55145 {header: "Ticker", width: 60, sortable: true, locked: true},
55146 {header: "Company Name", width: 150, sortable: true},
55147 {header: "Market Cap.", width: 100, sortable: true},
55148 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55149 {header: "Employees", width: 100, sortable: true, resizable: false}
55154 * The config options listed for this class are options which may appear in each
55155 * individual column definition.
55156 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55158 * @param {Object} config An Array of column config objects. See this class's
55159 * config objects for details.
55161 Roo.grid.ColumnModel = function(config){
55163 * The config passed into the constructor
55165 this.config = config;
55168 // if no id, create one
55169 // if the column does not have a dataIndex mapping,
55170 // map it to the order it is in the config
55171 for(var i = 0, len = config.length; i < len; i++){
55173 if(typeof c.dataIndex == "undefined"){
55176 if(typeof c.renderer == "string"){
55177 c.renderer = Roo.util.Format[c.renderer];
55179 if(typeof c.id == "undefined"){
55182 if(c.editor && c.editor.xtype){
55183 c.editor = Roo.factory(c.editor, Roo.grid);
55185 if(c.editor && c.editor.isFormField){
55186 c.editor = new Roo.grid.GridEditor(c.editor);
55188 this.lookup[c.id] = c;
55192 * The width of columns which have no width specified (defaults to 100)
55195 this.defaultWidth = 100;
55198 * Default sortable of columns which have no sortable specified (defaults to false)
55201 this.defaultSortable = false;
55205 * @event widthchange
55206 * Fires when the width of a column changes.
55207 * @param {ColumnModel} this
55208 * @param {Number} columnIndex The column index
55209 * @param {Number} newWidth The new width
55211 "widthchange": true,
55213 * @event headerchange
55214 * Fires when the text of a header changes.
55215 * @param {ColumnModel} this
55216 * @param {Number} columnIndex The column index
55217 * @param {Number} newText The new header text
55219 "headerchange": true,
55221 * @event hiddenchange
55222 * Fires when a column is hidden or "unhidden".
55223 * @param {ColumnModel} this
55224 * @param {Number} columnIndex The column index
55225 * @param {Boolean} hidden true if hidden, false otherwise
55227 "hiddenchange": true,
55229 * @event columnmoved
55230 * Fires when a column is moved.
55231 * @param {ColumnModel} this
55232 * @param {Number} oldIndex
55233 * @param {Number} newIndex
55235 "columnmoved" : true,
55237 * @event columlockchange
55238 * Fires when a column's locked state is changed
55239 * @param {ColumnModel} this
55240 * @param {Number} colIndex
55241 * @param {Boolean} locked true if locked
55243 "columnlockchange" : true
55245 Roo.grid.ColumnModel.superclass.constructor.call(this);
55247 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55249 * @cfg {String} header The header text to display in the Grid view.
55252 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55253 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55254 * specified, the column's index is used as an index into the Record's data Array.
55257 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55258 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55261 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55262 * Defaults to the value of the {@link #defaultSortable} property.
55263 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55266 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55269 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55272 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55275 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55278 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55279 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55280 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55281 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55284 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55287 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55290 * @cfg {String} cursor (Optional)
55293 * @cfg {String} tooltip (Optional)
55296 * Returns the id of the column at the specified index.
55297 * @param {Number} index The column index
55298 * @return {String} the id
55300 getColumnId : function(index){
55301 return this.config[index].id;
55305 * Returns the column for a specified id.
55306 * @param {String} id The column id
55307 * @return {Object} the column
55309 getColumnById : function(id){
55310 return this.lookup[id];
55315 * Returns the column for a specified dataIndex.
55316 * @param {String} dataIndex The column dataIndex
55317 * @return {Object|Boolean} the column or false if not found
55319 getColumnByDataIndex: function(dataIndex){
55320 var index = this.findColumnIndex(dataIndex);
55321 return index > -1 ? this.config[index] : false;
55325 * Returns the index for a specified column id.
55326 * @param {String} id The column id
55327 * @return {Number} the index, or -1 if not found
55329 getIndexById : function(id){
55330 for(var i = 0, len = this.config.length; i < len; i++){
55331 if(this.config[i].id == id){
55339 * Returns the index for a specified column dataIndex.
55340 * @param {String} dataIndex The column dataIndex
55341 * @return {Number} the index, or -1 if not found
55344 findColumnIndex : function(dataIndex){
55345 for(var i = 0, len = this.config.length; i < len; i++){
55346 if(this.config[i].dataIndex == dataIndex){
55354 moveColumn : function(oldIndex, newIndex){
55355 var c = this.config[oldIndex];
55356 this.config.splice(oldIndex, 1);
55357 this.config.splice(newIndex, 0, c);
55358 this.dataMap = null;
55359 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55362 isLocked : function(colIndex){
55363 return this.config[colIndex].locked === true;
55366 setLocked : function(colIndex, value, suppressEvent){
55367 if(this.isLocked(colIndex) == value){
55370 this.config[colIndex].locked = value;
55371 if(!suppressEvent){
55372 this.fireEvent("columnlockchange", this, colIndex, value);
55376 getTotalLockedWidth : function(){
55377 var totalWidth = 0;
55378 for(var i = 0; i < this.config.length; i++){
55379 if(this.isLocked(i) && !this.isHidden(i)){
55380 this.totalWidth += this.getColumnWidth(i);
55386 getLockedCount : function(){
55387 for(var i = 0, len = this.config.length; i < len; i++){
55388 if(!this.isLocked(i)){
55395 * Returns the number of columns.
55398 getColumnCount : function(visibleOnly){
55399 if(visibleOnly === true){
55401 for(var i = 0, len = this.config.length; i < len; i++){
55402 if(!this.isHidden(i)){
55408 return this.config.length;
55412 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55413 * @param {Function} fn
55414 * @param {Object} scope (optional)
55415 * @return {Array} result
55417 getColumnsBy : function(fn, scope){
55419 for(var i = 0, len = this.config.length; i < len; i++){
55420 var c = this.config[i];
55421 if(fn.call(scope||this, c, i) === true){
55429 * Returns true if the specified column is sortable.
55430 * @param {Number} col The column index
55431 * @return {Boolean}
55433 isSortable : function(col){
55434 if(typeof this.config[col].sortable == "undefined"){
55435 return this.defaultSortable;
55437 return this.config[col].sortable;
55441 * Returns the rendering (formatting) function defined for the column.
55442 * @param {Number} col The column index.
55443 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55445 getRenderer : function(col){
55446 if(!this.config[col].renderer){
55447 return Roo.grid.ColumnModel.defaultRenderer;
55449 return this.config[col].renderer;
55453 * Sets the rendering (formatting) function for a column.
55454 * @param {Number} col The column index
55455 * @param {Function} fn The function to use to process the cell's raw data
55456 * to return HTML markup for the grid view. The render function is called with
55457 * the following parameters:<ul>
55458 * <li>Data value.</li>
55459 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55460 * <li>css A CSS style string to apply to the table cell.</li>
55461 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55462 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55463 * <li>Row index</li>
55464 * <li>Column index</li>
55465 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55467 setRenderer : function(col, fn){
55468 this.config[col].renderer = fn;
55472 * Returns the width for the specified column.
55473 * @param {Number} col The column index
55476 getColumnWidth : function(col){
55477 return this.config[col].width * 1 || this.defaultWidth;
55481 * Sets the width for a column.
55482 * @param {Number} col The column index
55483 * @param {Number} width The new width
55485 setColumnWidth : function(col, width, suppressEvent){
55486 this.config[col].width = width;
55487 this.totalWidth = null;
55488 if(!suppressEvent){
55489 this.fireEvent("widthchange", this, col, width);
55494 * Returns the total width of all columns.
55495 * @param {Boolean} includeHidden True to include hidden column widths
55498 getTotalWidth : function(includeHidden){
55499 if(!this.totalWidth){
55500 this.totalWidth = 0;
55501 for(var i = 0, len = this.config.length; i < len; i++){
55502 if(includeHidden || !this.isHidden(i)){
55503 this.totalWidth += this.getColumnWidth(i);
55507 return this.totalWidth;
55511 * Returns the header for the specified column.
55512 * @param {Number} col The column index
55515 getColumnHeader : function(col){
55516 return this.config[col].header;
55520 * Sets the header for a column.
55521 * @param {Number} col The column index
55522 * @param {String} header The new header
55524 setColumnHeader : function(col, header){
55525 this.config[col].header = header;
55526 this.fireEvent("headerchange", this, col, header);
55530 * Returns the tooltip for the specified column.
55531 * @param {Number} col The column index
55534 getColumnTooltip : function(col){
55535 return this.config[col].tooltip;
55538 * Sets the tooltip for a column.
55539 * @param {Number} col The column index
55540 * @param {String} tooltip The new tooltip
55542 setColumnTooltip : function(col, tooltip){
55543 this.config[col].tooltip = tooltip;
55547 * Returns the dataIndex for the specified column.
55548 * @param {Number} col The column index
55551 getDataIndex : function(col){
55552 return this.config[col].dataIndex;
55556 * Sets the dataIndex for a column.
55557 * @param {Number} col The column index
55558 * @param {Number} dataIndex The new dataIndex
55560 setDataIndex : function(col, dataIndex){
55561 this.config[col].dataIndex = dataIndex;
55567 * Returns true if the cell is editable.
55568 * @param {Number} colIndex The column index
55569 * @param {Number} rowIndex The row index
55570 * @return {Boolean}
55572 isCellEditable : function(colIndex, rowIndex){
55573 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55577 * Returns the editor defined for the cell/column.
55578 * return false or null to disable editing.
55579 * @param {Number} colIndex The column index
55580 * @param {Number} rowIndex The row index
55583 getCellEditor : function(colIndex, rowIndex){
55584 return this.config[colIndex].editor;
55588 * Sets if a column is editable.
55589 * @param {Number} col The column index
55590 * @param {Boolean} editable True if the column is editable
55592 setEditable : function(col, editable){
55593 this.config[col].editable = editable;
55598 * Returns true if the column is hidden.
55599 * @param {Number} colIndex The column index
55600 * @return {Boolean}
55602 isHidden : function(colIndex){
55603 return this.config[colIndex].hidden;
55608 * Returns true if the column width cannot be changed
55610 isFixed : function(colIndex){
55611 return this.config[colIndex].fixed;
55615 * Returns true if the column can be resized
55616 * @return {Boolean}
55618 isResizable : function(colIndex){
55619 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55622 * Sets if a column is hidden.
55623 * @param {Number} colIndex The column index
55624 * @param {Boolean} hidden True if the column is hidden
55626 setHidden : function(colIndex, hidden){
55627 this.config[colIndex].hidden = hidden;
55628 this.totalWidth = null;
55629 this.fireEvent("hiddenchange", this, colIndex, hidden);
55633 * Sets the editor for a column.
55634 * @param {Number} col The column index
55635 * @param {Object} editor The editor object
55637 setEditor : function(col, editor){
55638 this.config[col].editor = editor;
55642 Roo.grid.ColumnModel.defaultRenderer = function(value){
55643 if(typeof value == "string" && value.length < 1){
55649 // Alias for backwards compatibility
55650 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55653 * Ext JS Library 1.1.1
55654 * Copyright(c) 2006-2007, Ext JS, LLC.
55656 * Originally Released Under LGPL - original licence link has changed is not relivant.
55659 * <script type="text/javascript">
55663 * @class Roo.grid.AbstractSelectionModel
55664 * @extends Roo.util.Observable
55665 * Abstract base class for grid SelectionModels. It provides the interface that should be
55666 * implemented by descendant classes. This class should not be directly instantiated.
55669 Roo.grid.AbstractSelectionModel = function(){
55670 this.locked = false;
55671 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55674 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55675 /** @ignore Called by the grid automatically. Do not call directly. */
55676 init : function(grid){
55682 * Locks the selections.
55685 this.locked = true;
55689 * Unlocks the selections.
55691 unlock : function(){
55692 this.locked = false;
55696 * Returns true if the selections are locked.
55697 * @return {Boolean}
55699 isLocked : function(){
55700 return this.locked;
55704 * Ext JS Library 1.1.1
55705 * Copyright(c) 2006-2007, Ext JS, LLC.
55707 * Originally Released Under LGPL - original licence link has changed is not relivant.
55710 * <script type="text/javascript">
55713 * @extends Roo.grid.AbstractSelectionModel
55714 * @class Roo.grid.RowSelectionModel
55715 * The default SelectionModel used by {@link Roo.grid.Grid}.
55716 * It supports multiple selections and keyboard selection/navigation.
55718 * @param {Object} config
55720 Roo.grid.RowSelectionModel = function(config){
55721 Roo.apply(this, config);
55722 this.selections = new Roo.util.MixedCollection(false, function(o){
55727 this.lastActive = false;
55731 * @event selectionchange
55732 * Fires when the selection changes
55733 * @param {SelectionModel} this
55735 "selectionchange" : true,
55737 * @event afterselectionchange
55738 * Fires after the selection changes (eg. by key press or clicking)
55739 * @param {SelectionModel} this
55741 "afterselectionchange" : true,
55743 * @event beforerowselect
55744 * Fires when a row is selected being selected, return false to cancel.
55745 * @param {SelectionModel} this
55746 * @param {Number} rowIndex The selected index
55747 * @param {Boolean} keepExisting False if other selections will be cleared
55749 "beforerowselect" : true,
55752 * Fires when a row is selected.
55753 * @param {SelectionModel} this
55754 * @param {Number} rowIndex The selected index
55755 * @param {Roo.data.Record} r The record
55757 "rowselect" : true,
55759 * @event rowdeselect
55760 * Fires when a row is deselected.
55761 * @param {SelectionModel} this
55762 * @param {Number} rowIndex The selected index
55764 "rowdeselect" : true
55766 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55767 this.locked = false;
55770 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55772 * @cfg {Boolean} singleSelect
55773 * True to allow selection of only one row at a time (defaults to false)
55775 singleSelect : false,
55778 initEvents : function(){
55780 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55781 this.grid.on("mousedown", this.handleMouseDown, this);
55782 }else{ // allow click to work like normal
55783 this.grid.on("rowclick", this.handleDragableRowClick, this);
55786 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55787 "up" : function(e){
55789 this.selectPrevious(e.shiftKey);
55790 }else if(this.last !== false && this.lastActive !== false){
55791 var last = this.last;
55792 this.selectRange(this.last, this.lastActive-1);
55793 this.grid.getView().focusRow(this.lastActive);
55794 if(last !== false){
55798 this.selectFirstRow();
55800 this.fireEvent("afterselectionchange", this);
55802 "down" : function(e){
55804 this.selectNext(e.shiftKey);
55805 }else if(this.last !== false && this.lastActive !== false){
55806 var last = this.last;
55807 this.selectRange(this.last, this.lastActive+1);
55808 this.grid.getView().focusRow(this.lastActive);
55809 if(last !== false){
55813 this.selectFirstRow();
55815 this.fireEvent("afterselectionchange", this);
55820 var view = this.grid.view;
55821 view.on("refresh", this.onRefresh, this);
55822 view.on("rowupdated", this.onRowUpdated, this);
55823 view.on("rowremoved", this.onRemove, this);
55827 onRefresh : function(){
55828 var ds = this.grid.dataSource, i, v = this.grid.view;
55829 var s = this.selections;
55830 s.each(function(r){
55831 if((i = ds.indexOfId(r.id)) != -1){
55840 onRemove : function(v, index, r){
55841 this.selections.remove(r);
55845 onRowUpdated : function(v, index, r){
55846 if(this.isSelected(r)){
55847 v.onRowSelect(index);
55853 * @param {Array} records The records to select
55854 * @param {Boolean} keepExisting (optional) True to keep existing selections
55856 selectRecords : function(records, keepExisting){
55858 this.clearSelections();
55860 var ds = this.grid.dataSource;
55861 for(var i = 0, len = records.length; i < len; i++){
55862 this.selectRow(ds.indexOf(records[i]), true);
55867 * Gets the number of selected rows.
55870 getCount : function(){
55871 return this.selections.length;
55875 * Selects the first row in the grid.
55877 selectFirstRow : function(){
55882 * Select the last row.
55883 * @param {Boolean} keepExisting (optional) True to keep existing selections
55885 selectLastRow : function(keepExisting){
55886 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55890 * Selects the row immediately following the last selected row.
55891 * @param {Boolean} keepExisting (optional) True to keep existing selections
55893 selectNext : function(keepExisting){
55894 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55895 this.selectRow(this.last+1, keepExisting);
55896 this.grid.getView().focusRow(this.last);
55901 * Selects the row that precedes the last selected row.
55902 * @param {Boolean} keepExisting (optional) True to keep existing selections
55904 selectPrevious : function(keepExisting){
55906 this.selectRow(this.last-1, keepExisting);
55907 this.grid.getView().focusRow(this.last);
55912 * Returns the selected records
55913 * @return {Array} Array of selected records
55915 getSelections : function(){
55916 return [].concat(this.selections.items);
55920 * Returns the first selected record.
55923 getSelected : function(){
55924 return this.selections.itemAt(0);
55929 * Clears all selections.
55931 clearSelections : function(fast){
55932 if(this.locked) return;
55934 var ds = this.grid.dataSource;
55935 var s = this.selections;
55936 s.each(function(r){
55937 this.deselectRow(ds.indexOfId(r.id));
55941 this.selections.clear();
55948 * Selects all rows.
55950 selectAll : function(){
55951 if(this.locked) return;
55952 this.selections.clear();
55953 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55954 this.selectRow(i, true);
55959 * Returns True if there is a selection.
55960 * @return {Boolean}
55962 hasSelection : function(){
55963 return this.selections.length > 0;
55967 * Returns True if the specified row is selected.
55968 * @param {Number/Record} record The record or index of the record to check
55969 * @return {Boolean}
55971 isSelected : function(index){
55972 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55973 return (r && this.selections.key(r.id) ? true : false);
55977 * Returns True if the specified record id is selected.
55978 * @param {String} id The id of record to check
55979 * @return {Boolean}
55981 isIdSelected : function(id){
55982 return (this.selections.key(id) ? true : false);
55986 handleMouseDown : function(e, t){
55987 var view = this.grid.getView(), rowIndex;
55988 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55991 if(e.shiftKey && this.last !== false){
55992 var last = this.last;
55993 this.selectRange(last, rowIndex, e.ctrlKey);
55994 this.last = last; // reset the last
55995 view.focusRow(rowIndex);
55997 var isSelected = this.isSelected(rowIndex);
55998 if(e.button !== 0 && isSelected){
55999 view.focusRow(rowIndex);
56000 }else if(e.ctrlKey && isSelected){
56001 this.deselectRow(rowIndex);
56002 }else if(!isSelected){
56003 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56004 view.focusRow(rowIndex);
56007 this.fireEvent("afterselectionchange", this);
56010 handleDragableRowClick : function(grid, rowIndex, e)
56012 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56013 this.selectRow(rowIndex, false);
56014 grid.view.focusRow(rowIndex);
56015 this.fireEvent("afterselectionchange", this);
56020 * Selects multiple rows.
56021 * @param {Array} rows Array of the indexes of the row to select
56022 * @param {Boolean} keepExisting (optional) True to keep existing selections
56024 selectRows : function(rows, keepExisting){
56026 this.clearSelections();
56028 for(var i = 0, len = rows.length; i < len; i++){
56029 this.selectRow(rows[i], true);
56034 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56035 * @param {Number} startRow The index of the first row in the range
56036 * @param {Number} endRow The index of the last row in the range
56037 * @param {Boolean} keepExisting (optional) True to retain existing selections
56039 selectRange : function(startRow, endRow, keepExisting){
56040 if(this.locked) return;
56042 this.clearSelections();
56044 if(startRow <= endRow){
56045 for(var i = startRow; i <= endRow; i++){
56046 this.selectRow(i, true);
56049 for(var i = startRow; i >= endRow; i--){
56050 this.selectRow(i, true);
56056 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56057 * @param {Number} startRow The index of the first row in the range
56058 * @param {Number} endRow The index of the last row in the range
56060 deselectRange : function(startRow, endRow, preventViewNotify){
56061 if(this.locked) return;
56062 for(var i = startRow; i <= endRow; i++){
56063 this.deselectRow(i, preventViewNotify);
56069 * @param {Number} row The index of the row to select
56070 * @param {Boolean} keepExisting (optional) True to keep existing selections
56072 selectRow : function(index, keepExisting, preventViewNotify){
56073 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56074 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56075 if(!keepExisting || this.singleSelect){
56076 this.clearSelections();
56078 var r = this.grid.dataSource.getAt(index);
56079 this.selections.add(r);
56080 this.last = this.lastActive = index;
56081 if(!preventViewNotify){
56082 this.grid.getView().onRowSelect(index);
56084 this.fireEvent("rowselect", this, index, r);
56085 this.fireEvent("selectionchange", this);
56091 * @param {Number} row The index of the row to deselect
56093 deselectRow : function(index, preventViewNotify){
56094 if(this.locked) return;
56095 if(this.last == index){
56098 if(this.lastActive == index){
56099 this.lastActive = false;
56101 var r = this.grid.dataSource.getAt(index);
56102 this.selections.remove(r);
56103 if(!preventViewNotify){
56104 this.grid.getView().onRowDeselect(index);
56106 this.fireEvent("rowdeselect", this, index);
56107 this.fireEvent("selectionchange", this);
56111 restoreLast : function(){
56113 this.last = this._last;
56118 acceptsNav : function(row, col, cm){
56119 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56123 onEditorKey : function(field, e){
56124 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56129 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56131 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56133 }else if(k == e.ENTER && !e.ctrlKey){
56137 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56139 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56141 }else if(k == e.ESC){
56145 g.startEditing(newCell[0], newCell[1]);
56150 * Ext JS Library 1.1.1
56151 * Copyright(c) 2006-2007, Ext JS, LLC.
56153 * Originally Released Under LGPL - original licence link has changed is not relivant.
56156 * <script type="text/javascript">
56159 * @class Roo.grid.CellSelectionModel
56160 * @extends Roo.grid.AbstractSelectionModel
56161 * This class provides the basic implementation for cell selection in a grid.
56163 * @param {Object} config The object containing the configuration of this model.
56164 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56166 Roo.grid.CellSelectionModel = function(config){
56167 Roo.apply(this, config);
56169 this.selection = null;
56173 * @event beforerowselect
56174 * Fires before a cell is selected.
56175 * @param {SelectionModel} this
56176 * @param {Number} rowIndex The selected row index
56177 * @param {Number} colIndex The selected cell index
56179 "beforecellselect" : true,
56181 * @event cellselect
56182 * Fires when a cell is selected.
56183 * @param {SelectionModel} this
56184 * @param {Number} rowIndex The selected row index
56185 * @param {Number} colIndex The selected cell index
56187 "cellselect" : true,
56189 * @event selectionchange
56190 * Fires when the active selection changes.
56191 * @param {SelectionModel} this
56192 * @param {Object} selection null for no selection or an object (o) with two properties
56194 <li>o.record: the record object for the row the selection is in</li>
56195 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56198 "selectionchange" : true,
56201 * Fires when the tab (or enter) was pressed on the last editable cell
56202 * You can use this to trigger add new row.
56203 * @param {SelectionModel} this
56207 * @event beforeeditnext
56208 * Fires before the next editable sell is made active
56209 * You can use this to skip to another cell or fire the tabend
56210 * if you set cell to false
56211 * @param {Object} eventdata object : { cell : [ row, col ] }
56213 "beforeeditnext" : true
56215 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56218 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56220 enter_is_tab: false,
56223 initEvents : function(){
56224 this.grid.on("mousedown", this.handleMouseDown, this);
56225 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56226 var view = this.grid.view;
56227 view.on("refresh", this.onViewChange, this);
56228 view.on("rowupdated", this.onRowUpdated, this);
56229 view.on("beforerowremoved", this.clearSelections, this);
56230 view.on("beforerowsinserted", this.clearSelections, this);
56231 if(this.grid.isEditor){
56232 this.grid.on("beforeedit", this.beforeEdit, this);
56237 beforeEdit : function(e){
56238 this.select(e.row, e.column, false, true, e.record);
56242 onRowUpdated : function(v, index, r){
56243 if(this.selection && this.selection.record == r){
56244 v.onCellSelect(index, this.selection.cell[1]);
56249 onViewChange : function(){
56250 this.clearSelections(true);
56254 * Returns the currently selected cell,.
56255 * @return {Array} The selected cell (row, column) or null if none selected.
56257 getSelectedCell : function(){
56258 return this.selection ? this.selection.cell : null;
56262 * Clears all selections.
56263 * @param {Boolean} true to prevent the gridview from being notified about the change.
56265 clearSelections : function(preventNotify){
56266 var s = this.selection;
56268 if(preventNotify !== true){
56269 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56271 this.selection = null;
56272 this.fireEvent("selectionchange", this, null);
56277 * Returns true if there is a selection.
56278 * @return {Boolean}
56280 hasSelection : function(){
56281 return this.selection ? true : false;
56285 handleMouseDown : function(e, t){
56286 var v = this.grid.getView();
56287 if(this.isLocked()){
56290 var row = v.findRowIndex(t);
56291 var cell = v.findCellIndex(t);
56292 if(row !== false && cell !== false){
56293 this.select(row, cell);
56299 * @param {Number} rowIndex
56300 * @param {Number} collIndex
56302 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56303 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56304 this.clearSelections();
56305 r = r || this.grid.dataSource.getAt(rowIndex);
56308 cell : [rowIndex, colIndex]
56310 if(!preventViewNotify){
56311 var v = this.grid.getView();
56312 v.onCellSelect(rowIndex, colIndex);
56313 if(preventFocus !== true){
56314 v.focusCell(rowIndex, colIndex);
56317 this.fireEvent("cellselect", this, rowIndex, colIndex);
56318 this.fireEvent("selectionchange", this, this.selection);
56323 isSelectable : function(rowIndex, colIndex, cm){
56324 return !cm.isHidden(colIndex);
56328 handleKeyDown : function(e){
56329 //Roo.log('Cell Sel Model handleKeyDown');
56330 if(!e.isNavKeyPress()){
56333 var g = this.grid, s = this.selection;
56336 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56338 this.select(cell[0], cell[1]);
56343 var walk = function(row, col, step){
56344 return g.walkCells(row, col, step, sm.isSelectable, sm);
56346 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56353 // handled by onEditorKey
56354 if (g.isEditor && g.editing) {
56358 newCell = walk(r, c-1, -1);
56360 newCell = walk(r, c+1, 1);
56365 newCell = walk(r+1, c, 1);
56369 newCell = walk(r-1, c, -1);
56373 newCell = walk(r, c+1, 1);
56377 newCell = walk(r, c-1, -1);
56382 if(g.isEditor && !g.editing){
56383 g.startEditing(r, c);
56392 this.select(newCell[0], newCell[1]);
56398 acceptsNav : function(row, col, cm){
56399 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56403 * @param {Number} field (not used) - as it's normally used as a listener
56404 * @param {Number} e - event - fake it by using
56406 * var e = Roo.EventObjectImpl.prototype;
56407 * e.keyCode = e.TAB
56411 onEditorKey : function(field, e){
56413 var k = e.getKey(),
56416 ed = g.activeEditor,
56418 ///Roo.log('onEditorKey' + k);
56421 if (this.enter_is_tab && k == e.ENTER) {
56427 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56429 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56435 } else if(k == e.ENTER && !e.ctrlKey){
56438 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56440 } else if(k == e.ESC){
56445 var ecall = { cell : newCell, forward : forward };
56446 this.fireEvent('beforeeditnext', ecall );
56447 newCell = ecall.cell;
56448 forward = ecall.forward;
56452 //Roo.log('next cell after edit');
56453 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56454 } else if (forward) {
56455 // tabbed past last
56456 this.fireEvent.defer(100, this, ['tabend',this]);
56461 * Ext JS Library 1.1.1
56462 * Copyright(c) 2006-2007, Ext JS, LLC.
56464 * Originally Released Under LGPL - original licence link has changed is not relivant.
56467 * <script type="text/javascript">
56471 * @class Roo.grid.EditorGrid
56472 * @extends Roo.grid.Grid
56473 * Class for creating and editable grid.
56474 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56475 * The container MUST have some type of size defined for the grid to fill. The container will be
56476 * automatically set to position relative if it isn't already.
56477 * @param {Object} dataSource The data model to bind to
56478 * @param {Object} colModel The column model with info about this grid's columns
56480 Roo.grid.EditorGrid = function(container, config){
56481 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56482 this.getGridEl().addClass("xedit-grid");
56484 if(!this.selModel){
56485 this.selModel = new Roo.grid.CellSelectionModel();
56488 this.activeEditor = null;
56492 * @event beforeedit
56493 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56494 * <ul style="padding:5px;padding-left:16px;">
56495 * <li>grid - This grid</li>
56496 * <li>record - The record being edited</li>
56497 * <li>field - The field name being edited</li>
56498 * <li>value - The value for the field being edited.</li>
56499 * <li>row - The grid row index</li>
56500 * <li>column - The grid column index</li>
56501 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56503 * @param {Object} e An edit event (see above for description)
56505 "beforeedit" : true,
56508 * Fires after a cell is edited. <br />
56509 * <ul style="padding:5px;padding-left:16px;">
56510 * <li>grid - This grid</li>
56511 * <li>record - The record being edited</li>
56512 * <li>field - The field name being edited</li>
56513 * <li>value - The value being set</li>
56514 * <li>originalValue - The original value for the field, before the edit.</li>
56515 * <li>row - The grid row index</li>
56516 * <li>column - The grid column index</li>
56518 * @param {Object} e An edit event (see above for description)
56520 "afteredit" : true,
56522 * @event validateedit
56523 * Fires after a cell is edited, but before the value is set in the record.
56524 * You can use this to modify the value being set in the field, Return false
56525 * to cancel the change. The edit event object has the following properties <br />
56526 * <ul style="padding:5px;padding-left:16px;">
56527 * <li>editor - This editor</li>
56528 * <li>grid - This grid</li>
56529 * <li>record - The record being edited</li>
56530 * <li>field - The field name being edited</li>
56531 * <li>value - The value being set</li>
56532 * <li>originalValue - The original value for the field, before the edit.</li>
56533 * <li>row - The grid row index</li>
56534 * <li>column - The grid column index</li>
56535 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56537 * @param {Object} e An edit event (see above for description)
56539 "validateedit" : true
56541 this.on("bodyscroll", this.stopEditing, this);
56542 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56545 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56547 * @cfg {Number} clicksToEdit
56548 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56555 trackMouseOver: false, // causes very odd FF errors
56557 onCellDblClick : function(g, row, col){
56558 this.startEditing(row, col);
56561 onEditComplete : function(ed, value, startValue){
56562 this.editing = false;
56563 this.activeEditor = null;
56564 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56566 var field = this.colModel.getDataIndex(ed.col);
56571 originalValue: startValue,
56578 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56581 if(String(value) !== String(startValue)){
56583 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56584 r.set(field, e.value);
56585 // if we are dealing with a combo box..
56586 // then we also set the 'name' colum to be the displayField
56587 if (ed.field.displayField && ed.field.name) {
56588 r.set(ed.field.name, ed.field.el.dom.value);
56591 delete e.cancel; //?? why!!!
56592 this.fireEvent("afteredit", e);
56595 this.fireEvent("afteredit", e); // always fire it!
56597 this.view.focusCell(ed.row, ed.col);
56601 * Starts editing the specified for the specified row/column
56602 * @param {Number} rowIndex
56603 * @param {Number} colIndex
56605 startEditing : function(row, col){
56606 this.stopEditing();
56607 if(this.colModel.isCellEditable(col, row)){
56608 this.view.ensureVisible(row, col, true);
56610 var r = this.dataSource.getAt(row);
56611 var field = this.colModel.getDataIndex(col);
56612 var cell = Roo.get(this.view.getCell(row,col));
56617 value: r.data[field],
56622 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56623 this.editing = true;
56624 var ed = this.colModel.getCellEditor(col, row);
56630 ed.render(ed.parentEl || document.body);
56636 (function(){ // complex but required for focus issues in safari, ie and opera
56640 ed.on("complete", this.onEditComplete, this, {single: true});
56641 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56642 this.activeEditor = ed;
56643 var v = r.data[field];
56644 ed.startEdit(this.view.getCell(row, col), v);
56645 // combo's with 'displayField and name set
56646 if (ed.field.displayField && ed.field.name) {
56647 ed.field.el.dom.value = r.data[ed.field.name];
56651 }).defer(50, this);
56657 * Stops any active editing
56659 stopEditing : function(){
56660 if(this.activeEditor){
56661 this.activeEditor.completeEdit();
56663 this.activeEditor = null;
56667 * Called to get grid's drag proxy text, by default returns this.ddText.
56670 getDragDropText : function(){
56671 var count = this.selModel.getSelectedCell() ? 1 : 0;
56672 return String.format(this.ddText, count, count == 1 ? '' : 's');
56677 * Ext JS Library 1.1.1
56678 * Copyright(c) 2006-2007, Ext JS, LLC.
56680 * Originally Released Under LGPL - original licence link has changed is not relivant.
56683 * <script type="text/javascript">
56686 // private - not really -- you end up using it !
56687 // This is a support class used internally by the Grid components
56690 * @class Roo.grid.GridEditor
56691 * @extends Roo.Editor
56692 * Class for creating and editable grid elements.
56693 * @param {Object} config any settings (must include field)
56695 Roo.grid.GridEditor = function(field, config){
56696 if (!config && field.field) {
56698 field = Roo.factory(config.field, Roo.form);
56700 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56701 field.monitorTab = false;
56704 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56707 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56710 alignment: "tl-tl",
56713 cls: "x-small-editor x-grid-editor",
56718 * Ext JS Library 1.1.1
56719 * Copyright(c) 2006-2007, Ext JS, LLC.
56721 * Originally Released Under LGPL - original licence link has changed is not relivant.
56724 * <script type="text/javascript">
56729 Roo.grid.PropertyRecord = Roo.data.Record.create([
56730 {name:'name',type:'string'}, 'value'
56734 Roo.grid.PropertyStore = function(grid, source){
56736 this.store = new Roo.data.Store({
56737 recordType : Roo.grid.PropertyRecord
56739 this.store.on('update', this.onUpdate, this);
56741 this.setSource(source);
56743 Roo.grid.PropertyStore.superclass.constructor.call(this);
56748 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56749 setSource : function(o){
56751 this.store.removeAll();
56754 if(this.isEditableValue(o[k])){
56755 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56758 this.store.loadRecords({records: data}, {}, true);
56761 onUpdate : function(ds, record, type){
56762 if(type == Roo.data.Record.EDIT){
56763 var v = record.data['value'];
56764 var oldValue = record.modified['value'];
56765 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56766 this.source[record.id] = v;
56768 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56775 getProperty : function(row){
56776 return this.store.getAt(row);
56779 isEditableValue: function(val){
56780 if(val && val instanceof Date){
56782 }else if(typeof val == 'object' || typeof val == 'function'){
56788 setValue : function(prop, value){
56789 this.source[prop] = value;
56790 this.store.getById(prop).set('value', value);
56793 getSource : function(){
56794 return this.source;
56798 Roo.grid.PropertyColumnModel = function(grid, store){
56801 g.PropertyColumnModel.superclass.constructor.call(this, [
56802 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56803 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56805 this.store = store;
56806 this.bselect = Roo.DomHelper.append(document.body, {
56807 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56808 {tag: 'option', value: 'true', html: 'true'},
56809 {tag: 'option', value: 'false', html: 'false'}
56812 Roo.id(this.bselect);
56815 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56816 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56817 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56818 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56819 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56821 this.renderCellDelegate = this.renderCell.createDelegate(this);
56822 this.renderPropDelegate = this.renderProp.createDelegate(this);
56825 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56829 valueText : 'Value',
56831 dateFormat : 'm/j/Y',
56834 renderDate : function(dateVal){
56835 return dateVal.dateFormat(this.dateFormat);
56838 renderBool : function(bVal){
56839 return bVal ? 'true' : 'false';
56842 isCellEditable : function(colIndex, rowIndex){
56843 return colIndex == 1;
56846 getRenderer : function(col){
56848 this.renderCellDelegate : this.renderPropDelegate;
56851 renderProp : function(v){
56852 return this.getPropertyName(v);
56855 renderCell : function(val){
56857 if(val instanceof Date){
56858 rv = this.renderDate(val);
56859 }else if(typeof val == 'boolean'){
56860 rv = this.renderBool(val);
56862 return Roo.util.Format.htmlEncode(rv);
56865 getPropertyName : function(name){
56866 var pn = this.grid.propertyNames;
56867 return pn && pn[name] ? pn[name] : name;
56870 getCellEditor : function(colIndex, rowIndex){
56871 var p = this.store.getProperty(rowIndex);
56872 var n = p.data['name'], val = p.data['value'];
56874 if(typeof(this.grid.customEditors[n]) == 'string'){
56875 return this.editors[this.grid.customEditors[n]];
56877 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56878 return this.grid.customEditors[n];
56880 if(val instanceof Date){
56881 return this.editors['date'];
56882 }else if(typeof val == 'number'){
56883 return this.editors['number'];
56884 }else if(typeof val == 'boolean'){
56885 return this.editors['boolean'];
56887 return this.editors['string'];
56893 * @class Roo.grid.PropertyGrid
56894 * @extends Roo.grid.EditorGrid
56895 * This class represents the interface of a component based property grid control.
56896 * <br><br>Usage:<pre><code>
56897 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56905 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56906 * The container MUST have some type of size defined for the grid to fill. The container will be
56907 * automatically set to position relative if it isn't already.
56908 * @param {Object} config A config object that sets properties on this grid.
56910 Roo.grid.PropertyGrid = function(container, config){
56911 config = config || {};
56912 var store = new Roo.grid.PropertyStore(this);
56913 this.store = store;
56914 var cm = new Roo.grid.PropertyColumnModel(this, store);
56915 store.store.sort('name', 'ASC');
56916 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56919 enableColLock:false,
56920 enableColumnMove:false,
56922 trackMouseOver: false,
56925 this.getGridEl().addClass('x-props-grid');
56926 this.lastEditRow = null;
56927 this.on('columnresize', this.onColumnResize, this);
56930 * @event beforepropertychange
56931 * Fires before a property changes (return false to stop?)
56932 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56933 * @param {String} id Record Id
56934 * @param {String} newval New Value
56935 * @param {String} oldval Old Value
56937 "beforepropertychange": true,
56939 * @event propertychange
56940 * Fires after a property changes
56941 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56942 * @param {String} id Record Id
56943 * @param {String} newval New Value
56944 * @param {String} oldval Old Value
56946 "propertychange": true
56948 this.customEditors = this.customEditors || {};
56950 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56953 * @cfg {Object} customEditors map of colnames=> custom editors.
56954 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56955 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56956 * false disables editing of the field.
56960 * @cfg {Object} propertyNames map of property Names to their displayed value
56963 render : function(){
56964 Roo.grid.PropertyGrid.superclass.render.call(this);
56965 this.autoSize.defer(100, this);
56968 autoSize : function(){
56969 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56971 this.view.fitColumns();
56975 onColumnResize : function(){
56976 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56980 * Sets the data for the Grid
56981 * accepts a Key => Value object of all the elements avaiable.
56982 * @param {Object} data to appear in grid.
56984 setSource : function(source){
56985 this.store.setSource(source);
56989 * Gets all the data from the grid.
56990 * @return {Object} data data stored in grid
56992 getSource : function(){
56993 return this.store.getSource();
57002 * @class Roo.grid.Calendar
57003 * @extends Roo.util.Grid
57004 * This class extends the Grid to provide a calendar widget
57005 * <br><br>Usage:<pre><code>
57006 var grid = new Roo.grid.Calendar("my-container-id", {
57009 selModel: mySelectionModel,
57010 autoSizeColumns: true,
57011 monitorWindowResize: false,
57012 trackMouseOver: true
57013 eventstore : real data store..
57019 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57020 * The container MUST have some type of size defined for the grid to fill. The container will be
57021 * automatically set to position relative if it isn't already.
57022 * @param {Object} config A config object that sets properties on this grid.
57024 Roo.grid.Calendar = function(container, config){
57025 // initialize the container
57026 this.container = Roo.get(container);
57027 this.container.update("");
57028 this.container.setStyle("overflow", "hidden");
57029 this.container.addClass('x-grid-container');
57031 this.id = this.container.id;
57033 Roo.apply(this, config);
57034 // check and correct shorthanded configs
57038 for (var r = 0;r < 6;r++) {
57041 for (var c =0;c < 7;c++) {
57045 if (this.eventStore) {
57046 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57047 this.eventStore.on('load',this.onLoad, this);
57048 this.eventStore.on('beforeload',this.clearEvents, this);
57052 this.dataSource = new Roo.data.Store({
57053 proxy: new Roo.data.MemoryProxy(rows),
57054 reader: new Roo.data.ArrayReader({}, [
57055 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57058 this.dataSource.load();
57059 this.ds = this.dataSource;
57060 this.ds.xmodule = this.xmodule || false;
57063 var cellRender = function(v,x,r)
57065 return String.format(
57066 '<div class="fc-day fc-widget-content"><div>' +
57067 '<div class="fc-event-container"></div>' +
57068 '<div class="fc-day-number">{0}</div>'+
57070 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57071 '</div></div>', v);
57076 this.colModel = new Roo.grid.ColumnModel( [
57078 xtype: 'ColumnModel',
57080 dataIndex : 'weekday0',
57082 renderer : cellRender
57085 xtype: 'ColumnModel',
57087 dataIndex : 'weekday1',
57089 renderer : cellRender
57092 xtype: 'ColumnModel',
57094 dataIndex : 'weekday2',
57095 header : 'Tuesday',
57096 renderer : cellRender
57099 xtype: 'ColumnModel',
57101 dataIndex : 'weekday3',
57102 header : 'Wednesday',
57103 renderer : cellRender
57106 xtype: 'ColumnModel',
57108 dataIndex : 'weekday4',
57109 header : 'Thursday',
57110 renderer : cellRender
57113 xtype: 'ColumnModel',
57115 dataIndex : 'weekday5',
57117 renderer : cellRender
57120 xtype: 'ColumnModel',
57122 dataIndex : 'weekday6',
57123 header : 'Saturday',
57124 renderer : cellRender
57127 this.cm = this.colModel;
57128 this.cm.xmodule = this.xmodule || false;
57132 //this.selModel = new Roo.grid.CellSelectionModel();
57133 //this.sm = this.selModel;
57134 //this.selModel.init(this);
57138 this.container.setWidth(this.width);
57142 this.container.setHeight(this.height);
57149 * The raw click event for the entire grid.
57150 * @param {Roo.EventObject} e
57155 * The raw dblclick event for the entire grid.
57156 * @param {Roo.EventObject} e
57160 * @event contextmenu
57161 * The raw contextmenu event for the entire grid.
57162 * @param {Roo.EventObject} e
57164 "contextmenu" : true,
57167 * The raw mousedown event for the entire grid.
57168 * @param {Roo.EventObject} e
57170 "mousedown" : true,
57173 * The raw mouseup event for the entire grid.
57174 * @param {Roo.EventObject} e
57179 * The raw mouseover event for the entire grid.
57180 * @param {Roo.EventObject} e
57182 "mouseover" : true,
57185 * The raw mouseout event for the entire grid.
57186 * @param {Roo.EventObject} e
57191 * The raw keypress event for the entire grid.
57192 * @param {Roo.EventObject} e
57197 * The raw keydown event for the entire grid.
57198 * @param {Roo.EventObject} e
57206 * Fires when a cell is clicked
57207 * @param {Grid} this
57208 * @param {Number} rowIndex
57209 * @param {Number} columnIndex
57210 * @param {Roo.EventObject} e
57212 "cellclick" : true,
57214 * @event celldblclick
57215 * Fires when a cell is double clicked
57216 * @param {Grid} this
57217 * @param {Number} rowIndex
57218 * @param {Number} columnIndex
57219 * @param {Roo.EventObject} e
57221 "celldblclick" : true,
57224 * Fires when a row is clicked
57225 * @param {Grid} this
57226 * @param {Number} rowIndex
57227 * @param {Roo.EventObject} e
57231 * @event rowdblclick
57232 * Fires when a row is double clicked
57233 * @param {Grid} this
57234 * @param {Number} rowIndex
57235 * @param {Roo.EventObject} e
57237 "rowdblclick" : true,
57239 * @event headerclick
57240 * Fires when a header is clicked
57241 * @param {Grid} this
57242 * @param {Number} columnIndex
57243 * @param {Roo.EventObject} e
57245 "headerclick" : true,
57247 * @event headerdblclick
57248 * Fires when a header cell is double clicked
57249 * @param {Grid} this
57250 * @param {Number} columnIndex
57251 * @param {Roo.EventObject} e
57253 "headerdblclick" : true,
57255 * @event rowcontextmenu
57256 * Fires when a row is right clicked
57257 * @param {Grid} this
57258 * @param {Number} rowIndex
57259 * @param {Roo.EventObject} e
57261 "rowcontextmenu" : true,
57263 * @event cellcontextmenu
57264 * Fires when a cell is right clicked
57265 * @param {Grid} this
57266 * @param {Number} rowIndex
57267 * @param {Number} cellIndex
57268 * @param {Roo.EventObject} e
57270 "cellcontextmenu" : true,
57272 * @event headercontextmenu
57273 * Fires when a header is right clicked
57274 * @param {Grid} this
57275 * @param {Number} columnIndex
57276 * @param {Roo.EventObject} e
57278 "headercontextmenu" : true,
57280 * @event bodyscroll
57281 * Fires when the body element is scrolled
57282 * @param {Number} scrollLeft
57283 * @param {Number} scrollTop
57285 "bodyscroll" : true,
57287 * @event columnresize
57288 * Fires when the user resizes a column
57289 * @param {Number} columnIndex
57290 * @param {Number} newSize
57292 "columnresize" : true,
57294 * @event columnmove
57295 * Fires when the user moves a column
57296 * @param {Number} oldIndex
57297 * @param {Number} newIndex
57299 "columnmove" : true,
57302 * Fires when row(s) start being dragged
57303 * @param {Grid} this
57304 * @param {Roo.GridDD} dd The drag drop object
57305 * @param {event} e The raw browser event
57307 "startdrag" : true,
57310 * Fires when a drag operation is complete
57311 * @param {Grid} this
57312 * @param {Roo.GridDD} dd The drag drop object
57313 * @param {event} e The raw browser event
57318 * Fires when dragged row(s) are dropped on a valid DD target
57319 * @param {Grid} this
57320 * @param {Roo.GridDD} dd The drag drop object
57321 * @param {String} targetId The target drag drop object
57322 * @param {event} e The raw browser event
57327 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57328 * @param {Grid} this
57329 * @param {Roo.GridDD} dd The drag drop object
57330 * @param {String} targetId The target drag drop object
57331 * @param {event} e The raw browser event
57336 * Fires when the dragged row(s) first cross another DD target while being dragged
57337 * @param {Grid} this
57338 * @param {Roo.GridDD} dd The drag drop object
57339 * @param {String} targetId The target drag drop object
57340 * @param {event} e The raw browser event
57342 "dragenter" : true,
57345 * Fires when the dragged row(s) leave another DD target while being dragged
57346 * @param {Grid} this
57347 * @param {Roo.GridDD} dd The drag drop object
57348 * @param {String} targetId The target drag drop object
57349 * @param {event} e The raw browser event
57354 * Fires when a row is rendered, so you can change add a style to it.
57355 * @param {GridView} gridview The grid view
57356 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57362 * Fires when the grid is rendered
57363 * @param {Grid} grid
57368 * Fires when a date is selected
57369 * @param {DatePicker} this
57370 * @param {Date} date The selected date
57374 * @event monthchange
57375 * Fires when the displayed month changes
57376 * @param {DatePicker} this
57377 * @param {Date} date The selected month
57379 'monthchange': true,
57381 * @event evententer
57382 * Fires when mouse over an event
57383 * @param {Calendar} this
57384 * @param {event} Event
57386 'evententer': true,
57388 * @event eventleave
57389 * Fires when the mouse leaves an
57390 * @param {Calendar} this
57393 'eventleave': true,
57395 * @event eventclick
57396 * Fires when the mouse click an
57397 * @param {Calendar} this
57400 'eventclick': true,
57402 * @event eventrender
57403 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57404 * @param {Calendar} this
57405 * @param {data} data to be modified
57407 'eventrender': true
57411 Roo.grid.Grid.superclass.constructor.call(this);
57412 this.on('render', function() {
57413 this.view.el.addClass('x-grid-cal');
57415 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57419 if (!Roo.grid.Calendar.style) {
57420 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57423 '.x-grid-cal .x-grid-col' : {
57424 height: 'auto !important',
57425 'vertical-align': 'top'
57427 '.x-grid-cal .fc-event-hori' : {
57438 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57440 * @cfg {Store} eventStore The store that loads events.
57445 activeDate : false,
57448 monitorWindowResize : false,
57451 resizeColumns : function() {
57452 var col = (this.view.el.getWidth() / 7) - 3;
57453 // loop through cols, and setWidth
57454 for(var i =0 ; i < 7 ; i++){
57455 this.cm.setColumnWidth(i, col);
57458 setDate :function(date) {
57460 Roo.log('setDate?');
57462 this.resizeColumns();
57463 var vd = this.activeDate;
57464 this.activeDate = date;
57465 // if(vd && this.el){
57466 // var t = date.getTime();
57467 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57468 // Roo.log('using add remove');
57470 // this.fireEvent('monthchange', this, date);
57472 // this.cells.removeClass("fc-state-highlight");
57473 // this.cells.each(function(c){
57474 // if(c.dateValue == t){
57475 // c.addClass("fc-state-highlight");
57476 // setTimeout(function(){
57477 // try{c.dom.firstChild.focus();}catch(e){}
57487 var days = date.getDaysInMonth();
57489 var firstOfMonth = date.getFirstDateOfMonth();
57490 var startingPos = firstOfMonth.getDay()-this.startDay;
57492 if(startingPos < this.startDay){
57496 var pm = date.add(Date.MONTH, -1);
57497 var prevStart = pm.getDaysInMonth()-startingPos;
57501 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57503 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57504 //this.cells.addClassOnOver('fc-state-hover');
57506 var cells = this.cells.elements;
57507 var textEls = this.textNodes;
57509 //Roo.each(cells, function(cell){
57510 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57513 days += startingPos;
57515 // convert everything to numbers so it's fast
57516 var day = 86400000;
57517 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57520 //Roo.log(prevStart);
57522 var today = new Date().clearTime().getTime();
57523 var sel = date.clearTime().getTime();
57524 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57525 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57526 var ddMatch = this.disabledDatesRE;
57527 var ddText = this.disabledDatesText;
57528 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57529 var ddaysText = this.disabledDaysText;
57530 var format = this.format;
57532 var setCellClass = function(cal, cell){
57534 //Roo.log('set Cell Class');
57536 var t = d.getTime();
57541 cell.dateValue = t;
57543 cell.className += " fc-today";
57544 cell.className += " fc-state-highlight";
57545 cell.title = cal.todayText;
57548 // disable highlight in other month..
57549 cell.className += " fc-state-highlight";
57554 //cell.className = " fc-state-disabled";
57555 cell.title = cal.minText;
57559 //cell.className = " fc-state-disabled";
57560 cell.title = cal.maxText;
57564 if(ddays.indexOf(d.getDay()) != -1){
57565 // cell.title = ddaysText;
57566 // cell.className = " fc-state-disabled";
57569 if(ddMatch && format){
57570 var fvalue = d.dateFormat(format);
57571 if(ddMatch.test(fvalue)){
57572 cell.title = ddText.replace("%0", fvalue);
57573 cell.className = " fc-state-disabled";
57577 if (!cell.initialClassName) {
57578 cell.initialClassName = cell.dom.className;
57581 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57586 for(; i < startingPos; i++) {
57587 cells[i].dayName = (++prevStart);
57588 Roo.log(textEls[i]);
57589 d.setDate(d.getDate()+1);
57591 //cells[i].className = "fc-past fc-other-month";
57592 setCellClass(this, cells[i]);
57597 for(; i < days; i++){
57598 intDay = i - startingPos + 1;
57599 cells[i].dayName = (intDay);
57600 d.setDate(d.getDate()+1);
57602 cells[i].className = ''; // "x-date-active";
57603 setCellClass(this, cells[i]);
57607 for(; i < 42; i++) {
57608 //textEls[i].innerHTML = (++extraDays);
57610 d.setDate(d.getDate()+1);
57611 cells[i].dayName = (++extraDays);
57612 cells[i].className = "fc-future fc-other-month";
57613 setCellClass(this, cells[i]);
57616 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57618 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57620 // this will cause all the cells to mis
57623 for (var r = 0;r < 6;r++) {
57624 for (var c =0;c < 7;c++) {
57625 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57629 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57630 for(i=0;i<cells.length;i++) {
57632 this.cells.elements[i].dayName = cells[i].dayName ;
57633 this.cells.elements[i].className = cells[i].className;
57634 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57635 this.cells.elements[i].title = cells[i].title ;
57636 this.cells.elements[i].dateValue = cells[i].dateValue ;
57642 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57643 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57645 ////if(totalRows != 6){
57646 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57647 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57650 this.fireEvent('monthchange', this, date);
57655 * Returns the grid's SelectionModel.
57656 * @return {SelectionModel}
57658 getSelectionModel : function(){
57659 if(!this.selModel){
57660 this.selModel = new Roo.grid.CellSelectionModel();
57662 return this.selModel;
57666 this.eventStore.load()
57672 findCell : function(dt) {
57673 dt = dt.clearTime().getTime();
57675 this.cells.each(function(c){
57676 //Roo.log("check " +c.dateValue + '?=' + dt);
57677 if(c.dateValue == dt){
57687 findCells : function(rec) {
57688 var s = rec.data.start_dt.clone().clearTime().getTime();
57690 var e= rec.data.end_dt.clone().clearTime().getTime();
57693 this.cells.each(function(c){
57694 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57696 if(c.dateValue > e){
57699 if(c.dateValue < s){
57708 findBestRow: function(cells)
57712 for (var i =0 ; i < cells.length;i++) {
57713 ret = Math.max(cells[i].rows || 0,ret);
57720 addItem : function(rec)
57722 // look for vertical location slot in
57723 var cells = this.findCells(rec);
57725 rec.row = this.findBestRow(cells);
57727 // work out the location.
57731 for(var i =0; i < cells.length; i++) {
57739 if (crow.start.getY() == cells[i].getY()) {
57741 crow.end = cells[i];
57757 for (var i = 0; i < cells.length;i++) {
57758 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57765 clearEvents: function() {
57767 if (!this.eventStore.getCount()) {
57770 // reset number of rows in cells.
57771 Roo.each(this.cells.elements, function(c){
57775 this.eventStore.each(function(e) {
57776 this.clearEvent(e);
57781 clearEvent : function(ev)
57784 Roo.each(ev.els, function(el) {
57785 el.un('mouseenter' ,this.onEventEnter, this);
57786 el.un('mouseleave' ,this.onEventLeave, this);
57794 renderEvent : function(ev,ctr) {
57796 ctr = this.view.el.select('.fc-event-container',true).first();
57800 this.clearEvent(ev);
57806 var cells = ev.cells;
57807 var rows = ev.rows;
57808 this.fireEvent('eventrender', this, ev);
57810 for(var i =0; i < rows.length; i++) {
57814 cls += ' fc-event-start';
57816 if ((i+1) == rows.length) {
57817 cls += ' fc-event-end';
57820 //Roo.log(ev.data);
57821 // how many rows should it span..
57822 var cg = this.eventTmpl.append(ctr,Roo.apply({
57825 }, ev.data) , true);
57828 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57829 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57830 cg.on('click', this.onEventClick, this, ev);
57834 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57835 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57838 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57839 cg.setWidth(ebox.right - sbox.x -2);
57843 renderEvents: function()
57845 // first make sure there is enough space..
57847 if (!this.eventTmpl) {
57848 this.eventTmpl = new Roo.Template(
57849 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57850 '<div class="fc-event-inner">' +
57851 '<span class="fc-event-time">{time}</span>' +
57852 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57854 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57862 this.cells.each(function(c) {
57863 //Roo.log(c.select('.fc-day-content div',true).first());
57864 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57867 var ctr = this.view.el.select('.fc-event-container',true).first();
57870 this.eventStore.each(function(ev){
57872 this.renderEvent(ev);
57876 this.view.layout();
57880 onEventEnter: function (e, el,event,d) {
57881 this.fireEvent('evententer', this, el, event);
57884 onEventLeave: function (e, el,event,d) {
57885 this.fireEvent('eventleave', this, el, event);
57888 onEventClick: function (e, el,event,d) {
57889 this.fireEvent('eventclick', this, el, event);
57892 onMonthChange: function () {
57896 onLoad: function () {
57898 //Roo.log('calendar onload');
57900 if(this.eventStore.getCount() > 0){
57904 this.eventStore.each(function(d){
57909 if (typeof(add.end_dt) == 'undefined') {
57910 Roo.log("Missing End time in calendar data: ");
57914 if (typeof(add.start_dt) == 'undefined') {
57915 Roo.log("Missing Start time in calendar data: ");
57919 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57920 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57921 add.id = add.id || d.id;
57922 add.title = add.title || '??';
57930 this.renderEvents();
57940 render : function ()
57944 if (!this.view.el.hasClass('course-timesheet')) {
57945 this.view.el.addClass('course-timesheet');
57947 if (this.tsStyle) {
57952 Roo.log(_this.grid.view.el.getWidth());
57955 this.tsStyle = Roo.util.CSS.createStyleSheet({
57956 '.course-timesheet .x-grid-row' : {
57959 '.x-grid-row td' : {
57960 'vertical-align' : 0
57962 '.course-edit-link' : {
57964 'text-overflow' : 'ellipsis',
57965 'overflow' : 'hidden',
57966 'white-space' : 'nowrap',
57967 'cursor' : 'pointer'
57972 '.de-act-sup-link' : {
57973 'color' : 'purple',
57974 'text-decoration' : 'line-through'
57978 'text-decoration' : 'line-through'
57980 '.course-timesheet .course-highlight' : {
57981 'border-top-style': 'dashed !important',
57982 'border-bottom-bottom': 'dashed !important'
57984 '.course-timesheet .course-item' : {
57985 'font-family' : 'tahoma, arial, helvetica',
57986 'font-size' : '11px',
57987 'overflow' : 'hidden',
57988 'padding-left' : '10px',
57989 'padding-right' : '10px',
57990 'padding-top' : '10px'
57998 monitorWindowResize : false,
57999 cellrenderer : function(v,x,r)
58004 xtype: 'CellSelectionModel',
58011 beforeload : function (_self, options)
58013 options.params = options.params || {};
58014 options.params._month = _this.monthField.getValue();
58015 options.params.limit = 9999;
58016 options.params['sort'] = 'when_dt';
58017 options.params['dir'] = 'ASC';
58018 this.proxy.loadResponse = this.loadResponse;
58020 //this.addColumns();
58022 load : function (_self, records, options)
58024 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58025 // if you click on the translation.. you can edit it...
58026 var el = Roo.get(this);
58027 var id = el.dom.getAttribute('data-id');
58028 var d = el.dom.getAttribute('data-date');
58029 var t = el.dom.getAttribute('data-time');
58030 //var id = this.child('span').dom.textContent;
58033 Pman.Dialog.CourseCalendar.show({
58037 productitem_active : id ? 1 : 0
58039 _this.grid.ds.load({});
58044 _this.panel.fireEvent('resize', [ '', '' ]);
58047 loadResponse : function(o, success, response){
58048 // this is overridden on before load..
58050 Roo.log("our code?");
58051 //Roo.log(success);
58052 //Roo.log(response)
58053 delete this.activeRequest;
58055 this.fireEvent("loadexception", this, o, response);
58056 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58061 result = o.reader.read(response);
58063 Roo.log("load exception?");
58064 this.fireEvent("loadexception", this, o, response, e);
58065 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58068 Roo.log("ready...");
58069 // loop through result.records;
58070 // and set this.tdate[date] = [] << array of records..
58072 Roo.each(result.records, function(r){
58074 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58075 _this.tdata[r.data.when_dt.format('j')] = [];
58077 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58080 //Roo.log(_this.tdata);
58082 result.records = [];
58083 result.totalRecords = 6;
58085 // let's generate some duumy records for the rows.
58086 //var st = _this.dateField.getValue();
58088 // work out monday..
58089 //st = st.add(Date.DAY, -1 * st.format('w'));
58091 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58093 var firstOfMonth = date.getFirstDayOfMonth();
58094 var days = date.getDaysInMonth();
58096 var firstAdded = false;
58097 for (var i = 0; i < result.totalRecords ; i++) {
58098 //var d= st.add(Date.DAY, i);
58101 for(var w = 0 ; w < 7 ; w++){
58102 if(!firstAdded && firstOfMonth != w){
58109 var dd = (d > 0 && d < 10) ? "0"+d : d;
58110 row['weekday'+w] = String.format(
58111 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58112 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58114 date.format('Y-m-')+dd
58117 if(typeof(_this.tdata[d]) != 'undefined'){
58118 Roo.each(_this.tdata[d], function(r){
58122 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58123 if(r.parent_id*1>0){
58124 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58127 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58128 deactive = 'de-act-link';
58131 row['weekday'+w] += String.format(
58132 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58134 r.product_id_name, //1
58135 r.when_dt.format('h:ia'), //2
58145 // only do this if something added..
58147 result.records.push(_this.grid.dataSource.reader.newRow(row));
58151 // push it twice. (second one with an hour..
58155 this.fireEvent("load", this, o, o.request.arg);
58156 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58158 sortInfo : {field: 'when_dt', direction : 'ASC' },
58160 xtype: 'HttpProxy',
58163 url : baseURL + '/Roo/Shop_course.php'
58166 xtype: 'JsonReader',
58183 'name': 'parent_id',
58187 'name': 'product_id',
58191 'name': 'productitem_id',
58209 click : function (_self, e)
58211 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58212 sd.setMonth(sd.getMonth()-1);
58213 _this.monthField.setValue(sd.format('Y-m-d'));
58214 _this.grid.ds.load({});
58220 xtype: 'Separator',
58224 xtype: 'MonthField',
58227 render : function (_self)
58229 _this.monthField = _self;
58230 // _this.monthField.set today
58232 select : function (combo, date)
58234 _this.grid.ds.load({});
58237 value : (function() { return new Date(); })()
58240 xtype: 'Separator',
58246 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58256 click : function (_self, e)
58258 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58259 sd.setMonth(sd.getMonth()+1);
58260 _this.monthField.setValue(sd.format('Y-m-d'));
58261 _this.grid.ds.load({});
58274 * Ext JS Library 1.1.1
58275 * Copyright(c) 2006-2007, Ext JS, LLC.
58277 * Originally Released Under LGPL - original licence link has changed is not relivant.
58280 * <script type="text/javascript">
58284 * @class Roo.LoadMask
58285 * A simple utility class for generically masking elements while loading data. If the element being masked has
58286 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58287 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58288 * element's UpdateManager load indicator and will be destroyed after the initial load.
58290 * Create a new LoadMask
58291 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58292 * @param {Object} config The config object
58294 Roo.LoadMask = function(el, config){
58295 this.el = Roo.get(el);
58296 Roo.apply(this, config);
58298 this.store.on('beforeload', this.onBeforeLoad, this);
58299 this.store.on('load', this.onLoad, this);
58300 this.store.on('loadexception', this.onLoadException, this);
58301 this.removeMask = false;
58303 var um = this.el.getUpdateManager();
58304 um.showLoadIndicator = false; // disable the default indicator
58305 um.on('beforeupdate', this.onBeforeLoad, this);
58306 um.on('update', this.onLoad, this);
58307 um.on('failure', this.onLoad, this);
58308 this.removeMask = true;
58312 Roo.LoadMask.prototype = {
58314 * @cfg {Boolean} removeMask
58315 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58316 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58319 * @cfg {String} msg
58320 * The text to display in a centered loading message box (defaults to 'Loading...')
58322 msg : 'Loading...',
58324 * @cfg {String} msgCls
58325 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58327 msgCls : 'x-mask-loading',
58330 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58336 * Disables the mask to prevent it from being displayed
58338 disable : function(){
58339 this.disabled = true;
58343 * Enables the mask so that it can be displayed
58345 enable : function(){
58346 this.disabled = false;
58349 onLoadException : function()
58351 Roo.log(arguments);
58353 if (typeof(arguments[3]) != 'undefined') {
58354 Roo.MessageBox.alert("Error loading",arguments[3]);
58358 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58359 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58368 this.el.unmask(this.removeMask);
58371 onLoad : function()
58373 this.el.unmask(this.removeMask);
58377 onBeforeLoad : function(){
58378 if(!this.disabled){
58379 this.el.mask(this.msg, this.msgCls);
58384 destroy : function(){
58386 this.store.un('beforeload', this.onBeforeLoad, this);
58387 this.store.un('load', this.onLoad, this);
58388 this.store.un('loadexception', this.onLoadException, this);
58390 var um = this.el.getUpdateManager();
58391 um.un('beforeupdate', this.onBeforeLoad, this);
58392 um.un('update', this.onLoad, this);
58393 um.un('failure', this.onLoad, this);
58398 * Ext JS Library 1.1.1
58399 * Copyright(c) 2006-2007, Ext JS, LLC.
58401 * Originally Released Under LGPL - original licence link has changed is not relivant.
58404 * <script type="text/javascript">
58409 * @class Roo.XTemplate
58410 * @extends Roo.Template
58411 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58413 var t = new Roo.XTemplate(
58414 '<select name="{name}">',
58415 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58419 // then append, applying the master template values
58422 * Supported features:
58427 {a_variable} - output encoded.
58428 {a_variable.format:("Y-m-d")} - call a method on the variable
58429 {a_variable:raw} - unencoded output
58430 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58431 {a_variable:this.method_on_template(...)} - call a method on the template object.
58436 <tpl for="a_variable or condition.."></tpl>
58437 <tpl if="a_variable or condition"></tpl>
58438 <tpl exec="some javascript"></tpl>
58439 <tpl name="named_template"></tpl> (experimental)
58441 <tpl for="."></tpl> - just iterate the property..
58442 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58446 Roo.XTemplate = function()
58448 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58455 Roo.extend(Roo.XTemplate, Roo.Template, {
58458 * The various sub templates
58463 * basic tag replacing syntax
58466 * // you can fake an object call by doing this
58470 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58473 * compile the template
58475 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58478 compile: function()
58482 s = ['<tpl>', s, '</tpl>'].join('');
58484 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58485 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58486 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58487 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58488 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58493 while(true == !!(m = s.match(re))){
58494 var forMatch = m[0].match(nameRe),
58495 ifMatch = m[0].match(ifRe),
58496 execMatch = m[0].match(execRe),
58497 namedMatch = m[0].match(namedRe),
58502 name = forMatch && forMatch[1] ? forMatch[1] : '';
58505 // if - puts fn into test..
58506 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58508 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58513 // exec - calls a function... returns empty if true is returned.
58514 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58516 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58524 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58525 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58526 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58529 var uid = namedMatch ? namedMatch[1] : id;
58533 id: namedMatch ? namedMatch[1] : id,
58540 s = s.replace(m[0], '');
58542 s = s.replace(m[0], '{xtpl'+ id + '}');
58547 for(var i = tpls.length-1; i >= 0; --i){
58548 this.compileTpl(tpls[i]);
58549 this.tpls[tpls[i].id] = tpls[i];
58551 this.master = tpls[tpls.length-1];
58555 * same as applyTemplate, except it's done to one of the subTemplates
58556 * when using named templates, you can do:
58558 * var str = pl.applySubTemplate('your-name', values);
58561 * @param {Number} id of the template
58562 * @param {Object} values to apply to template
58563 * @param {Object} parent (normaly the instance of this object)
58565 applySubTemplate : function(id, values, parent)
58569 var t = this.tpls[id];
58573 if(t.test && !t.test.call(this, values, parent)){
58577 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58578 Roo.log(e.toString());
58584 if(t.exec && t.exec.call(this, values, parent)){
58588 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58589 Roo.log(e.toString());
58594 var vs = t.target ? t.target.call(this, values, parent) : values;
58595 parent = t.target ? values : parent;
58596 if(t.target && vs instanceof Array){
58598 for(var i = 0, len = vs.length; i < len; i++){
58599 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58601 return buf.join('');
58603 return t.compiled.call(this, vs, parent);
58605 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58606 Roo.log(e.toString());
58607 Roo.log(t.compiled);
58612 compileTpl : function(tpl)
58614 var fm = Roo.util.Format;
58615 var useF = this.disableFormats !== true;
58616 var sep = Roo.isGecko ? "+" : ",";
58617 var undef = function(str) {
58618 Roo.log("Property not found :" + str);
58622 var fn = function(m, name, format, args)
58624 //Roo.log(arguments);
58625 args = args ? args.replace(/\\'/g,"'") : args;
58626 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58627 if (typeof(format) == 'undefined') {
58628 format= 'htmlEncode';
58630 if (format == 'raw' ) {
58634 if(name.substr(0, 4) == 'xtpl'){
58635 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58638 // build an array of options to determine if value is undefined..
58640 // basically get 'xxxx.yyyy' then do
58641 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58642 // (function () { Roo.log("Property not found"); return ''; })() :
58647 Roo.each(name.split('.'), function(st) {
58648 lookfor += (lookfor.length ? '.': '') + st;
58649 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58652 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58655 if(format && useF){
58657 args = args ? ',' + args : "";
58659 if(format.substr(0, 5) != "this."){
58660 format = "fm." + format + '(';
58662 format = 'this.call("'+ format.substr(5) + '", ';
58666 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58670 // called with xxyx.yuu:(test,test)
58672 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58674 // raw.. - :raw modifier..
58675 return "'"+ sep + udef_st + name + ")"+sep+"'";
58679 // branched to use + in gecko and [].join() in others
58681 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58682 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58685 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58686 body.push(tpl.body.replace(/(\r\n|\n)/g,
58687 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58688 body.push("'].join('');};};");
58689 body = body.join('');
58692 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58694 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58700 applyTemplate : function(values){
58701 return this.master.compiled.call(this, values, {});
58702 //var s = this.subs;
58705 apply : function(){
58706 return this.applyTemplate.apply(this, arguments);
58711 Roo.XTemplate.from = function(el){
58712 el = Roo.getDom(el);
58713 return new Roo.XTemplate(el.value || el.innerHTML);