4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 Roo.log('extend!!!!');
213 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
216 sb = function(){sp.apply(this, arguments);};
218 var F = function(){}, sbp, spp = sp.prototype;
220 sbp = sb.prototype = new F();
224 if(spp.constructor == Object.prototype.constructor){
229 sb.override = function(o){
233 Roo.override(sb, overrides);
239 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
241 Roo.override(MyClass, {
242 newMethod1: function(){
245 newMethod2: function(foo){
250 * @param {Object} origclass The class to override
251 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
252 * containing one or more methods.
255 override : function(origclass, overrides){
257 var p = origclass.prototype;
258 for(var method in overrides){
259 p[method] = overrides[method];
264 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
266 Roo.namespace('Company', 'Company.data');
267 Company.Widget = function() { ... }
268 Company.data.CustomStore = function(config) { ... }
270 * @param {String} namespace1
271 * @param {String} namespace2
272 * @param {String} etc
275 namespace : function(){
276 var a=arguments, o=null, i, j, d, rt;
277 for (i=0; i<a.length; ++i) {
281 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
282 for (j=1; j<d.length; ++j) {
283 o[d[j]]=o[d[j]] || {};
289 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
291 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
292 Roo.factory(conf, Roo.data);
294 * @param {String} classname
295 * @param {String} namespace (optional)
299 factory : function(c, ns)
301 // no xtype, no ns or c.xns - or forced off by c.xns
302 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
305 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
306 if (c.constructor == ns[c.xtype]) {// already created...
310 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
311 var ret = new ns[c.xtype](c);
315 c.xns = false; // prevent recursion..
319 * Logs to console if it can.
321 * @param {String|Object} string
326 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
333 * 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.
337 urlEncode : function(o){
343 var ov = o[key], k = Roo.encodeURIComponent(key);
344 var type = typeof ov;
345 if(type == 'undefined'){
347 }else if(type != "function" && type != "object"){
348 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
349 }else if(ov instanceof Array){
351 for(var i = 0, len = ov.length; i < len; i++) {
352 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
363 * Safe version of encodeURIComponent
364 * @param {String} data
368 encodeURIComponent : function (data)
371 return encodeURIComponent(data);
372 } catch(e) {} // should be an uri encode error.
374 if (data == '' || data == null){
377 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
378 function nibble_to_hex(nibble){
379 var chars = '0123456789ABCDEF';
380 return chars.charAt(nibble);
382 data = data.toString();
384 for(var i=0; i<data.length; i++){
385 var c = data.charCodeAt(i);
386 var bs = new Array();
389 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
390 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
391 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
392 bs[3] = 0x80 | (c & 0x3F);
393 }else if (c > 0x800){
395 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
396 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
397 bs[2] = 0x80 | (c & 0x3F);
400 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
401 bs[1] = 0x80 | (c & 0x3F);
406 for(var j=0; j<bs.length; j++){
408 var hex = nibble_to_hex((b & 0xF0) >>> 4)
409 + nibble_to_hex(b &0x0F);
418 * 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]}.
419 * @param {String} string
420 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
421 * @return {Object} A literal with members
423 urlDecode : function(string, overwrite){
424 if(!string || !string.length){
428 var pairs = string.split('&');
429 var pair, name, value;
430 for(var i = 0, len = pairs.length; i < len; i++){
431 pair = pairs[i].split('=');
432 name = decodeURIComponent(pair[0]);
433 value = decodeURIComponent(pair[1]);
434 if(overwrite !== true){
435 if(typeof obj[name] == "undefined"){
437 }else if(typeof obj[name] == "string"){
438 obj[name] = [obj[name]];
439 obj[name].push(value);
441 obj[name].push(value);
451 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
452 * passed array is not really an array, your function is called once with it.
453 * The supplied function is called with (Object item, Number index, Array allItems).
454 * @param {Array/NodeList/Mixed} array
455 * @param {Function} fn
456 * @param {Object} scope
458 each : function(array, fn, scope){
459 if(typeof array.length == "undefined" || typeof array == "string"){
462 for(var i = 0, len = array.length; i < len; i++){
463 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
468 combine : function(){
469 var as = arguments, l = as.length, r = [];
470 for(var i = 0; i < l; i++){
472 if(a instanceof Array){
474 }else if(a.length !== undefined && !a.substr){
475 r = r.concat(Array.prototype.slice.call(a, 0));
484 * Escapes the passed string for use in a regular expression
485 * @param {String} str
488 escapeRe : function(s) {
489 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
493 callback : function(cb, scope, args, delay){
494 if(typeof cb == "function"){
496 cb.defer(delay, scope, args || []);
498 cb.apply(scope, args || []);
504 * Return the dom node for the passed string (id), dom node, or Roo.Element
505 * @param {String/HTMLElement/Roo.Element} el
506 * @return HTMLElement
508 getDom : function(el){
512 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
516 * Shorthand for {@link Roo.ComponentMgr#get}
518 * @return Roo.Component
520 getCmp : function(id){
521 return Roo.ComponentMgr.get(id);
524 num : function(v, defaultValue){
525 if(typeof v != 'number'){
531 destroy : function(){
532 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
536 as.removeAllListeners();
540 if(typeof as.purgeListeners == 'function'){
543 if(typeof as.destroy == 'function'){
550 // inpired by a similar function in mootools library
552 * Returns the type of object that is passed in. If the object passed in is null or undefined it
553 * return false otherwise it returns one of the following values:<ul>
554 * <li><b>string</b>: If the object passed is a string</li>
555 * <li><b>number</b>: If the object passed is a number</li>
556 * <li><b>boolean</b>: If the object passed is a boolean value</li>
557 * <li><b>function</b>: If the object passed is a function reference</li>
558 * <li><b>object</b>: If the object passed is an object</li>
559 * <li><b>array</b>: If the object passed is an array</li>
560 * <li><b>regexp</b>: If the object passed is a regular expression</li>
561 * <li><b>element</b>: If the object passed is a DOM Element</li>
562 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
563 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
564 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
565 * @param {Mixed} object
569 if(o === undefined || o === null){
576 if(t == 'object' && o.nodeName) {
578 case 1: return 'element';
579 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
582 if(t == 'object' || t == 'function') {
583 switch(o.constructor) {
584 case Array: return 'array';
585 case RegExp: return 'regexp';
587 if(typeof o.length == 'number' && typeof o.item == 'function') {
595 * Returns true if the passed value is null, undefined or an empty string (optional).
596 * @param {Mixed} value The value to test
597 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
600 isEmpty : function(v, allowBlank){
601 return v === null || v === undefined || (!allowBlank ? v === '' : false);
615 isBorderBox : isBorderBox,
617 isWindows : isWindows,
626 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
627 * you may want to set this to true.
630 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
635 * Selects a single element as a Roo Element
636 * This is about as close as you can get to jQuery's $('do crazy stuff')
637 * @param {String} selector The selector/xpath query
638 * @param {Node} root (optional) The start of the query (defaults to document).
639 * @return {Roo.Element}
641 selectNode : function(selector, root)
643 var node = Roo.DomQuery.selectNode(selector,root);
644 return node ? Roo.get(node) : new Roo.Element(false);
652 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
653 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
656 * Ext JS Library 1.1.1
657 * Copyright(c) 2006-2007, Ext JS, LLC.
659 * Originally Released Under LGPL - original licence link has changed is not relivant.
662 * <script type="text/javascript">
666 // wrappedn so fnCleanup is not in global scope...
668 function fnCleanUp() {
669 var p = Function.prototype;
670 delete p.createSequence;
672 delete p.createDelegate;
673 delete p.createCallback;
674 delete p.createInterceptor;
676 window.detachEvent("onunload", fnCleanUp);
678 window.attachEvent("onunload", fnCleanUp);
685 * These functions are available on every Function object (any JavaScript function).
687 Roo.apply(Function.prototype, {
689 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
690 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
691 * Will create a function that is bound to those 2 args.
692 * @return {Function} The new function
694 createCallback : function(/*args...*/){
695 // make args available, in function below
696 var args = arguments;
699 return method.apply(window, args);
704 * Creates a delegate (callback) that sets the scope to obj.
705 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
706 * Will create a function that is automatically scoped to this.
707 * @param {Object} obj (optional) The object for which the scope is set
708 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
709 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
710 * if a number the args are inserted at the specified position
711 * @return {Function} The new function
713 createDelegate : function(obj, args, appendArgs){
716 var callArgs = args || arguments;
717 if(appendArgs === true){
718 callArgs = Array.prototype.slice.call(arguments, 0);
719 callArgs = callArgs.concat(args);
720 }else if(typeof appendArgs == "number"){
721 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
722 var applyArgs = [appendArgs, 0].concat(args); // create method call params
723 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
725 return method.apply(obj || window, callArgs);
730 * Calls this function after the number of millseconds specified.
731 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
732 * @param {Object} obj (optional) The object for which the scope is set
733 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
734 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
735 * if a number the args are inserted at the specified position
736 * @return {Number} The timeout id that can be used with clearTimeout
738 defer : function(millis, obj, args, appendArgs){
739 var fn = this.createDelegate(obj, args, appendArgs);
741 return setTimeout(fn, millis);
747 * Create a combined function call sequence of the original function + the passed function.
748 * The resulting function returns the results of the original function.
749 * The passed fcn is called with the parameters of the original function
750 * @param {Function} fcn The function to sequence
751 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
752 * @return {Function} The new function
754 createSequence : function(fcn, scope){
755 if(typeof fcn != "function"){
760 var retval = method.apply(this || window, arguments);
761 fcn.apply(scope || this || window, arguments);
767 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
768 * The resulting function returns the results of the original function.
769 * The passed fcn is called with the parameters of the original function.
771 * @param {Function} fcn The function to call before the original
772 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
773 * @return {Function} The new function
775 createInterceptor : function(fcn, scope){
776 if(typeof fcn != "function"){
783 if(fcn.apply(scope || this || window, arguments) === false){
786 return method.apply(this || window, arguments);
792 * Ext JS Library 1.1.1
793 * Copyright(c) 2006-2007, Ext JS, LLC.
795 * Originally Released Under LGPL - original licence link has changed is not relivant.
798 * <script type="text/javascript">
801 Roo.applyIf(String, {
806 * Escapes the passed string for ' and \
807 * @param {String} string The string to escape
808 * @return {String} The escaped string
811 escape : function(string) {
812 return string.replace(/('|\\)/g, "\\$1");
816 * Pads the left side of a string with a specified character. This is especially useful
817 * for normalizing number and date strings. Example usage:
819 var s = String.leftPad('123', 5, '0');
820 // s now contains the string: '00123'
822 * @param {String} string The original string
823 * @param {Number} size The total length of the output string
824 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
825 * @return {String} The padded string
828 leftPad : function (val, size, ch) {
829 var result = new String(val);
830 if(ch === null || ch === undefined || ch === '') {
833 while (result.length < size) {
834 result = ch + result;
840 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
841 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
843 var cls = 'my-class', text = 'Some text';
844 var s = String.format('<div class="{0}">{1}</div>', cls, text);
845 // s now contains the string: '<div class="my-class">Some text</div>'
847 * @param {String} string The tokenized string to be formatted
848 * @param {String} value1 The value to replace token {0}
849 * @param {String} value2 Etc...
850 * @return {String} The formatted string
853 format : function(format){
854 var args = Array.prototype.slice.call(arguments, 1);
855 return format.replace(/\{(\d+)\}/g, function(m, i){
856 return Roo.util.Format.htmlEncode(args[i]);
862 * Utility function that allows you to easily switch a string between two alternating values. The passed value
863 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
864 * they are already different, the first value passed in is returned. Note that this method returns the new value
865 * but does not change the current string.
867 // alternate sort directions
868 sort = sort.toggle('ASC', 'DESC');
870 // instead of conditional logic:
871 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
873 * @param {String} value The value to compare to the current string
874 * @param {String} other The new value to use if the string already equals the first value passed in
875 * @return {String} The new value
878 String.prototype.toggle = function(value, other){
879 return this == value ? other : value;
882 * Ext JS Library 1.1.1
883 * Copyright(c) 2006-2007, Ext JS, LLC.
885 * Originally Released Under LGPL - original licence link has changed is not relivant.
888 * <script type="text/javascript">
894 Roo.applyIf(Number.prototype, {
896 * Checks whether or not the current number is within a desired range. If the number is already within the
897 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
898 * exceeded. Note that this method returns the constrained value but does not change the current number.
899 * @param {Number} min The minimum number in the range
900 * @param {Number} max The maximum number in the range
901 * @return {Number} The constrained value if outside the range, otherwise the current value
903 constrain : function(min, max){
904 return Math.min(Math.max(this, min), max);
908 * Ext JS Library 1.1.1
909 * Copyright(c) 2006-2007, Ext JS, LLC.
911 * Originally Released Under LGPL - original licence link has changed is not relivant.
914 * <script type="text/javascript">
919 Roo.applyIf(Array.prototype, {
921 * Checks whether or not the specified object exists in the array.
922 * @param {Object} o The object to check for
923 * @return {Number} The index of o in the array (or -1 if it is not found)
925 indexOf : function(o){
926 for (var i = 0, len = this.length; i < len; i++){
927 if(this[i] == o) return i;
933 * Removes the specified object from the array. If the object is not found nothing happens.
934 * @param {Object} o The object to remove
936 remove : function(o){
937 var index = this.indexOf(o);
939 this.splice(index, 1);
943 * Map (JS 1.6 compatibility)
944 * @param {Function} function to call
948 var len = this.length >>> 0;
949 if (typeof fun != "function")
950 throw new TypeError();
952 var res = new Array(len);
953 var thisp = arguments[1];
954 for (var i = 0; i < len; i++)
957 res[i] = fun.call(thisp, this[i], i, this);
968 * Ext JS Library 1.1.1
969 * Copyright(c) 2006-2007, Ext JS, LLC.
971 * Originally Released Under LGPL - original licence link has changed is not relivant.
974 * <script type="text/javascript">
980 * The date parsing and format syntax is a subset of
981 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
982 * supported will provide results equivalent to their PHP versions.
984 * Following is the list of all currently supported formats:
987 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
989 Format Output Description
990 ------ ---------- --------------------------------------------------------------
991 d 10 Day of the month, 2 digits with leading zeros
992 D Wed A textual representation of a day, three letters
993 j 10 Day of the month without leading zeros
994 l Wednesday A full textual representation of the day of the week
995 S th English ordinal day of month suffix, 2 chars (use with j)
996 w 3 Numeric representation of the day of the week
997 z 9 The julian date, or day of the year (0-365)
998 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
999 F January A full textual representation of the month
1000 m 01 Numeric representation of a month, with leading zeros
1001 M Jan Month name abbreviation, three letters
1002 n 1 Numeric representation of a month, without leading zeros
1003 t 31 Number of days in the given month
1004 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1005 Y 2007 A full numeric representation of a year, 4 digits
1006 y 07 A two digit representation of a year
1007 a pm Lowercase Ante meridiem and Post meridiem
1008 A PM Uppercase Ante meridiem and Post meridiem
1009 g 3 12-hour format of an hour without leading zeros
1010 G 15 24-hour format of an hour without leading zeros
1011 h 03 12-hour format of an hour with leading zeros
1012 H 15 24-hour format of an hour with leading zeros
1013 i 05 Minutes with leading zeros
1014 s 01 Seconds, with leading zeros
1015 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1016 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1017 T CST Timezone setting of the machine running the code
1018 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1021 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1023 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1024 document.write(dt.format('Y-m-d')); //2007-01-10
1025 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1026 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
1029 * Here are some standard date/time patterns that you might find helpful. They
1030 * are not part of the source of Date.js, but to use them you can simply copy this
1031 * block of code into any script that is included after Date.js and they will also become
1032 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1035 ISO8601Long:"Y-m-d H:i:s",
1036 ISO8601Short:"Y-m-d",
1038 LongDate: "l, F d, Y",
1039 FullDateTime: "l, F d, Y g:i:s A",
1042 LongTime: "g:i:s A",
1043 SortableDateTime: "Y-m-d\\TH:i:s",
1044 UniversalSortableDateTime: "Y-m-d H:i:sO",
1051 var dt = new Date();
1052 document.write(dt.format(Date.patterns.ShortDate));
1057 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1058 * They generate precompiled functions from date formats instead of parsing and
1059 * processing the pattern every time you format a date. These functions are available
1060 * on every Date object (any javascript function).
1062 * The original article and download are here:
1063 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1070 Returns the number of milliseconds between this date and date
1071 @param {Date} date (optional) Defaults to now
1072 @return {Number} The diff in milliseconds
1073 @member Date getElapsed
1075 Date.prototype.getElapsed = function(date) {
1076 return Math.abs((date || new Date()).getTime()-this.getTime());
1078 // was in date file..
1082 Date.parseFunctions = {count:0};
1084 Date.parseRegexes = [];
1086 Date.formatFunctions = {count:0};
1089 Date.prototype.dateFormat = function(format) {
1090 if (Date.formatFunctions[format] == null) {
1091 Date.createNewFormat(format);
1093 var func = Date.formatFunctions[format];
1094 return this[func]();
1099 * Formats a date given the supplied format string
1100 * @param {String} format The format string
1101 * @return {String} The formatted date
1104 Date.prototype.format = Date.prototype.dateFormat;
1107 Date.createNewFormat = function(format) {
1108 var funcName = "format" + Date.formatFunctions.count++;
1109 Date.formatFunctions[format] = funcName;
1110 var code = "Date.prototype." + funcName + " = function(){return ";
1111 var special = false;
1113 for (var i = 0; i < format.length; ++i) {
1114 ch = format.charAt(i);
1115 if (!special && ch == "\\") {
1120 code += "'" + String.escape(ch) + "' + ";
1123 code += Date.getFormatCode(ch);
1126 /** eval:var:zzzzzzzzzzzzz */
1127 eval(code.substring(0, code.length - 3) + ";}");
1131 Date.getFormatCode = function(character) {
1132 switch (character) {
1134 return "String.leftPad(this.getDate(), 2, '0') + ";
1136 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1138 return "this.getDate() + ";
1140 return "Date.dayNames[this.getDay()] + ";
1142 return "this.getSuffix() + ";
1144 return "this.getDay() + ";
1146 return "this.getDayOfYear() + ";
1148 return "this.getWeekOfYear() + ";
1150 return "Date.monthNames[this.getMonth()] + ";
1152 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1154 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1156 return "(this.getMonth() + 1) + ";
1158 return "this.getDaysInMonth() + ";
1160 return "(this.isLeapYear() ? 1 : 0) + ";
1162 return "this.getFullYear() + ";
1164 return "('' + this.getFullYear()).substring(2, 4) + ";
1166 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1168 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1170 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1172 return "this.getHours() + ";
1174 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1176 return "String.leftPad(this.getHours(), 2, '0') + ";
1178 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1180 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1182 return "this.getGMTOffset() + ";
1184 return "this.getGMTColonOffset() + ";
1186 return "this.getTimezone() + ";
1188 return "(this.getTimezoneOffset() * -60) + ";
1190 return "'" + String.escape(character) + "' + ";
1195 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1196 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1197 * the date format that is not specified will default to the current date value for that part. Time parts can also
1198 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1199 * string or the parse operation will fail.
1202 //dt = Fri May 25 2007 (current date)
1203 var dt = new Date();
1205 //dt = Thu May 25 2006 (today's month/day in 2006)
1206 dt = Date.parseDate("2006", "Y");
1208 //dt = Sun Jan 15 2006 (all date parts specified)
1209 dt = Date.parseDate("2006-1-15", "Y-m-d");
1211 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1212 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1214 * @param {String} input The unparsed date as a string
1215 * @param {String} format The format the date is in
1216 * @return {Date} The parsed date
1219 Date.parseDate = function(input, format) {
1220 if (Date.parseFunctions[format] == null) {
1221 Date.createParser(format);
1223 var func = Date.parseFunctions[format];
1224 return Date[func](input);
1229 Date.createParser = function(format) {
1230 var funcName = "parse" + Date.parseFunctions.count++;
1231 var regexNum = Date.parseRegexes.length;
1232 var currentGroup = 1;
1233 Date.parseFunctions[format] = funcName;
1235 var code = "Date." + funcName + " = function(input){\n"
1236 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1237 + "var d = new Date();\n"
1238 + "y = d.getFullYear();\n"
1239 + "m = d.getMonth();\n"
1240 + "d = d.getDate();\n"
1241 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1242 + "if (results && results.length > 0) {";
1245 var special = false;
1247 for (var i = 0; i < format.length; ++i) {
1248 ch = format.charAt(i);
1249 if (!special && ch == "\\") {
1254 regex += String.escape(ch);
1257 var obj = Date.formatCodeToRegex(ch, currentGroup);
1258 currentGroup += obj.g;
1260 if (obj.g && obj.c) {
1266 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1267 + "{v = new Date(y, m, d, h, i, s);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1269 + "{v = new Date(y, m, d, h, i);}\n"
1270 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1271 + "{v = new Date(y, m, d, h);}\n"
1272 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1273 + "{v = new Date(y, m, d);}\n"
1274 + "else if (y >= 0 && m >= 0)\n"
1275 + "{v = new Date(y, m);}\n"
1276 + "else if (y >= 0)\n"
1277 + "{v = new Date(y);}\n"
1278 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1279 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1280 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1283 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1284 /** eval:var:zzzzzzzzzzzzz */
1289 Date.formatCodeToRegex = function(character, currentGroup) {
1290 switch (character) {
1294 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{1,2})"}; // day of month without leading zeroes
1301 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1302 s:"(\\d{2})"}; // day of month with leading zeroes
1306 s:"(?:" + Date.dayNames.join("|") + ")"};
1310 s:"(?:st|nd|rd|th)"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1326 s:"(" + Date.monthNames.join("|") + ")"};
1329 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1330 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1337 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1338 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1349 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1353 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1354 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1358 c:"if (results[" + currentGroup + "] == 'am') {\n"
1359 + "if (h == 12) { h = 0; }\n"
1360 + "} else { if (h < 12) { h += 12; }}",
1364 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1365 + "if (h == 12) { h = 0; }\n"
1366 + "} else { if (h < 12) { h += 12; }}",
1371 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1372 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1376 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1377 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1380 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1384 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1389 "o = results[", currentGroup, "];\n",
1390 "var sn = o.substring(0,1);\n", // get + / - sign
1391 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1392 "var mn = o.substring(3,5) % 60;\n", // get minutes
1393 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1394 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1396 s:"([+\-]\\d{2,4})"};
1402 "o = results[", currentGroup, "];\n",
1403 "var sn = o.substring(0,1);\n",
1404 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1405 "var mn = o.substring(4,6) % 60;\n",
1406 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1407 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1413 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1416 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1417 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1418 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1422 s:String.escape(character)};
1427 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1428 * @return {String} The abbreviated timezone name (e.g. 'CST')
1430 Date.prototype.getTimezone = function() {
1431 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1435 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1436 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1438 Date.prototype.getGMTOffset = function() {
1439 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1440 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1441 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1445 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1446 * @return {String} 2-characters representing hours and 2-characters representing minutes
1447 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1449 Date.prototype.getGMTColonOffset = function() {
1450 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1451 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1453 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1457 * Get the numeric day number of the year, adjusted for leap year.
1458 * @return {Number} 0 through 364 (365 in leap years)
1460 Date.prototype.getDayOfYear = function() {
1462 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1463 for (var i = 0; i < this.getMonth(); ++i) {
1464 num += Date.daysInMonth[i];
1466 return num + this.getDate() - 1;
1470 * Get the string representation of the numeric week number of the year
1471 * (equivalent to the format specifier 'W').
1472 * @return {String} '00' through '52'
1474 Date.prototype.getWeekOfYear = function() {
1475 // Skip to Thursday of this week
1476 var now = this.getDayOfYear() + (4 - this.getDay());
1477 // Find the first Thursday of the year
1478 var jan1 = new Date(this.getFullYear(), 0, 1);
1479 var then = (7 - jan1.getDay() + 4);
1480 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1484 * Whether or not the current date is in a leap year.
1485 * @return {Boolean} True if the current date is in a leap year, else false
1487 Date.prototype.isLeapYear = function() {
1488 var year = this.getFullYear();
1489 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1493 * Get the first day of the current month, adjusted for leap year. The returned value
1494 * is the numeric day index within the week (0-6) which can be used in conjunction with
1495 * the {@link #monthNames} array to retrieve the textual day name.
1498 var dt = new Date('1/10/2007');
1499 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1501 * @return {Number} The day number (0-6)
1503 Date.prototype.getFirstDayOfMonth = function() {
1504 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1505 return (day < 0) ? (day + 7) : day;
1509 * Get the last day of the current month, adjusted for leap year. The returned value
1510 * is the numeric day index within the week (0-6) which can be used in conjunction with
1511 * the {@link #monthNames} array to retrieve the textual day name.
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1517 * @return {Number} The day number (0-6)
1519 Date.prototype.getLastDayOfMonth = function() {
1520 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1521 return (day < 0) ? (day + 7) : day;
1526 * Get the first date of this date's month
1529 Date.prototype.getFirstDateOfMonth = function() {
1530 return new Date(this.getFullYear(), this.getMonth(), 1);
1534 * Get the last date of this date's month
1537 Date.prototype.getLastDateOfMonth = function() {
1538 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1541 * Get the number of days in the current month, adjusted for leap year.
1542 * @return {Number} The number of days in the month
1544 Date.prototype.getDaysInMonth = function() {
1545 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1546 return Date.daysInMonth[this.getMonth()];
1550 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1551 * @return {String} 'st, 'nd', 'rd' or 'th'
1553 Date.prototype.getSuffix = function() {
1554 switch (this.getDate()) {
1571 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1574 * An array of textual month names.
1575 * Override these values for international dates, for example...
1576 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1595 * An array of textual day names.
1596 * Override these values for international dates, for example...
1597 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1613 Date.monthNumbers = {
1628 * Creates and returns a new Date instance with the exact same date value as the called instance.
1629 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1630 * variable will also be changed. When the intention is to create a new variable that will not
1631 * modify the original instance, you should create a clone.
1633 * Example of correctly cloning a date:
1636 var orig = new Date('10/1/2006');
1639 document.write(orig); //returns 'Thu Oct 05 2006'!
1642 var orig = new Date('10/1/2006');
1643 var copy = orig.clone();
1645 document.write(orig); //returns 'Thu Oct 01 2006'
1647 * @return {Date} The new Date instance
1649 Date.prototype.clone = function() {
1650 return new Date(this.getTime());
1654 * Clears any time information from this date
1655 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1656 @return {Date} this or the clone
1658 Date.prototype.clearTime = function(clone){
1660 return this.clone().clearTime();
1665 this.setMilliseconds(0);
1670 // safari setMonth is broken
1672 Date.brokenSetMonth = Date.prototype.setMonth;
1673 Date.prototype.setMonth = function(num){
1675 var n = Math.ceil(-num);
1676 var back_year = Math.ceil(n/12);
1677 var month = (n % 12) ? 12 - n % 12 : 0 ;
1678 this.setFullYear(this.getFullYear() - back_year);
1679 return Date.brokenSetMonth.call(this, month);
1681 return Date.brokenSetMonth.apply(this, arguments);
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1710 /** Date interval constant
1716 * Provides a convenient method of performing basic date arithmetic. This method
1717 * does not modify the Date instance being called - it creates and returns
1718 * a new Date instance containing the resulting date value.
1723 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1724 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1726 //Negative values will subtract correctly:
1727 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1728 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1730 //You can even chain several calls together in one line!
1731 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1732 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1735 * @param {String} interval A valid date interval enum value
1736 * @param {Number} value The amount to add to the current date
1737 * @return {Date} The new Date instance
1739 Date.prototype.add = function(interval, value){
1740 var d = this.clone();
1741 if (!interval || value === 0) return d;
1742 switch(interval.toLowerCase()){
1744 d.setMilliseconds(this.getMilliseconds() + value);
1747 d.setSeconds(this.getSeconds() + value);
1750 d.setMinutes(this.getMinutes() + value);
1753 d.setHours(this.getHours() + value);
1756 d.setDate(this.getDate() + value);
1759 var day = this.getDate();
1761 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1764 d.setMonth(this.getMonth() + value);
1767 d.setFullYear(this.getFullYear() + value);
1774 * Ext JS Library 1.1.1
1775 * Copyright(c) 2006-2007, Ext JS, LLC.
1777 * Originally Released Under LGPL - original licence link has changed is not relivant.
1780 * <script type="text/javascript">
1784 * @class Roo.lib.Dom
1787 * Dom utils (from YIU afaik)
1792 * Get the view width
1793 * @param {Boolean} full True will get the full document, otherwise it's the view width
1794 * @return {Number} The width
1797 getViewWidth : function(full) {
1798 return full ? this.getDocumentWidth() : this.getViewportWidth();
1801 * Get the view height
1802 * @param {Boolean} full True will get the full document, otherwise it's the view height
1803 * @return {Number} The height
1805 getViewHeight : function(full) {
1806 return full ? this.getDocumentHeight() : this.getViewportHeight();
1809 getDocumentHeight: function() {
1810 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1811 return Math.max(scrollHeight, this.getViewportHeight());
1814 getDocumentWidth: function() {
1815 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1816 return Math.max(scrollWidth, this.getViewportWidth());
1819 getViewportHeight: function() {
1820 var height = self.innerHeight;
1821 var mode = document.compatMode;
1823 if ((mode || Roo.isIE) && !Roo.isOpera) {
1824 height = (mode == "CSS1Compat") ?
1825 document.documentElement.clientHeight :
1826 document.body.clientHeight;
1832 getViewportWidth: function() {
1833 var width = self.innerWidth;
1834 var mode = document.compatMode;
1836 if (mode || Roo.isIE) {
1837 width = (mode == "CSS1Compat") ?
1838 document.documentElement.clientWidth :
1839 document.body.clientWidth;
1844 isAncestor : function(p, c) {
1851 if (p.contains && !Roo.isSafari) {
1852 return p.contains(c);
1853 } else if (p.compareDocumentPosition) {
1854 return !!(p.compareDocumentPosition(c) & 16);
1856 var parent = c.parentNode;
1861 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1864 parent = parent.parentNode;
1870 getRegion : function(el) {
1871 return Roo.lib.Region.getRegion(el);
1874 getY : function(el) {
1875 return this.getXY(el)[1];
1878 getX : function(el) {
1879 return this.getXY(el)[0];
1882 getXY : function(el) {
1883 var p, pe, b, scroll, bd = document.body;
1884 el = Roo.getDom(el);
1885 var fly = Roo.lib.AnimBase.fly;
1886 if (el.getBoundingClientRect) {
1887 b = el.getBoundingClientRect();
1888 scroll = fly(document).getScroll();
1889 return [b.left + scroll.left, b.top + scroll.top];
1895 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1902 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1909 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1910 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1917 if (p != el && pe.getStyle('overflow') != 'visible') {
1925 if (Roo.isSafari && hasAbsolute) {
1930 if (Roo.isGecko && !hasAbsolute) {
1932 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1933 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1937 while (p && p != bd) {
1938 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1950 setXY : function(el, xy) {
1951 el = Roo.fly(el, '_setXY');
1953 var pts = el.translatePoints(xy);
1954 if (xy[0] !== false) {
1955 el.dom.style.left = pts.left + "px";
1957 if (xy[1] !== false) {
1958 el.dom.style.top = pts.top + "px";
1962 setX : function(el, x) {
1963 this.setXY(el, [x, false]);
1966 setY : function(el, y) {
1967 this.setXY(el, [false, y]);
1971 * Portions of this file are based on pieces of Yahoo User Interface Library
1972 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1973 * YUI licensed under the BSD License:
1974 * http://developer.yahoo.net/yui/license.txt
1975 * <script type="text/javascript">
1979 Roo.lib.Event = function() {
1980 var loadComplete = false;
1982 var unloadListeners = [];
1984 var onAvailStack = [];
1986 var lastError = null;
1999 startInterval: function() {
2000 if (!this._interval) {
2002 var callback = function() {
2003 self._tryPreloadAttach();
2005 this._interval = setInterval(callback, this.POLL_INTERVAL);
2010 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2011 onAvailStack.push({ id: p_id,
2014 override: p_override,
2015 checkReady: false });
2017 retryCount = this.POLL_RETRYS;
2018 this.startInterval();
2022 addListener: function(el, eventName, fn) {
2023 el = Roo.getDom(el);
2028 if ("unload" == eventName) {
2029 unloadListeners[unloadListeners.length] =
2030 [el, eventName, fn];
2034 var wrappedFn = function(e) {
2035 return fn(Roo.lib.Event.getEvent(e));
2038 var li = [el, eventName, fn, wrappedFn];
2040 var index = listeners.length;
2041 listeners[index] = li;
2043 this.doAdd(el, eventName, wrappedFn, false);
2049 removeListener: function(el, eventName, fn) {
2052 el = Roo.getDom(el);
2055 return this.purgeElement(el, false, eventName);
2059 if ("unload" == eventName) {
2061 for (i = 0,len = unloadListeners.length; i < len; i++) {
2062 var li = unloadListeners[i];
2065 li[1] == eventName &&
2067 unloadListeners.splice(i, 1);
2075 var cacheItem = null;
2078 var index = arguments[3];
2080 if ("undefined" == typeof index) {
2081 index = this._getCacheIndex(el, eventName, fn);
2085 cacheItem = listeners[index];
2088 if (!el || !cacheItem) {
2092 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2094 delete listeners[index][this.WFN];
2095 delete listeners[index][this.FN];
2096 listeners.splice(index, 1);
2103 getTarget: function(ev, resolveTextNode) {
2104 ev = ev.browserEvent || ev;
2105 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2106 var t = ev.target || ev.srcElement;
2107 return this.resolveTextNode(t);
2111 resolveTextNode: function(node) {
2112 if (Roo.isSafari && node && 3 == node.nodeType) {
2113 return node.parentNode;
2120 getPageX: function(ev) {
2121 ev = ev.browserEvent || ev;
2122 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2124 if (!x && 0 !== x) {
2125 x = ev.clientX || 0;
2128 x += this.getScroll()[1];
2136 getPageY: function(ev) {
2137 ev = ev.browserEvent || ev;
2138 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2140 if (!y && 0 !== y) {
2141 y = ev.clientY || 0;
2144 y += this.getScroll()[0];
2153 getXY: function(ev) {
2154 ev = ev.browserEvent || ev;
2155 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2156 return [this.getPageX(ev), this.getPageY(ev)];
2160 getRelatedTarget: function(ev) {
2161 ev = ev.browserEvent || ev;
2162 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2163 var t = ev.relatedTarget;
2165 if (ev.type == "mouseout") {
2167 } else if (ev.type == "mouseover") {
2172 return this.resolveTextNode(t);
2176 getTime: function(ev) {
2177 ev = ev.browserEvent || ev;
2178 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2180 var t = new Date().getTime();
2184 this.lastError = ex;
2193 stopEvent: function(ev) {
2194 this.stopPropagation(ev);
2195 this.preventDefault(ev);
2199 stopPropagation: function(ev) {
2200 ev = ev.browserEvent || ev;
2201 if (ev.stopPropagation) {
2202 ev.stopPropagation();
2204 ev.cancelBubble = true;
2209 preventDefault: function(ev) {
2210 ev = ev.browserEvent || ev;
2211 if(ev.preventDefault) {
2212 ev.preventDefault();
2214 ev.returnValue = false;
2219 getEvent: function(e) {
2220 var ev = e || window.event;
2222 var c = this.getEvent.caller;
2224 ev = c.arguments[0];
2225 if (ev && Event == ev.constructor) {
2235 getCharCode: function(ev) {
2236 ev = ev.browserEvent || ev;
2237 return ev.charCode || ev.keyCode || 0;
2241 _getCacheIndex: function(el, eventName, fn) {
2242 for (var i = 0,len = listeners.length; i < len; ++i) {
2243 var li = listeners[i];
2245 li[this.FN] == fn &&
2246 li[this.EL] == el &&
2247 li[this.TYPE] == eventName) {
2259 getEl: function(id) {
2260 return document.getElementById(id);
2264 clearCache: function() {
2268 _load: function(e) {
2269 loadComplete = true;
2270 var EU = Roo.lib.Event;
2274 EU.doRemove(window, "load", EU._load);
2279 _tryPreloadAttach: function() {
2288 var tryAgain = !loadComplete;
2290 tryAgain = (retryCount > 0);
2295 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2296 var item = onAvailStack[i];
2298 var el = this.getEl(item.id);
2301 if (!item.checkReady ||
2304 (document && document.body)) {
2307 if (item.override) {
2308 if (item.override === true) {
2311 scope = item.override;
2314 item.fn.call(scope, item.obj);
2315 onAvailStack[i] = null;
2318 notAvail.push(item);
2323 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2327 this.startInterval();
2329 clearInterval(this._interval);
2330 this._interval = null;
2333 this.locked = false;
2340 purgeElement: function(el, recurse, eventName) {
2341 var elListeners = this.getListeners(el, eventName);
2343 for (var i = 0,len = elListeners.length; i < len; ++i) {
2344 var l = elListeners[i];
2345 this.removeListener(el, l.type, l.fn);
2349 if (recurse && el && el.childNodes) {
2350 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2351 this.purgeElement(el.childNodes[i], recurse, eventName);
2357 getListeners: function(el, eventName) {
2358 var results = [], searchLists;
2360 searchLists = [listeners, unloadListeners];
2361 } else if (eventName == "unload") {
2362 searchLists = [unloadListeners];
2364 searchLists = [listeners];
2367 for (var j = 0; j < searchLists.length; ++j) {
2368 var searchList = searchLists[j];
2369 if (searchList && searchList.length > 0) {
2370 for (var i = 0,len = searchList.length; i < len; ++i) {
2371 var l = searchList[i];
2372 if (l && l[this.EL] === el &&
2373 (!eventName || eventName === l[this.TYPE])) {
2378 adjust: l[this.ADJ_SCOPE],
2386 return (results.length) ? results : null;
2390 _unload: function(e) {
2392 var EU = Roo.lib.Event, i, j, l, len, index;
2394 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2395 l = unloadListeners[i];
2398 if (l[EU.ADJ_SCOPE]) {
2399 if (l[EU.ADJ_SCOPE] === true) {
2402 scope = l[EU.ADJ_SCOPE];
2405 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2406 unloadListeners[i] = null;
2412 unloadListeners = null;
2414 if (listeners && listeners.length > 0) {
2415 j = listeners.length;
2418 l = listeners[index];
2420 EU.removeListener(l[EU.EL], l[EU.TYPE],
2430 EU.doRemove(window, "unload", EU._unload);
2435 getScroll: function() {
2436 var dd = document.documentElement, db = document.body;
2437 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2438 return [dd.scrollTop, dd.scrollLeft];
2440 return [db.scrollTop, db.scrollLeft];
2447 doAdd: function () {
2448 if (window.addEventListener) {
2449 return function(el, eventName, fn, capture) {
2450 el.addEventListener(eventName, fn, (capture));
2452 } else if (window.attachEvent) {
2453 return function(el, eventName, fn, capture) {
2454 el.attachEvent("on" + eventName, fn);
2463 doRemove: function() {
2464 if (window.removeEventListener) {
2465 return function (el, eventName, fn, capture) {
2466 el.removeEventListener(eventName, fn, (capture));
2468 } else if (window.detachEvent) {
2469 return function (el, eventName, fn) {
2470 el.detachEvent("on" + eventName, fn);
2482 var E = Roo.lib.Event;
2483 E.on = E.addListener;
2484 E.un = E.removeListener;
2486 if (document && document.body) {
2489 E.doAdd(window, "load", E._load);
2491 E.doAdd(window, "unload", E._unload);
2492 E._tryPreloadAttach();
2496 * Portions of this file are based on pieces of Yahoo User Interface Library
2497 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2498 * YUI licensed under the BSD License:
2499 * http://developer.yahoo.net/yui/license.txt
2500 * <script type="text/javascript">
2506 * @class Roo.lib.Ajax
2513 request : function(method, uri, cb, data, options) {
2515 var hs = options.headers;
2518 if(hs.hasOwnProperty(h)){
2519 this.initHeader(h, hs[h], false);
2523 if(options.xmlData){
2524 this.initHeader('Content-Type', 'text/xml', false);
2526 data = options.xmlData;
2530 return this.asyncRequest(method, uri, cb, data);
2533 serializeForm : function(form) {
2534 if(typeof form == 'string') {
2535 form = (document.getElementById(form) || document.forms[form]);
2538 var el, name, val, disabled, data = '', hasSubmit = false;
2539 for (var i = 0; i < form.elements.length; i++) {
2540 el = form.elements[i];
2541 disabled = form.elements[i].disabled;
2542 name = form.elements[i].name;
2543 val = form.elements[i].value;
2545 if (!disabled && name){
2549 case 'select-multiple':
2550 for (var j = 0; j < el.options.length; j++) {
2551 if (el.options[j].selected) {
2553 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2556 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2564 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2577 if(hasSubmit == false) {
2578 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2583 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2588 data = data.substr(0, data.length - 1);
2596 useDefaultHeader:true,
2598 defaultPostHeader:'application/x-www-form-urlencoded',
2600 useDefaultXhrHeader:true,
2602 defaultXhrHeader:'XMLHttpRequest',
2604 hasDefaultHeaders:true,
2616 setProgId:function(id)
2618 this.activeX.unshift(id);
2621 setDefaultPostHeader:function(b)
2623 this.useDefaultHeader = b;
2626 setDefaultXhrHeader:function(b)
2628 this.useDefaultXhrHeader = b;
2631 setPollingInterval:function(i)
2633 if (typeof i == 'number' && isFinite(i)) {
2634 this.pollInterval = i;
2638 createXhrObject:function(transactionId)
2644 http = new XMLHttpRequest();
2646 obj = { conn:http, tId:transactionId };
2650 for (var i = 0; i < this.activeX.length; ++i) {
2654 http = new ActiveXObject(this.activeX[i]);
2656 obj = { conn:http, tId:transactionId };
2669 getConnectionObject:function()
2672 var tId = this.transactionId;
2676 o = this.createXhrObject(tId);
2678 this.transactionId++;
2689 asyncRequest:function(method, uri, callback, postData)
2691 var o = this.getConnectionObject();
2697 o.conn.open(method, uri, true);
2699 if (this.useDefaultXhrHeader) {
2700 if (!this.defaultHeaders['X-Requested-With']) {
2701 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2705 if(postData && this.useDefaultHeader){
2706 this.initHeader('Content-Type', this.defaultPostHeader);
2709 if (this.hasDefaultHeaders || this.hasHeaders) {
2713 this.handleReadyState(o, callback);
2714 o.conn.send(postData || null);
2720 handleReadyState:function(o, callback)
2724 if (callback && callback.timeout) {
2726 this.timeout[o.tId] = window.setTimeout(function() {
2727 oConn.abort(o, callback, true);
2728 }, callback.timeout);
2731 this.poll[o.tId] = window.setInterval(
2733 if (o.conn && o.conn.readyState == 4) {
2734 window.clearInterval(oConn.poll[o.tId]);
2735 delete oConn.poll[o.tId];
2737 if(callback && callback.timeout) {
2738 window.clearTimeout(oConn.timeout[o.tId]);
2739 delete oConn.timeout[o.tId];
2742 oConn.handleTransactionResponse(o, callback);
2745 , this.pollInterval);
2748 handleTransactionResponse:function(o, callback, isAbort)
2752 this.releaseObject(o);
2756 var httpStatus, responseObject;
2760 if (o.conn.status !== undefined && o.conn.status != 0) {
2761 httpStatus = o.conn.status;
2773 if (httpStatus >= 200 && httpStatus < 300) {
2774 responseObject = this.createResponseObject(o, callback.argument);
2775 if (callback.success) {
2776 if (!callback.scope) {
2777 callback.success(responseObject);
2782 callback.success.apply(callback.scope, [responseObject]);
2787 switch (httpStatus) {
2795 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2796 if (callback.failure) {
2797 if (!callback.scope) {
2798 callback.failure(responseObject);
2801 callback.failure.apply(callback.scope, [responseObject]);
2806 responseObject = this.createResponseObject(o, callback.argument);
2807 if (callback.failure) {
2808 if (!callback.scope) {
2809 callback.failure(responseObject);
2812 callback.failure.apply(callback.scope, [responseObject]);
2818 this.releaseObject(o);
2819 responseObject = null;
2822 createResponseObject:function(o, callbackArg)
2829 var headerStr = o.conn.getAllResponseHeaders();
2830 var header = headerStr.split('\n');
2831 for (var i = 0; i < header.length; i++) {
2832 var delimitPos = header[i].indexOf(':');
2833 if (delimitPos != -1) {
2834 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2842 obj.status = o.conn.status;
2843 obj.statusText = o.conn.statusText;
2844 obj.getResponseHeader = headerObj;
2845 obj.getAllResponseHeaders = headerStr;
2846 obj.responseText = o.conn.responseText;
2847 obj.responseXML = o.conn.responseXML;
2849 if (typeof callbackArg !== undefined) {
2850 obj.argument = callbackArg;
2856 createExceptionObject:function(tId, callbackArg, isAbort)
2859 var COMM_ERROR = 'communication failure';
2860 var ABORT_CODE = -1;
2861 var ABORT_ERROR = 'transaction aborted';
2867 obj.status = ABORT_CODE;
2868 obj.statusText = ABORT_ERROR;
2871 obj.status = COMM_CODE;
2872 obj.statusText = COMM_ERROR;
2876 obj.argument = callbackArg;
2882 initHeader:function(label, value, isDefault)
2884 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2886 if (headerObj[label] === undefined) {
2887 headerObj[label] = value;
2892 headerObj[label] = value + "," + headerObj[label];
2896 this.hasDefaultHeaders = true;
2899 this.hasHeaders = true;
2904 setHeader:function(o)
2906 if (this.hasDefaultHeaders) {
2907 for (var prop in this.defaultHeaders) {
2908 if (this.defaultHeaders.hasOwnProperty(prop)) {
2909 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2914 if (this.hasHeaders) {
2915 for (var prop in this.headers) {
2916 if (this.headers.hasOwnProperty(prop)) {
2917 o.conn.setRequestHeader(prop, this.headers[prop]);
2921 this.hasHeaders = false;
2925 resetDefaultHeaders:function() {
2926 delete this.defaultHeaders;
2927 this.defaultHeaders = {};
2928 this.hasDefaultHeaders = false;
2931 abort:function(o, callback, isTimeout)
2933 if(this.isCallInProgress(o)) {
2935 window.clearInterval(this.poll[o.tId]);
2936 delete this.poll[o.tId];
2938 delete this.timeout[o.tId];
2941 this.handleTransactionResponse(o, callback, true);
2951 isCallInProgress:function(o)
2954 return o.conn.readyState != 4 && o.conn.readyState != 0;
2963 releaseObject:function(o)
2972 'MSXML2.XMLHTTP.3.0',
2980 * Portions of this file are based on pieces of Yahoo User Interface Library
2981 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2982 * YUI licensed under the BSD License:
2983 * http://developer.yahoo.net/yui/license.txt
2984 * <script type="text/javascript">
2988 Roo.lib.Region = function(t, r, b, l) {
2998 Roo.lib.Region.prototype = {
2999 contains : function(region) {
3000 return ( region.left >= this.left &&
3001 region.right <= this.right &&
3002 region.top >= this.top &&
3003 region.bottom <= this.bottom );
3007 getArea : function() {
3008 return ( (this.bottom - this.top) * (this.right - this.left) );
3011 intersect : function(region) {
3012 var t = Math.max(this.top, region.top);
3013 var r = Math.min(this.right, region.right);
3014 var b = Math.min(this.bottom, region.bottom);
3015 var l = Math.max(this.left, region.left);
3017 if (b >= t && r >= l) {
3018 return new Roo.lib.Region(t, r, b, l);
3023 union : function(region) {
3024 var t = Math.min(this.top, region.top);
3025 var r = Math.max(this.right, region.right);
3026 var b = Math.max(this.bottom, region.bottom);
3027 var l = Math.min(this.left, region.left);
3029 return new Roo.lib.Region(t, r, b, l);
3032 adjust : function(t, l, b, r) {
3041 Roo.lib.Region.getRegion = function(el) {
3042 var p = Roo.lib.Dom.getXY(el);
3045 var r = p[0] + el.offsetWidth;
3046 var b = p[1] + el.offsetHeight;
3049 return new Roo.lib.Region(t, r, b, l);
3052 * Portions of this file are based on pieces of Yahoo User Interface Library
3053 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3054 * YUI licensed under the BSD License:
3055 * http://developer.yahoo.net/yui/license.txt
3056 * <script type="text/javascript">
3059 //@@dep Roo.lib.Region
3062 Roo.lib.Point = function(x, y) {
3063 if (x instanceof Array) {
3067 this.x = this.right = this.left = this[0] = x;
3068 this.y = this.top = this.bottom = this[1] = y;
3071 Roo.lib.Point.prototype = new Roo.lib.Region();
3073 * Portions of this file are based on pieces of Yahoo User Interface Library
3074 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3075 * YUI licensed under the BSD License:
3076 * http://developer.yahoo.net/yui/license.txt
3077 * <script type="text/javascript">
3084 scroll : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3088 motion : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3092 color : function(el, args, duration, easing, cb, scope) {
3093 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3096 run : function(el, args, duration, easing, cb, scope, type) {
3097 type = type || Roo.lib.AnimBase;
3098 if (typeof easing == "string") {
3099 easing = Roo.lib.Easing[easing];
3101 var anim = new type(el, args, duration, easing);
3102 anim.animateX(function() {
3103 Roo.callback(cb, scope);
3109 * Portions of this file are based on pieces of Yahoo User Interface Library
3110 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3111 * YUI licensed under the BSD License:
3112 * http://developer.yahoo.net/yui/license.txt
3113 * <script type="text/javascript">
3121 if (!libFlyweight) {
3122 libFlyweight = new Roo.Element.Flyweight();
3124 libFlyweight.dom = el;
3125 return libFlyweight;
3128 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3132 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3134 this.init(el, attributes, duration, method);
3138 Roo.lib.AnimBase.fly = fly;
3142 Roo.lib.AnimBase.prototype = {
3144 toString: function() {
3145 var el = this.getEl();
3146 var id = el.id || el.tagName;
3147 return ("Anim " + id);
3151 noNegatives: /width|height|opacity|padding/i,
3152 offsetAttribute: /^((width|height)|(top|left))$/,
3153 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3154 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3158 doMethod: function(attr, start, end) {
3159 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3163 setAttribute: function(attr, val, unit) {
3164 if (this.patterns.noNegatives.test(attr)) {
3165 val = (val > 0) ? val : 0;
3168 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3172 getAttribute: function(attr) {
3173 var el = this.getEl();
3174 var val = fly(el).getStyle(attr);
3176 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3177 return parseFloat(val);
3180 var a = this.patterns.offsetAttribute.exec(attr) || [];
3181 var pos = !!( a[3] );
3182 var box = !!( a[2] );
3185 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3186 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3195 getDefaultUnit: function(attr) {
3196 if (this.patterns.defaultUnit.test(attr)) {
3203 animateX : function(callback, scope) {
3204 var f = function() {
3205 this.onComplete.removeListener(f);
3206 if (typeof callback == "function") {
3207 callback.call(scope || this, this);
3210 this.onComplete.addListener(f, this);
3215 setRuntimeAttribute: function(attr) {
3218 var attributes = this.attributes;
3220 this.runtimeAttributes[attr] = {};
3222 var isset = function(prop) {
3223 return (typeof prop !== 'undefined');
3226 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3230 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3233 if (isset(attributes[attr]['to'])) {
3234 end = attributes[attr]['to'];
3235 } else if (isset(attributes[attr]['by'])) {
3236 if (start.constructor == Array) {
3238 for (var i = 0, len = start.length; i < len; ++i) {
3239 end[i] = start[i] + attributes[attr]['by'][i];
3242 end = start + attributes[attr]['by'];
3246 this.runtimeAttributes[attr].start = start;
3247 this.runtimeAttributes[attr].end = end;
3250 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3254 init: function(el, attributes, duration, method) {
3256 var isAnimated = false;
3259 var startTime = null;
3262 var actualFrames = 0;
3265 el = Roo.getDom(el);
3268 this.attributes = attributes || {};
3271 this.duration = duration || 1;
3274 this.method = method || Roo.lib.Easing.easeNone;
3277 this.useSeconds = true;
3280 this.currentFrame = 0;
3283 this.totalFrames = Roo.lib.AnimMgr.fps;
3286 this.getEl = function() {
3291 this.isAnimated = function() {
3296 this.getStartTime = function() {
3300 this.runtimeAttributes = {};
3303 this.animate = function() {
3304 if (this.isAnimated()) {
3308 this.currentFrame = 0;
3310 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3312 Roo.lib.AnimMgr.registerElement(this);
3316 this.stop = function(finish) {
3318 this.currentFrame = this.totalFrames;
3319 this._onTween.fire();
3321 Roo.lib.AnimMgr.stop(this);
3324 var onStart = function() {
3325 this.onStart.fire();
3327 this.runtimeAttributes = {};
3328 for (var attr in this.attributes) {
3329 this.setRuntimeAttribute(attr);
3334 startTime = new Date();
3338 var onTween = function() {
3340 duration: new Date() - this.getStartTime(),
3341 currentFrame: this.currentFrame
3344 data.toString = function() {
3346 'duration: ' + data.duration +
3347 ', currentFrame: ' + data.currentFrame
3351 this.onTween.fire(data);
3353 var runtimeAttributes = this.runtimeAttributes;
3355 for (var attr in runtimeAttributes) {
3356 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3362 var onComplete = function() {
3363 var actual_duration = (new Date() - startTime) / 1000 ;
3366 duration: actual_duration,
3367 frames: actualFrames,
3368 fps: actualFrames / actual_duration
3371 data.toString = function() {
3373 'duration: ' + data.duration +
3374 ', frames: ' + data.frames +
3375 ', fps: ' + data.fps
3381 this.onComplete.fire(data);
3385 this._onStart = new Roo.util.Event(this);
3386 this.onStart = new Roo.util.Event(this);
3387 this.onTween = new Roo.util.Event(this);
3388 this._onTween = new Roo.util.Event(this);
3389 this.onComplete = new Roo.util.Event(this);
3390 this._onComplete = new Roo.util.Event(this);
3391 this._onStart.addListener(onStart);
3392 this._onTween.addListener(onTween);
3393 this._onComplete.addListener(onComplete);
3398 * Portions of this file are based on pieces of Yahoo User Interface Library
3399 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3400 * YUI licensed under the BSD License:
3401 * http://developer.yahoo.net/yui/license.txt
3402 * <script type="text/javascript">
3406 Roo.lib.AnimMgr = new function() {
3423 this.registerElement = function(tween) {
3424 queue[queue.length] = tween;
3426 tween._onStart.fire();
3431 this.unRegister = function(tween, index) {
3432 tween._onComplete.fire();
3433 index = index || getIndex(tween);
3435 queue.splice(index, 1);
3439 if (tweenCount <= 0) {
3445 this.start = function() {
3446 if (thread === null) {
3447 thread = setInterval(this.run, this.delay);
3452 this.stop = function(tween) {
3454 clearInterval(thread);
3456 for (var i = 0, len = queue.length; i < len; ++i) {
3457 if (queue[0].isAnimated()) {
3458 this.unRegister(queue[0], 0);
3467 this.unRegister(tween);
3472 this.run = function() {
3473 for (var i = 0, len = queue.length; i < len; ++i) {
3474 var tween = queue[i];
3475 if (!tween || !tween.isAnimated()) {
3479 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3481 tween.currentFrame += 1;
3483 if (tween.useSeconds) {
3484 correctFrame(tween);
3486 tween._onTween.fire();
3489 Roo.lib.AnimMgr.stop(tween, i);
3494 var getIndex = function(anim) {
3495 for (var i = 0, len = queue.length; i < len; ++i) {
3496 if (queue[i] == anim) {
3504 var correctFrame = function(tween) {
3505 var frames = tween.totalFrames;
3506 var frame = tween.currentFrame;
3507 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3508 var elapsed = (new Date() - tween.getStartTime());
3511 if (elapsed < tween.duration * 1000) {
3512 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3514 tweak = frames - (frame + 1);
3516 if (tweak > 0 && isFinite(tweak)) {
3517 if (tween.currentFrame + tweak >= frames) {
3518 tweak = frames - (frame + 1);
3521 tween.currentFrame += tweak;
3527 * Portions of this file are based on pieces of Yahoo User Interface Library
3528 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3529 * YUI licensed under the BSD License:
3530 * http://developer.yahoo.net/yui/license.txt
3531 * <script type="text/javascript">
3534 Roo.lib.Bezier = new function() {
3536 this.getPosition = function(points, t) {
3537 var n = points.length;
3540 for (var i = 0; i < n; ++i) {
3541 tmp[i] = [points[i][0], points[i][1]];
3544 for (var j = 1; j < n; ++j) {
3545 for (i = 0; i < n - j; ++i) {
3546 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3547 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3551 return [ tmp[0][0], tmp[0][1] ];
3555 * Portions of this file are based on pieces of Yahoo User Interface Library
3556 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3557 * YUI licensed under the BSD License:
3558 * http://developer.yahoo.net/yui/license.txt
3559 * <script type="text/javascript">
3564 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3565 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3568 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3570 var fly = Roo.lib.AnimBase.fly;
3572 var superclass = Y.ColorAnim.superclass;
3573 var proto = Y.ColorAnim.prototype;
3575 proto.toString = function() {
3576 var el = this.getEl();
3577 var id = el.id || el.tagName;
3578 return ("ColorAnim " + id);
3581 proto.patterns.color = /color$/i;
3582 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3583 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3584 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3585 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3588 proto.parseColor = function(s) {
3589 if (s.length == 3) {
3593 var c = this.patterns.hex.exec(s);
3594 if (c && c.length == 4) {
3595 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3598 c = this.patterns.rgb.exec(s);
3599 if (c && c.length == 4) {
3600 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3603 c = this.patterns.hex3.exec(s);
3604 if (c && c.length == 4) {
3605 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3610 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3611 proto.getAttribute = function(attr) {
3612 var el = this.getEl();
3613 if (this.patterns.color.test(attr)) {
3614 var val = fly(el).getStyle(attr);
3616 if (this.patterns.transparent.test(val)) {
3617 var parent = el.parentNode;
3618 val = fly(parent).getStyle(attr);
3620 while (parent && this.patterns.transparent.test(val)) {
3621 parent = parent.parentNode;
3622 val = fly(parent).getStyle(attr);
3623 if (parent.tagName.toUpperCase() == 'HTML') {
3629 val = superclass.getAttribute.call(this, attr);
3634 proto.getAttribute = function(attr) {
3635 var el = this.getEl();
3636 if (this.patterns.color.test(attr)) {
3637 var val = fly(el).getStyle(attr);
3639 if (this.patterns.transparent.test(val)) {
3640 var parent = el.parentNode;
3641 val = fly(parent).getStyle(attr);
3643 while (parent && this.patterns.transparent.test(val)) {
3644 parent = parent.parentNode;
3645 val = fly(parent).getStyle(attr);
3646 if (parent.tagName.toUpperCase() == 'HTML') {
3652 val = superclass.getAttribute.call(this, attr);
3658 proto.doMethod = function(attr, start, end) {
3661 if (this.patterns.color.test(attr)) {
3663 for (var i = 0, len = start.length; i < len; ++i) {
3664 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3667 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3670 val = superclass.doMethod.call(this, attr, start, end);
3676 proto.setRuntimeAttribute = function(attr) {
3677 superclass.setRuntimeAttribute.call(this, attr);
3679 if (this.patterns.color.test(attr)) {
3680 var attributes = this.attributes;
3681 var start = this.parseColor(this.runtimeAttributes[attr].start);
3682 var end = this.parseColor(this.runtimeAttributes[attr].end);
3684 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3685 end = this.parseColor(attributes[attr].by);
3687 for (var i = 0, len = start.length; i < len; ++i) {
3688 end[i] = start[i] + end[i];
3692 this.runtimeAttributes[attr].start = start;
3693 this.runtimeAttributes[attr].end = end;
3699 * Portions of this file are based on pieces of Yahoo User Interface Library
3700 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3701 * YUI licensed under the BSD License:
3702 * http://developer.yahoo.net/yui/license.txt
3703 * <script type="text/javascript">
3709 easeNone: function (t, b, c, d) {
3710 return c * t / d + b;
3714 easeIn: function (t, b, c, d) {
3715 return c * (t /= d) * t + b;
3719 easeOut: function (t, b, c, d) {
3720 return -c * (t /= d) * (t - 2) + b;
3724 easeBoth: function (t, b, c, d) {
3725 if ((t /= d / 2) < 1) {
3726 return c / 2 * t * t + b;
3729 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3733 easeInStrong: function (t, b, c, d) {
3734 return c * (t /= d) * t * t * t + b;
3738 easeOutStrong: function (t, b, c, d) {
3739 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3743 easeBothStrong: function (t, b, c, d) {
3744 if ((t /= d / 2) < 1) {
3745 return c / 2 * t * t * t * t + b;
3748 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3753 elasticIn: function (t, b, c, d, a, p) {
3757 if ((t /= d) == 1) {
3764 if (!a || a < Math.abs(c)) {
3769 var s = p / (2 * Math.PI) * Math.asin(c / a);
3772 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3776 elasticOut: function (t, b, c, d, a, p) {
3780 if ((t /= d) == 1) {
3787 if (!a || a < Math.abs(c)) {
3792 var s = p / (2 * Math.PI) * Math.asin(c / a);
3795 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3799 elasticBoth: function (t, b, c, d, a, p) {
3804 if ((t /= d / 2) == 2) {
3812 if (!a || a < Math.abs(c)) {
3817 var s = p / (2 * Math.PI) * Math.asin(c / a);
3821 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3822 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3824 return a * Math.pow(2, -10 * (t -= 1)) *
3825 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3830 backIn: function (t, b, c, d, s) {
3831 if (typeof s == 'undefined') {
3834 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3838 backOut: function (t, b, c, d, s) {
3839 if (typeof s == 'undefined') {
3842 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3846 backBoth: function (t, b, c, d, s) {
3847 if (typeof s == 'undefined') {
3851 if ((t /= d / 2 ) < 1) {
3852 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3854 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3858 bounceIn: function (t, b, c, d) {
3859 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3863 bounceOut: function (t, b, c, d) {
3864 if ((t /= d) < (1 / 2.75)) {
3865 return c * (7.5625 * t * t) + b;
3866 } else if (t < (2 / 2.75)) {
3867 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3868 } else if (t < (2.5 / 2.75)) {
3869 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3871 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3875 bounceBoth: function (t, b, c, d) {
3877 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3879 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3882 * Portions of this file are based on pieces of Yahoo User Interface Library
3883 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3884 * YUI licensed under the BSD License:
3885 * http://developer.yahoo.net/yui/license.txt
3886 * <script type="text/javascript">
3890 Roo.lib.Motion = function(el, attributes, duration, method) {
3892 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3896 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3900 var superclass = Y.Motion.superclass;
3901 var proto = Y.Motion.prototype;
3903 proto.toString = function() {
3904 var el = this.getEl();
3905 var id = el.id || el.tagName;
3906 return ("Motion " + id);
3909 proto.patterns.points = /^points$/i;
3911 proto.setAttribute = function(attr, val, unit) {
3912 if (this.patterns.points.test(attr)) {
3913 unit = unit || 'px';
3914 superclass.setAttribute.call(this, 'left', val[0], unit);
3915 superclass.setAttribute.call(this, 'top', val[1], unit);
3917 superclass.setAttribute.call(this, attr, val, unit);
3921 proto.getAttribute = function(attr) {
3922 if (this.patterns.points.test(attr)) {
3924 superclass.getAttribute.call(this, 'left'),
3925 superclass.getAttribute.call(this, 'top')
3928 val = superclass.getAttribute.call(this, attr);
3934 proto.doMethod = function(attr, start, end) {
3937 if (this.patterns.points.test(attr)) {
3938 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3939 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3941 val = superclass.doMethod.call(this, attr, start, end);
3946 proto.setRuntimeAttribute = function(attr) {
3947 if (this.patterns.points.test(attr)) {
3948 var el = this.getEl();
3949 var attributes = this.attributes;
3951 var control = attributes['points']['control'] || [];
3955 if (control.length > 0 && !(control[0] instanceof Array)) {
3956 control = [control];
3959 for (i = 0,len = control.length; i < len; ++i) {
3960 tmp[i] = control[i];
3965 Roo.fly(el).position();
3967 if (isset(attributes['points']['from'])) {
3968 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3971 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3974 start = this.getAttribute('points');
3977 if (isset(attributes['points']['to'])) {
3978 end = translateValues.call(this, attributes['points']['to'], start);
3980 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3981 for (i = 0,len = control.length; i < len; ++i) {
3982 control[i] = translateValues.call(this, control[i], start);
3986 } else if (isset(attributes['points']['by'])) {
3987 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3989 for (i = 0,len = control.length; i < len; ++i) {
3990 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3994 this.runtimeAttributes[attr] = [start];
3996 if (control.length > 0) {
3997 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4000 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4003 superclass.setRuntimeAttribute.call(this, attr);
4007 var translateValues = function(val, start) {
4008 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4009 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4014 var isset = function(prop) {
4015 return (typeof prop !== 'undefined');
4019 * Portions of this file are based on pieces of Yahoo User Interface Library
4020 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4021 * YUI licensed under the BSD License:
4022 * http://developer.yahoo.net/yui/license.txt
4023 * <script type="text/javascript">
4027 Roo.lib.Scroll = function(el, attributes, duration, method) {
4029 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4033 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4037 var superclass = Y.Scroll.superclass;
4038 var proto = Y.Scroll.prototype;
4040 proto.toString = function() {
4041 var el = this.getEl();
4042 var id = el.id || el.tagName;
4043 return ("Scroll " + id);
4046 proto.doMethod = function(attr, start, end) {
4049 if (attr == 'scroll') {
4051 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4052 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4056 val = superclass.doMethod.call(this, attr, start, end);
4061 proto.getAttribute = function(attr) {
4063 var el = this.getEl();
4065 if (attr == 'scroll') {
4066 val = [ el.scrollLeft, el.scrollTop ];
4068 val = superclass.getAttribute.call(this, attr);
4074 proto.setAttribute = function(attr, val, unit) {
4075 var el = this.getEl();
4077 if (attr == 'scroll') {
4078 el.scrollLeft = val[0];
4079 el.scrollTop = val[1];
4081 superclass.setAttribute.call(this, attr, val, unit);
4087 * Ext JS Library 1.1.1
4088 * Copyright(c) 2006-2007, Ext JS, LLC.
4090 * Originally Released Under LGPL - original licence link has changed is not relivant.
4093 * <script type="text/javascript">
4097 // nasty IE9 hack - what a pile of crap that is..
4099 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4100 Range.prototype.createContextualFragment = function (html) {
4101 var doc = window.document;
4102 var container = doc.createElement("div");
4103 container.innerHTML = html;
4104 var frag = doc.createDocumentFragment(), n;
4105 while ((n = container.firstChild)) {
4106 frag.appendChild(n);
4113 * @class Roo.DomHelper
4114 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4115 * 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>.
4118 Roo.DomHelper = function(){
4119 var tempTableEl = null;
4120 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4121 var tableRe = /^table|tbody|tr|td$/i;
4123 // build as innerHTML where available
4125 var createHtml = function(o){
4126 if(typeof o == 'string'){
4135 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4136 if(attr == "style"){
4138 if(typeof s == "function"){
4141 if(typeof s == "string"){
4142 b += ' style="' + s + '"';
4143 }else if(typeof s == "object"){
4146 if(typeof s[key] != "function"){
4147 b += key + ":" + s[key] + ";";
4154 b += ' class="' + o["cls"] + '"';
4155 }else if(attr == "htmlFor"){
4156 b += ' for="' + o["htmlFor"] + '"';
4158 b += " " + attr + '="' + o[attr] + '"';
4162 if(emptyTags.test(o.tag)){
4166 var cn = o.children || o.cn;
4168 //http://bugs.kde.org/show_bug.cgi?id=71506
4169 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4170 for(var i = 0, len = cn.length; i < len; i++) {
4171 b += createHtml(cn[i], b);
4174 b += createHtml(cn, b);
4180 b += "</" + o.tag + ">";
4187 var createDom = function(o, parentNode){
4189 // defininition craeted..
4191 if (o.ns && o.ns != 'html') {
4193 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4194 xmlns[o.ns] = o.xmlns;
4197 if (typeof(xmlns[o.ns]) == 'undefined') {
4198 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4204 if (typeof(o) == 'string') {
4205 return parentNode.appendChild(document.createTextNode(o));
4207 o.tag = o.tag || div;
4208 if (o.ns && Roo.isIE) {
4210 o.tag = o.ns + ':' + o.tag;
4213 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4214 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4217 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4218 attr == "style" || typeof o[attr] == "function") continue;
4220 if(attr=="cls" && Roo.isIE){
4221 el.className = o["cls"];
4223 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4224 else el[attr] = o[attr];
4227 Roo.DomHelper.applyStyles(el, o.style);
4228 var cn = o.children || o.cn;
4230 //http://bugs.kde.org/show_bug.cgi?id=71506
4231 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4232 for(var i = 0, len = cn.length; i < len; i++) {
4233 createDom(cn[i], el);
4240 el.innerHTML = o.html;
4243 parentNode.appendChild(el);
4248 var ieTable = function(depth, s, h, e){
4249 tempTableEl.innerHTML = [s, h, e].join('');
4250 var i = -1, el = tempTableEl;
4257 // kill repeat to save bytes
4261 tbe = '</tbody>'+te,
4267 * Nasty code for IE's broken table implementation
4269 var insertIntoTable = function(tag, where, el, html){
4271 tempTableEl = document.createElement('div');
4276 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4279 if(where == 'beforebegin'){
4283 before = el.nextSibling;
4286 node = ieTable(4, trs, html, tre);
4288 else if(tag == 'tr'){
4289 if(where == 'beforebegin'){
4292 node = ieTable(3, tbs, html, tbe);
4293 } else if(where == 'afterend'){
4294 before = el.nextSibling;
4296 node = ieTable(3, tbs, html, tbe);
4297 } else{ // INTO a TR
4298 if(where == 'afterbegin'){
4299 before = el.firstChild;
4301 node = ieTable(4, trs, html, tre);
4303 } else if(tag == 'tbody'){
4304 if(where == 'beforebegin'){
4307 node = ieTable(2, ts, html, te);
4308 } else if(where == 'afterend'){
4309 before = el.nextSibling;
4311 node = ieTable(2, ts, html, te);
4313 if(where == 'afterbegin'){
4314 before = el.firstChild;
4316 node = ieTable(3, tbs, html, tbe);
4319 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4322 if(where == 'afterbegin'){
4323 before = el.firstChild;
4325 node = ieTable(2, ts, html, te);
4327 el.insertBefore(node, before);
4332 /** True to force the use of DOM instead of html fragments @type Boolean */
4336 * Returns the markup for the passed Element(s) config
4337 * @param {Object} o The Dom object spec (and children)
4340 markup : function(o){
4341 return createHtml(o);
4345 * Applies a style specification to an element
4346 * @param {String/HTMLElement} el The element to apply styles to
4347 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4348 * a function which returns such a specification.
4350 applyStyles : function(el, styles){
4353 if(typeof styles == "string"){
4354 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4356 while ((matches = re.exec(styles)) != null){
4357 el.setStyle(matches[1], matches[2]);
4359 }else if (typeof styles == "object"){
4360 for (var style in styles){
4361 el.setStyle(style, styles[style]);
4363 }else if (typeof styles == "function"){
4364 Roo.DomHelper.applyStyles(el, styles.call());
4370 * Inserts an HTML fragment into the Dom
4371 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4372 * @param {HTMLElement} el The context element
4373 * @param {String} html The HTML fragmenet
4374 * @return {HTMLElement} The new node
4376 insertHtml : function(where, el, html){
4377 where = where.toLowerCase();
4378 if(el.insertAdjacentHTML){
4379 if(tableRe.test(el.tagName)){
4381 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4387 el.insertAdjacentHTML('BeforeBegin', html);
4388 return el.previousSibling;
4390 el.insertAdjacentHTML('AfterBegin', html);
4391 return el.firstChild;
4393 el.insertAdjacentHTML('BeforeEnd', html);
4394 return el.lastChild;
4396 el.insertAdjacentHTML('AfterEnd', html);
4397 return el.nextSibling;
4399 throw 'Illegal insertion point -> "' + where + '"';
4401 var range = el.ownerDocument.createRange();
4405 range.setStartBefore(el);
4406 frag = range.createContextualFragment(html);
4407 el.parentNode.insertBefore(frag, el);
4408 return el.previousSibling;
4411 range.setStartBefore(el.firstChild);
4412 frag = range.createContextualFragment(html);
4413 el.insertBefore(frag, el.firstChild);
4414 return el.firstChild;
4416 el.innerHTML = html;
4417 return el.firstChild;
4421 range.setStartAfter(el.lastChild);
4422 frag = range.createContextualFragment(html);
4423 el.appendChild(frag);
4424 return el.lastChild;
4426 el.innerHTML = html;
4427 return el.lastChild;
4430 range.setStartAfter(el);
4431 frag = range.createContextualFragment(html);
4432 el.parentNode.insertBefore(frag, el.nextSibling);
4433 return el.nextSibling;
4435 throw 'Illegal insertion point -> "' + where + '"';
4439 * Creates new Dom element(s) and inserts them before el
4440 * @param {String/HTMLElement/Element} el The context element
4441 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4442 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4443 * @return {HTMLElement/Roo.Element} The new node
4445 insertBefore : function(el, o, returnElement){
4446 return this.doInsert(el, o, returnElement, "beforeBegin");
4450 * Creates new Dom element(s) and inserts them after el
4451 * @param {String/HTMLElement/Element} el The context element
4452 * @param {Object} o The Dom object spec (and children)
4453 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4454 * @return {HTMLElement/Roo.Element} The new node
4456 insertAfter : function(el, o, returnElement){
4457 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4461 * Creates new Dom element(s) and inserts them as the first child of el
4462 * @param {String/HTMLElement/Element} el The context element
4463 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4464 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4465 * @return {HTMLElement/Roo.Element} The new node
4467 insertFirst : function(el, o, returnElement){
4468 return this.doInsert(el, o, returnElement, "afterBegin");
4472 doInsert : function(el, o, returnElement, pos, sibling){
4473 el = Roo.getDom(el);
4475 if(this.useDom || o.ns){
4476 newNode = createDom(o, null);
4477 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4479 var html = createHtml(o);
4480 newNode = this.insertHtml(pos, el, html);
4482 return returnElement ? Roo.get(newNode, true) : newNode;
4486 * Creates new Dom element(s) and appends them to el
4487 * @param {String/HTMLElement/Element} el The context element
4488 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4489 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490 * @return {HTMLElement/Roo.Element} The new node
4492 append : function(el, o, returnElement){
4493 el = Roo.getDom(el);
4495 if(this.useDom || o.ns){
4496 newNode = createDom(o, null);
4497 el.appendChild(newNode);
4499 var html = createHtml(o);
4500 newNode = this.insertHtml("beforeEnd", el, html);
4502 return returnElement ? Roo.get(newNode, true) : newNode;
4506 * Creates new Dom element(s) and overwrites the contents of el with them
4507 * @param {String/HTMLElement/Element} el The context element
4508 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4509 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4510 * @return {HTMLElement/Roo.Element} The new node
4512 overwrite : function(el, o, returnElement){
4513 el = Roo.getDom(el);
4516 while (el.childNodes.length) {
4517 el.removeChild(el.firstChild);
4521 el.innerHTML = createHtml(o);
4524 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4528 * Creates a new Roo.DomHelper.Template from the Dom object spec
4529 * @param {Object} o The Dom object spec (and children)
4530 * @return {Roo.DomHelper.Template} The new template
4532 createTemplate : function(o){
4533 var html = createHtml(o);
4534 return new Roo.Template(html);
4540 * Ext JS Library 1.1.1
4541 * Copyright(c) 2006-2007, Ext JS, LLC.
4543 * Originally Released Under LGPL - original licence link has changed is not relivant.
4546 * <script type="text/javascript">
4550 * @class Roo.Template
4551 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4552 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4555 var t = new Roo.Template({
4556 html : '<div name="{id}">' +
4557 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4559 myformat: function (value, allValues) {
4560 return 'XX' + value;
4563 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4565 * For more information see this blog post with examples:
4566 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4567 - Create Elements using DOM, HTML fragments and Templates</a>.
4569 * @param {Object} cfg - Configuration object.
4571 Roo.Template = function(cfg){
4573 if(cfg instanceof Array){
4575 }else if(arguments.length > 1){
4576 cfg = Array.prototype.join.call(arguments, "");
4580 if (typeof(cfg) == 'object') {
4591 Roo.Template.prototype = {
4594 * @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..
4595 * it should be fixed so that template is observable...
4599 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4603 * Returns an HTML fragment of this template with the specified values applied.
4604 * @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'})
4605 * @return {String} The HTML fragment
4607 applyTemplate : function(values){
4611 return this.compiled(values);
4613 var useF = this.disableFormats !== true;
4614 var fm = Roo.util.Format, tpl = this;
4615 var fn = function(m, name, format, args){
4617 if(format.substr(0, 5) == "this."){
4618 return tpl.call(format.substr(5), values[name], values);
4621 // quoted values are required for strings in compiled templates,
4622 // but for non compiled we need to strip them
4623 // quoted reversed for jsmin
4624 var re = /^\s*['"](.*)["']\s*$/;
4625 args = args.split(',');
4626 for(var i = 0, len = args.length; i < len; i++){
4627 args[i] = args[i].replace(re, "$1");
4629 args = [values[name]].concat(args);
4631 args = [values[name]];
4633 return fm[format].apply(fm, args);
4636 return values[name] !== undefined ? values[name] : "";
4639 return this.html.replace(this.re, fn);
4657 this.loading = true;
4658 this.compiled = false;
4660 var cx = new Roo.data.Connection();
4664 success : function (response) {
4666 _t.html = response.responseText;
4670 failure : function(response) {
4671 Roo.log("Template failed to load from " + _t.url);
4678 * Sets the HTML used as the template and optionally compiles it.
4679 * @param {String} html
4680 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4681 * @return {Roo.Template} this
4683 set : function(html, compile){
4685 this.compiled = null;
4693 * True to disable format functions (defaults to false)
4696 disableFormats : false,
4699 * The regular expression used to match template variables
4703 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4706 * Compiles the template into an internal function, eliminating the RegEx overhead.
4707 * @return {Roo.Template} this
4709 compile : function(){
4710 var fm = Roo.util.Format;
4711 var useF = this.disableFormats !== true;
4712 var sep = Roo.isGecko ? "+" : ",";
4713 var fn = function(m, name, format, args){
4715 args = args ? ',' + args : "";
4716 if(format.substr(0, 5) != "this."){
4717 format = "fm." + format + '(';
4719 format = 'this.call("'+ format.substr(5) + '", ';
4723 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4725 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4728 // branched to use + in gecko and [].join() in others
4730 body = "this.compiled = function(values){ return '" +
4731 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4734 body = ["this.compiled = function(values){ return ['"];
4735 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4736 body.push("'].join('');};");
4737 body = body.join('');
4747 // private function used to call members
4748 call : function(fnName, value, allValues){
4749 return this[fnName](value, allValues);
4753 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4754 * @param {String/HTMLElement/Roo.Element} el The context element
4755 * @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'})
4756 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4757 * @return {HTMLElement/Roo.Element} The new node or Element
4759 insertFirst: function(el, values, returnElement){
4760 return this.doInsert('afterBegin', el, values, returnElement);
4764 * Applies the supplied values to the template and inserts the new node(s) before el.
4765 * @param {String/HTMLElement/Roo.Element} el The context element
4766 * @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'})
4767 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4768 * @return {HTMLElement/Roo.Element} The new node or Element
4770 insertBefore: function(el, values, returnElement){
4771 return this.doInsert('beforeBegin', el, values, returnElement);
4775 * Applies the supplied values to the template and inserts the new node(s) after el.
4776 * @param {String/HTMLElement/Roo.Element} el The context element
4777 * @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'})
4778 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4779 * @return {HTMLElement/Roo.Element} The new node or Element
4781 insertAfter : function(el, values, returnElement){
4782 return this.doInsert('afterEnd', el, values, returnElement);
4786 * Applies the supplied values to the template and appends the new node(s) to el.
4787 * @param {String/HTMLElement/Roo.Element} el The context element
4788 * @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'})
4789 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790 * @return {HTMLElement/Roo.Element} The new node or Element
4792 append : function(el, values, returnElement){
4793 return this.doInsert('beforeEnd', el, values, returnElement);
4796 doInsert : function(where, el, values, returnEl){
4797 el = Roo.getDom(el);
4798 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4799 return returnEl ? Roo.get(newNode, true) : newNode;
4803 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4804 * @param {String/HTMLElement/Roo.Element} el The context element
4805 * @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'})
4806 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4807 * @return {HTMLElement/Roo.Element} The new node or Element
4809 overwrite : function(el, values, returnElement){
4810 el = Roo.getDom(el);
4811 el.innerHTML = this.applyTemplate(values);
4812 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4816 * Alias for {@link #applyTemplate}
4819 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4822 Roo.DomHelper.Template = Roo.Template;
4825 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4826 * @param {String/HTMLElement} el A DOM element or its id
4827 * @returns {Roo.Template} The created template
4830 Roo.Template.from = function(el){
4831 el = Roo.getDom(el);
4832 return new Roo.Template(el.value || el.innerHTML);
4835 * Ext JS Library 1.1.1
4836 * Copyright(c) 2006-2007, Ext JS, LLC.
4838 * Originally Released Under LGPL - original licence link has changed is not relivant.
4841 * <script type="text/javascript">
4846 * This is code is also distributed under MIT license for use
4847 * with jQuery and prototype JavaScript libraries.
4850 * @class Roo.DomQuery
4851 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).
4853 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>
4856 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.
4858 <h4>Element Selectors:</h4>
4860 <li> <b>*</b> any element</li>
4861 <li> <b>E</b> an element with the tag E</li>
4862 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4863 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4864 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4865 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4867 <h4>Attribute Selectors:</h4>
4868 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4870 <li> <b>E[foo]</b> has an attribute "foo"</li>
4871 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4872 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4873 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4874 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4875 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4876 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4878 <h4>Pseudo Classes:</h4>
4880 <li> <b>E:first-child</b> E is the first child of its parent</li>
4881 <li> <b>E:last-child</b> E is the last child of its parent</li>
4882 <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>
4883 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4884 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4885 <li> <b>E:only-child</b> E is the only child of its parent</li>
4886 <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>
4887 <li> <b>E:first</b> the first E in the resultset</li>
4888 <li> <b>E:last</b> the last E in the resultset</li>
4889 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4890 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4891 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4892 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4893 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4894 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4895 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4896 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4897 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4899 <h4>CSS Value Selectors:</h4>
4901 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4902 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4903 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4904 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4905 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4906 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4910 Roo.DomQuery = function(){
4911 var cache = {}, simpleCache = {}, valueCache = {};
4912 var nonSpace = /\S/;
4913 var trimRe = /^\s+|\s+$/g;
4914 var tplRe = /\{(\d+)\}/g;
4915 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4916 var tagTokenRe = /^(#)?([\w-\*]+)/;
4917 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4919 function child(p, index){
4921 var n = p.firstChild;
4923 if(n.nodeType == 1){
4934 while((n = n.nextSibling) && n.nodeType != 1);
4939 while((n = n.previousSibling) && n.nodeType != 1);
4943 function children(d){
4944 var n = d.firstChild, ni = -1;
4946 var nx = n.nextSibling;
4947 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4957 function byClassName(c, a, v){
4961 var r = [], ri = -1, cn;
4962 for(var i = 0, ci; ci = c[i]; i++){
4963 if((' '+ci.className+' ').indexOf(v) != -1){
4970 function attrValue(n, attr){
4971 if(!n.tagName && typeof n.length != "undefined"){
4980 if(attr == "class" || attr == "className"){
4983 return n.getAttribute(attr) || n[attr];
4987 function getNodes(ns, mode, tagName){
4988 var result = [], ri = -1, cs;
4992 tagName = tagName || "*";
4993 if(typeof ns.getElementsByTagName != "undefined"){
4997 for(var i = 0, ni; ni = ns[i]; i++){
4998 cs = ni.getElementsByTagName(tagName);
4999 for(var j = 0, ci; ci = cs[j]; j++){
5003 }else if(mode == "/" || mode == ">"){
5004 var utag = tagName.toUpperCase();
5005 for(var i = 0, ni, cn; ni = ns[i]; i++){
5006 cn = ni.children || ni.childNodes;
5007 for(var j = 0, cj; cj = cn[j]; j++){
5008 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5013 }else if(mode == "+"){
5014 var utag = tagName.toUpperCase();
5015 for(var i = 0, n; n = ns[i]; i++){
5016 while((n = n.nextSibling) && n.nodeType != 1);
5017 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5021 }else if(mode == "~"){
5022 for(var i = 0, n; n = ns[i]; i++){
5023 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5032 function concat(a, b){
5036 for(var i = 0, l = b.length; i < l; i++){
5042 function byTag(cs, tagName){
5043 if(cs.tagName || cs == document){
5049 var r = [], ri = -1;
5050 tagName = tagName.toLowerCase();
5051 for(var i = 0, ci; ci = cs[i]; i++){
5052 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5059 function byId(cs, attr, id){
5060 if(cs.tagName || cs == document){
5066 var r = [], ri = -1;
5067 for(var i = 0,ci; ci = cs[i]; i++){
5068 if(ci && ci.id == id){
5076 function byAttribute(cs, attr, value, op, custom){
5077 var r = [], ri = -1, st = custom=="{";
5078 var f = Roo.DomQuery.operators[op];
5079 for(var i = 0, ci; ci = cs[i]; i++){
5082 a = Roo.DomQuery.getStyle(ci, attr);
5084 else if(attr == "class" || attr == "className"){
5086 }else if(attr == "for"){
5088 }else if(attr == "href"){
5089 a = ci.getAttribute("href", 2);
5091 a = ci.getAttribute(attr);
5093 if((f && f(a, value)) || (!f && a)){
5100 function byPseudo(cs, name, value){
5101 return Roo.DomQuery.pseudos[name](cs, value);
5104 // This is for IE MSXML which does not support expandos.
5105 // IE runs the same speed using setAttribute, however FF slows way down
5106 // and Safari completely fails so they need to continue to use expandos.
5107 var isIE = window.ActiveXObject ? true : false;
5109 // this eval is stop the compressor from
5110 // renaming the variable to something shorter
5112 /** eval:var:batch */
5117 function nodupIEXml(cs){
5119 cs[0].setAttribute("_nodup", d);
5121 for(var i = 1, len = cs.length; i < len; i++){
5123 if(!c.getAttribute("_nodup") != d){
5124 c.setAttribute("_nodup", d);
5128 for(var i = 0, len = cs.length; i < len; i++){
5129 cs[i].removeAttribute("_nodup");
5138 var len = cs.length, c, i, r = cs, cj, ri = -1;
5139 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5142 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5143 return nodupIEXml(cs);
5147 for(i = 1; c = cs[i]; i++){
5152 for(var j = 0; j < i; j++){
5155 for(j = i+1; cj = cs[j]; j++){
5167 function quickDiffIEXml(c1, c2){
5169 for(var i = 0, len = c1.length; i < len; i++){
5170 c1[i].setAttribute("_qdiff", d);
5173 for(var i = 0, len = c2.length; i < len; i++){
5174 if(c2[i].getAttribute("_qdiff") != d){
5175 r[r.length] = c2[i];
5178 for(var i = 0, len = c1.length; i < len; i++){
5179 c1[i].removeAttribute("_qdiff");
5184 function quickDiff(c1, c2){
5185 var len1 = c1.length;
5189 if(isIE && c1[0].selectSingleNode){
5190 return quickDiffIEXml(c1, c2);
5193 for(var i = 0; i < len1; i++){
5197 for(var i = 0, len = c2.length; i < len; i++){
5198 if(c2[i]._qdiff != d){
5199 r[r.length] = c2[i];
5205 function quickId(ns, mode, root, id){
5207 var d = root.ownerDocument || root;
5208 return d.getElementById(id);
5210 ns = getNodes(ns, mode, "*");
5211 return byId(ns, null, id);
5215 getStyle : function(el, name){
5216 return Roo.fly(el).getStyle(name);
5219 * Compiles a selector/xpath query into a reusable function. The returned function
5220 * takes one parameter "root" (optional), which is the context node from where the query should start.
5221 * @param {String} selector The selector/xpath query
5222 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5223 * @return {Function}
5225 compile : function(path, type){
5226 type = type || "select";
5228 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5229 var q = path, mode, lq;
5230 var tk = Roo.DomQuery.matchers;
5231 var tklen = tk.length;
5234 // accept leading mode switch
5235 var lmode = q.match(modeRe);
5236 if(lmode && lmode[1]){
5237 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5238 q = q.replace(lmode[1], "");
5240 // strip leading slashes
5241 while(path.substr(0, 1)=="/"){
5242 path = path.substr(1);
5245 while(q && lq != q){
5247 var tm = q.match(tagTokenRe);
5248 if(type == "select"){
5251 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5253 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5255 q = q.replace(tm[0], "");
5256 }else if(q.substr(0, 1) != '@'){
5257 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5262 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5264 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5266 q = q.replace(tm[0], "");
5269 while(!(mm = q.match(modeRe))){
5270 var matched = false;
5271 for(var j = 0; j < tklen; j++){
5273 var m = q.match(t.re);
5275 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5278 q = q.replace(m[0], "");
5283 // prevent infinite loop on bad selector
5285 throw 'Error parsing selector, parsing failed at "' + q + '"';
5289 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5290 q = q.replace(mm[1], "");
5293 fn[fn.length] = "return nodup(n);\n}";
5296 * list of variables that need from compression as they are used by eval.
5306 * eval:var:byClassName
5308 * eval:var:byAttribute
5309 * eval:var:attrValue
5317 * Selects a group of elements.
5318 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5319 * @param {Node} root (optional) The start of the query (defaults to document).
5322 select : function(path, root, type){
5323 if(!root || root == document){
5326 if(typeof root == "string"){
5327 root = document.getElementById(root);
5329 var paths = path.split(",");
5331 for(var i = 0, len = paths.length; i < len; i++){
5332 var p = paths[i].replace(trimRe, "");
5334 cache[p] = Roo.DomQuery.compile(p);
5336 throw p + " is not a valid selector";
5339 var result = cache[p](root);
5340 if(result && result != document){
5341 results = results.concat(result);
5344 if(paths.length > 1){
5345 return nodup(results);
5351 * Selects a single element.
5352 * @param {String} selector The selector/xpath query
5353 * @param {Node} root (optional) The start of the query (defaults to document).
5356 selectNode : function(path, root){
5357 return Roo.DomQuery.select(path, root)[0];
5361 * Selects the value of a node, optionally replacing null with the defaultValue.
5362 * @param {String} selector The selector/xpath query
5363 * @param {Node} root (optional) The start of the query (defaults to document).
5364 * @param {String} defaultValue
5366 selectValue : function(path, root, defaultValue){
5367 path = path.replace(trimRe, "");
5368 if(!valueCache[path]){
5369 valueCache[path] = Roo.DomQuery.compile(path, "select");
5371 var n = valueCache[path](root);
5372 n = n[0] ? n[0] : n;
5373 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5374 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5378 * Selects the value of a node, parsing integers and floats.
5379 * @param {String} selector The selector/xpath query
5380 * @param {Node} root (optional) The start of the query (defaults to document).
5381 * @param {Number} defaultValue
5384 selectNumber : function(path, root, defaultValue){
5385 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5386 return parseFloat(v);
5390 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5391 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5392 * @param {String} selector The simple selector to test
5395 is : function(el, ss){
5396 if(typeof el == "string"){
5397 el = document.getElementById(el);
5399 var isArray = (el instanceof Array);
5400 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5401 return isArray ? (result.length == el.length) : (result.length > 0);
5405 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5406 * @param {Array} el An array of elements to filter
5407 * @param {String} selector The simple selector to test
5408 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5409 * the selector instead of the ones that match
5412 filter : function(els, ss, nonMatches){
5413 ss = ss.replace(trimRe, "");
5414 if(!simpleCache[ss]){
5415 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5417 var result = simpleCache[ss](els);
5418 return nonMatches ? quickDiff(result, els) : result;
5422 * Collection of matching regular expressions and code snippets.
5426 select: 'n = byClassName(n, null, " {1} ");'
5428 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5429 select: 'n = byPseudo(n, "{1}", "{2}");'
5431 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5432 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5435 select: 'n = byId(n, null, "{1}");'
5438 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5443 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5444 * 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, > <.
5447 "=" : function(a, v){
5450 "!=" : function(a, v){
5453 "^=" : function(a, v){
5454 return a && a.substr(0, v.length) == v;
5456 "$=" : function(a, v){
5457 return a && a.substr(a.length-v.length) == v;
5459 "*=" : function(a, v){
5460 return a && a.indexOf(v) !== -1;
5462 "%=" : function(a, v){
5463 return (a % v) == 0;
5465 "|=" : function(a, v){
5466 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5468 "~=" : function(a, v){
5469 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5474 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5475 * and the argument (if any) supplied in the selector.
5478 "first-child" : function(c){
5479 var r = [], ri = -1, n;
5480 for(var i = 0, ci; ci = n = c[i]; i++){
5481 while((n = n.previousSibling) && n.nodeType != 1);
5489 "last-child" : function(c){
5490 var r = [], ri = -1, n;
5491 for(var i = 0, ci; ci = n = c[i]; i++){
5492 while((n = n.nextSibling) && n.nodeType != 1);
5500 "nth-child" : function(c, a) {
5501 var r = [], ri = -1;
5502 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5503 var f = (m[1] || 1) - 0, l = m[2] - 0;
5504 for(var i = 0, n; n = c[i]; i++){
5505 var pn = n.parentNode;
5506 if (batch != pn._batch) {
5508 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5509 if(cn.nodeType == 1){
5516 if (l == 0 || n.nodeIndex == l){
5519 } else if ((n.nodeIndex + l) % f == 0){
5527 "only-child" : function(c){
5528 var r = [], ri = -1;;
5529 for(var i = 0, ci; ci = c[i]; i++){
5530 if(!prev(ci) && !next(ci)){
5537 "empty" : function(c){
5538 var r = [], ri = -1;
5539 for(var i = 0, ci; ci = c[i]; i++){
5540 var cns = ci.childNodes, j = 0, cn, empty = true;
5543 if(cn.nodeType == 1 || cn.nodeType == 3){
5555 "contains" : function(c, v){
5556 var r = [], ri = -1;
5557 for(var i = 0, ci; ci = c[i]; i++){
5558 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5565 "nodeValue" : function(c, v){
5566 var r = [], ri = -1;
5567 for(var i = 0, ci; ci = c[i]; i++){
5568 if(ci.firstChild && ci.firstChild.nodeValue == v){
5575 "checked" : function(c){
5576 var r = [], ri = -1;
5577 for(var i = 0, ci; ci = c[i]; i++){
5578 if(ci.checked == true){
5585 "not" : function(c, ss){
5586 return Roo.DomQuery.filter(c, ss, true);
5589 "odd" : function(c){
5590 return this["nth-child"](c, "odd");
5593 "even" : function(c){
5594 return this["nth-child"](c, "even");
5597 "nth" : function(c, a){
5598 return c[a-1] || [];
5601 "first" : function(c){
5605 "last" : function(c){
5606 return c[c.length-1] || [];
5609 "has" : function(c, ss){
5610 var s = Roo.DomQuery.select;
5611 var r = [], ri = -1;
5612 for(var i = 0, ci; ci = c[i]; i++){
5613 if(s(ss, ci).length > 0){
5620 "next" : function(c, ss){
5621 var is = Roo.DomQuery.is;
5622 var r = [], ri = -1;
5623 for(var i = 0, ci; ci = c[i]; i++){
5632 "prev" : function(c, ss){
5633 var is = Roo.DomQuery.is;
5634 var r = [], ri = -1;
5635 for(var i = 0, ci; ci = c[i]; i++){
5648 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5649 * @param {String} path The selector/xpath query
5650 * @param {Node} root (optional) The start of the query (defaults to document).
5655 Roo.query = Roo.DomQuery.select;
5658 * Ext JS Library 1.1.1
5659 * Copyright(c) 2006-2007, Ext JS, LLC.
5661 * Originally Released Under LGPL - original licence link has changed is not relivant.
5664 * <script type="text/javascript">
5668 * @class Roo.util.Observable
5669 * Base class that provides a common interface for publishing events. Subclasses are expected to
5670 * to have a property "events" with all the events defined.<br>
5673 Employee = function(name){
5680 Roo.extend(Employee, Roo.util.Observable);
5682 * @param {Object} config properties to use (incuding events / listeners)
5685 Roo.util.Observable = function(cfg){
5688 this.addEvents(cfg.events || {});
5690 delete cfg.events; // make sure
5693 Roo.apply(this, cfg);
5696 this.on(this.listeners);
5697 delete this.listeners;
5700 Roo.util.Observable.prototype = {
5702 * @cfg {Object} listeners list of events and functions to call for this object,
5706 'click' : function(e) {
5716 * Fires the specified event with the passed parameters (minus the event name).
5717 * @param {String} eventName
5718 * @param {Object...} args Variable number of parameters are passed to handlers
5719 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5721 fireEvent : function(){
5722 var ce = this.events[arguments[0].toLowerCase()];
5723 if(typeof ce == "object"){
5724 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5731 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5734 * Appends an event handler to this component
5735 * @param {String} eventName The type of event to listen for
5736 * @param {Function} handler The method the event invokes
5737 * @param {Object} scope (optional) The scope in which to execute the handler
5738 * function. The handler function's "this" context.
5739 * @param {Object} options (optional) An object containing handler configuration
5740 * properties. This may contain any of the following properties:<ul>
5741 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5742 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5743 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5744 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5745 * by the specified number of milliseconds. If the event fires again within that time, the original
5746 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5749 * <b>Combining Options</b><br>
5750 * Using the options argument, it is possible to combine different types of listeners:<br>
5752 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5754 el.on('click', this.onClick, this, {
5761 * <b>Attaching multiple handlers in 1 call</b><br>
5762 * The method also allows for a single argument to be passed which is a config object containing properties
5763 * which specify multiple handlers.
5772 fn: this.onMouseOver,
5776 fn: this.onMouseOut,
5782 * Or a shorthand syntax which passes the same scope object to all handlers:
5785 'click': this.onClick,
5786 'mouseover': this.onMouseOver,
5787 'mouseout': this.onMouseOut,
5792 addListener : function(eventName, fn, scope, o){
5793 if(typeof eventName == "object"){
5796 if(this.filterOptRe.test(e)){
5799 if(typeof o[e] == "function"){
5801 this.addListener(e, o[e], o.scope, o);
5803 // individual options
5804 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5809 o = (!o || typeof o == "boolean") ? {} : o;
5810 eventName = eventName.toLowerCase();
5811 var ce = this.events[eventName] || true;
5812 if(typeof ce == "boolean"){
5813 ce = new Roo.util.Event(this, eventName);
5814 this.events[eventName] = ce;
5816 ce.addListener(fn, scope, o);
5820 * Removes a listener
5821 * @param {String} eventName The type of event to listen for
5822 * @param {Function} handler The handler to remove
5823 * @param {Object} scope (optional) The scope (this object) for the handler
5825 removeListener : function(eventName, fn, scope){
5826 var ce = this.events[eventName.toLowerCase()];
5827 if(typeof ce == "object"){
5828 ce.removeListener(fn, scope);
5833 * Removes all listeners for this object
5835 purgeListeners : function(){
5836 for(var evt in this.events){
5837 if(typeof this.events[evt] == "object"){
5838 this.events[evt].clearListeners();
5843 relayEvents : function(o, events){
5844 var createHandler = function(ename){
5846 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5849 for(var i = 0, len = events.length; i < len; i++){
5850 var ename = events[i];
5851 if(!this.events[ename]){ this.events[ename] = true; };
5852 o.on(ename, createHandler(ename), this);
5857 * Used to define events on this Observable
5858 * @param {Object} object The object with the events defined
5860 addEvents : function(o){
5864 Roo.applyIf(this.events, o);
5868 * Checks to see if this object has any listeners for a specified event
5869 * @param {String} eventName The name of the event to check for
5870 * @return {Boolean} True if the event is being listened for, else false
5872 hasListener : function(eventName){
5873 var e = this.events[eventName];
5874 return typeof e == "object" && e.listeners.length > 0;
5878 * Appends an event handler to this element (shorthand for addListener)
5879 * @param {String} eventName The type of event to listen for
5880 * @param {Function} handler The method the event invokes
5881 * @param {Object} scope (optional) The scope in which to execute the handler
5882 * function. The handler function's "this" context.
5883 * @param {Object} options (optional)
5886 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5888 * Removes a listener (shorthand for removeListener)
5889 * @param {String} eventName The type of event to listen for
5890 * @param {Function} handler The handler to remove
5891 * @param {Object} scope (optional) The scope (this object) for the handler
5894 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5897 * Starts capture on the specified Observable. All events will be passed
5898 * to the supplied function with the event name + standard signature of the event
5899 * <b>before</b> the event is fired. If the supplied function returns false,
5900 * the event will not fire.
5901 * @param {Observable} o The Observable to capture
5902 * @param {Function} fn The function to call
5903 * @param {Object} scope (optional) The scope (this object) for the fn
5906 Roo.util.Observable.capture = function(o, fn, scope){
5907 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5911 * Removes <b>all</b> added captures from the Observable.
5912 * @param {Observable} o The Observable to release
5915 Roo.util.Observable.releaseCapture = function(o){
5916 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5921 var createBuffered = function(h, o, scope){
5922 var task = new Roo.util.DelayedTask();
5924 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5928 var createSingle = function(h, e, fn, scope){
5930 e.removeListener(fn, scope);
5931 return h.apply(scope, arguments);
5935 var createDelayed = function(h, o, scope){
5937 var args = Array.prototype.slice.call(arguments, 0);
5938 setTimeout(function(){
5939 h.apply(scope, args);
5944 Roo.util.Event = function(obj, name){
5947 this.listeners = [];
5950 Roo.util.Event.prototype = {
5951 addListener : function(fn, scope, options){
5952 var o = options || {};
5953 scope = scope || this.obj;
5954 if(!this.isListening(fn, scope)){
5955 var l = {fn: fn, scope: scope, options: o};
5958 h = createDelayed(h, o, scope);
5961 h = createSingle(h, this, fn, scope);
5964 h = createBuffered(h, o, scope);
5967 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5968 this.listeners.push(l);
5970 this.listeners = this.listeners.slice(0);
5971 this.listeners.push(l);
5976 findListener : function(fn, scope){
5977 scope = scope || this.obj;
5978 var ls = this.listeners;
5979 for(var i = 0, len = ls.length; i < len; i++){
5981 if(l.fn == fn && l.scope == scope){
5988 isListening : function(fn, scope){
5989 return this.findListener(fn, scope) != -1;
5992 removeListener : function(fn, scope){
5994 if((index = this.findListener(fn, scope)) != -1){
5996 this.listeners.splice(index, 1);
5998 this.listeners = this.listeners.slice(0);
5999 this.listeners.splice(index, 1);
6006 clearListeners : function(){
6007 this.listeners = [];
6011 var ls = this.listeners, scope, len = ls.length;
6014 var args = Array.prototype.slice.call(arguments, 0);
6015 for(var i = 0; i < len; i++){
6017 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6018 this.firing = false;
6022 this.firing = false;
6029 * Ext JS Library 1.1.1
6030 * Copyright(c) 2006-2007, Ext JS, LLC.
6032 * Originally Released Under LGPL - original licence link has changed is not relivant.
6035 * <script type="text/javascript">
6039 * @class Roo.EventManager
6040 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6041 * several useful events directly.
6042 * See {@link Roo.EventObject} for more details on normalized event objects.
6045 Roo.EventManager = function(){
6046 var docReadyEvent, docReadyProcId, docReadyState = false;
6047 var resizeEvent, resizeTask, textEvent, textSize;
6048 var E = Roo.lib.Event;
6049 var D = Roo.lib.Dom;
6052 var fireDocReady = function(){
6054 docReadyState = true;
6057 clearInterval(docReadyProcId);
6059 if(Roo.isGecko || Roo.isOpera) {
6060 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6063 var defer = document.getElementById("ie-deferred-loader");
6065 defer.onreadystatechange = null;
6066 defer.parentNode.removeChild(defer);
6070 docReadyEvent.fire();
6071 docReadyEvent.clearListeners();
6076 var initDocReady = function(){
6077 docReadyEvent = new Roo.util.Event();
6078 if(Roo.isGecko || Roo.isOpera) {
6079 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6081 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6082 var defer = document.getElementById("ie-deferred-loader");
6083 defer.onreadystatechange = function(){
6084 if(this.readyState == "complete"){
6088 }else if(Roo.isSafari){
6089 docReadyProcId = setInterval(function(){
6090 var rs = document.readyState;
6091 if(rs == "complete") {
6096 // no matter what, make sure it fires on load
6097 E.on(window, "load", fireDocReady);
6100 var createBuffered = function(h, o){
6101 var task = new Roo.util.DelayedTask(h);
6103 // create new event object impl so new events don't wipe out properties
6104 e = new Roo.EventObjectImpl(e);
6105 task.delay(o.buffer, h, null, [e]);
6109 var createSingle = function(h, el, ename, fn){
6111 Roo.EventManager.removeListener(el, ename, fn);
6116 var createDelayed = function(h, o){
6118 // create new event object impl so new events don't wipe out properties
6119 e = new Roo.EventObjectImpl(e);
6120 setTimeout(function(){
6126 var listen = function(element, ename, opt, fn, scope){
6127 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6128 fn = fn || o.fn; scope = scope || o.scope;
6129 var el = Roo.getDom(element);
6131 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6133 var h = function(e){
6134 e = Roo.EventObject.setEvent(e);
6137 t = e.getTarget(o.delegate, el);
6144 if(o.stopEvent === true){
6147 if(o.preventDefault === true){
6150 if(o.stopPropagation === true){
6151 e.stopPropagation();
6154 if(o.normalized === false){
6158 fn.call(scope || el, e, t, o);
6161 h = createDelayed(h, o);
6164 h = createSingle(h, el, ename, fn);
6167 h = createBuffered(h, o);
6169 fn._handlers = fn._handlers || [];
6170 fn._handlers.push([Roo.id(el), ename, h]);
6173 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6174 el.addEventListener("DOMMouseScroll", h, false);
6175 E.on(window, 'unload', function(){
6176 el.removeEventListener("DOMMouseScroll", h, false);
6179 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6180 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6185 var stopListening = function(el, ename, fn){
6186 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6188 for(var i = 0, len = hds.length; i < len; i++){
6190 if(h[0] == id && h[1] == ename){
6197 E.un(el, ename, hd);
6198 el = Roo.getDom(el);
6199 if(ename == "mousewheel" && el.addEventListener){
6200 el.removeEventListener("DOMMouseScroll", hd, false);
6202 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6203 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6207 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6214 * @scope Roo.EventManager
6219 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6220 * object with a Roo.EventObject
6221 * @param {Function} fn The method the event invokes
6222 * @param {Object} scope An object that becomes the scope of the handler
6223 * @param {boolean} override If true, the obj passed in becomes
6224 * the execution scope of the listener
6225 * @return {Function} The wrapped function
6228 wrap : function(fn, scope, override){
6230 Roo.EventObject.setEvent(e);
6231 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6236 * Appends an event handler to an element (shorthand for addListener)
6237 * @param {String/HTMLElement} element The html element or id to assign the
6238 * @param {String} eventName The type of event to listen for
6239 * @param {Function} handler The method the event invokes
6240 * @param {Object} scope (optional) The scope in which to execute the handler
6241 * function. The handler function's "this" context.
6242 * @param {Object} options (optional) An object containing handler configuration
6243 * properties. This may contain any of the following properties:<ul>
6244 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6245 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6246 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6247 * <li>preventDefault {Boolean} True to prevent the default action</li>
6248 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6249 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6250 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6251 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6252 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6253 * by the specified number of milliseconds. If the event fires again within that time, the original
6254 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6257 * <b>Combining Options</b><br>
6258 * Using the options argument, it is possible to combine different types of listeners:<br>
6260 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6262 el.on('click', this.onClick, this, {
6269 * <b>Attaching multiple handlers in 1 call</b><br>
6270 * The method also allows for a single argument to be passed which is a config object containing properties
6271 * which specify multiple handlers.
6281 fn: this.onMouseOver
6290 * Or a shorthand syntax:<br>
6293 'click' : this.onClick,
6294 'mouseover' : this.onMouseOver,
6295 'mouseout' : this.onMouseOut
6299 addListener : function(element, eventName, fn, scope, options){
6300 if(typeof eventName == "object"){
6306 if(typeof o[e] == "function"){
6308 listen(element, e, o, o[e], o.scope);
6310 // individual options
6311 listen(element, e, o[e]);
6316 return listen(element, eventName, options, fn, scope);
6320 * Removes an event handler
6322 * @param {String/HTMLElement} element The id or html element to remove the
6324 * @param {String} eventName The type of event
6325 * @param {Function} fn
6326 * @return {Boolean} True if a listener was actually removed
6328 removeListener : function(element, eventName, fn){
6329 return stopListening(element, eventName, fn);
6333 * Fires when the document is ready (before onload and before images are loaded). Can be
6334 * accessed shorthanded Roo.onReady().
6335 * @param {Function} fn The method the event invokes
6336 * @param {Object} scope An object that becomes the scope of the handler
6337 * @param {boolean} options
6339 onDocumentReady : function(fn, scope, options){
6340 if(docReadyState){ // if it already fired
6341 docReadyEvent.addListener(fn, scope, options);
6342 docReadyEvent.fire();
6343 docReadyEvent.clearListeners();
6349 docReadyEvent.addListener(fn, scope, options);
6353 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6354 * @param {Function} fn The method the event invokes
6355 * @param {Object} scope An object that becomes the scope of the handler
6356 * @param {boolean} options
6358 onWindowResize : function(fn, scope, options){
6360 resizeEvent = new Roo.util.Event();
6361 resizeTask = new Roo.util.DelayedTask(function(){
6362 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6364 E.on(window, "resize", function(){
6366 resizeTask.delay(50);
6368 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6372 resizeEvent.addListener(fn, scope, options);
6376 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6377 * @param {Function} fn The method the event invokes
6378 * @param {Object} scope An object that becomes the scope of the handler
6379 * @param {boolean} options
6381 onTextResize : function(fn, scope, options){
6383 textEvent = new Roo.util.Event();
6384 var textEl = new Roo.Element(document.createElement('div'));
6385 textEl.dom.className = 'x-text-resize';
6386 textEl.dom.innerHTML = 'X';
6387 textEl.appendTo(document.body);
6388 textSize = textEl.dom.offsetHeight;
6389 setInterval(function(){
6390 if(textEl.dom.offsetHeight != textSize){
6391 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6393 }, this.textResizeInterval);
6395 textEvent.addListener(fn, scope, options);
6399 * Removes the passed window resize listener.
6400 * @param {Function} fn The method the event invokes
6401 * @param {Object} scope The scope of handler
6403 removeResizeListener : function(fn, scope){
6405 resizeEvent.removeListener(fn, scope);
6410 fireResize : function(){
6412 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6416 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6420 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6422 textResizeInterval : 50
6427 * @scopeAlias pub=Roo.EventManager
6431 * Appends an event handler to an element (shorthand for addListener)
6432 * @param {String/HTMLElement} element The html element or id to assign the
6433 * @param {String} eventName The type of event to listen for
6434 * @param {Function} handler The method the event invokes
6435 * @param {Object} scope (optional) The scope in which to execute the handler
6436 * function. The handler function's "this" context.
6437 * @param {Object} options (optional) An object containing handler configuration
6438 * properties. This may contain any of the following properties:<ul>
6439 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6440 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6441 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6442 * <li>preventDefault {Boolean} True to prevent the default action</li>
6443 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6444 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6445 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6446 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6447 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6448 * by the specified number of milliseconds. If the event fires again within that time, the original
6449 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6452 * <b>Combining Options</b><br>
6453 * Using the options argument, it is possible to combine different types of listeners:<br>
6455 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6457 el.on('click', this.onClick, this, {
6464 * <b>Attaching multiple handlers in 1 call</b><br>
6465 * The method also allows for a single argument to be passed which is a config object containing properties
6466 * which specify multiple handlers.
6476 fn: this.onMouseOver
6485 * Or a shorthand syntax:<br>
6488 'click' : this.onClick,
6489 'mouseover' : this.onMouseOver,
6490 'mouseout' : this.onMouseOut
6494 pub.on = pub.addListener;
6495 pub.un = pub.removeListener;
6497 pub.stoppedMouseDownEvent = new Roo.util.Event();
6501 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6502 * @param {Function} fn The method the event invokes
6503 * @param {Object} scope An object that becomes the scope of the handler
6504 * @param {boolean} override If true, the obj passed in becomes
6505 * the execution scope of the listener
6509 Roo.onReady = Roo.EventManager.onDocumentReady;
6511 Roo.onReady(function(){
6512 var bd = Roo.get(document.body);
6517 : Roo.isGecko ? "roo-gecko"
6518 : Roo.isOpera ? "roo-opera"
6519 : Roo.isSafari ? "roo-safari" : ""];
6522 cls.push("roo-mac");
6525 cls.push("roo-linux");
6527 if(Roo.isBorderBox){
6528 cls.push('roo-border-box');
6530 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6531 var p = bd.dom.parentNode;
6533 p.className += ' roo-strict';
6536 bd.addClass(cls.join(' '));
6540 * @class Roo.EventObject
6541 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6542 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6545 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6547 var target = e.getTarget();
6550 var myDiv = Roo.get("myDiv");
6551 myDiv.on("click", handleClick);
6553 Roo.EventManager.on("myDiv", 'click', handleClick);
6554 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6558 Roo.EventObject = function(){
6560 var E = Roo.lib.Event;
6562 // safari keypress events for special keys return bad keycodes
6565 63235 : 39, // right
6568 63276 : 33, // page up
6569 63277 : 34, // page down
6570 63272 : 46, // delete
6575 // normalize button clicks
6576 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6577 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6579 Roo.EventObjectImpl = function(e){
6581 this.setEvent(e.browserEvent || e);
6584 Roo.EventObjectImpl.prototype = {
6586 * Used to fix doc tools.
6587 * @scope Roo.EventObject.prototype
6593 /** The normal browser event */
6594 browserEvent : null,
6595 /** The button pressed in a mouse event */
6597 /** True if the shift key was down during the event */
6599 /** True if the control key was down during the event */
6601 /** True if the alt key was down during the event */
6660 setEvent : function(e){
6661 if(e == this || (e && e.browserEvent)){ // already wrapped
6664 this.browserEvent = e;
6666 // normalize buttons
6667 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6668 if(e.type == 'click' && this.button == -1){
6672 this.shiftKey = e.shiftKey;
6673 // mac metaKey behaves like ctrlKey
6674 this.ctrlKey = e.ctrlKey || e.metaKey;
6675 this.altKey = e.altKey;
6676 // in getKey these will be normalized for the mac
6677 this.keyCode = e.keyCode;
6678 // keyup warnings on firefox.
6679 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6680 // cache the target for the delayed and or buffered events
6681 this.target = E.getTarget(e);
6683 this.xy = E.getXY(e);
6686 this.shiftKey = false;
6687 this.ctrlKey = false;
6688 this.altKey = false;
6698 * Stop the event (preventDefault and stopPropagation)
6700 stopEvent : function(){
6701 if(this.browserEvent){
6702 if(this.browserEvent.type == 'mousedown'){
6703 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6705 E.stopEvent(this.browserEvent);
6710 * Prevents the browsers default handling of the event.
6712 preventDefault : function(){
6713 if(this.browserEvent){
6714 E.preventDefault(this.browserEvent);
6719 isNavKeyPress : function(){
6720 var k = this.keyCode;
6721 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6722 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6725 isSpecialKey : function(){
6726 var k = this.keyCode;
6727 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6728 (k == 16) || (k == 17) ||
6729 (k >= 18 && k <= 20) ||
6730 (k >= 33 && k <= 35) ||
6731 (k >= 36 && k <= 39) ||
6732 (k >= 44 && k <= 45);
6735 * Cancels bubbling of the event.
6737 stopPropagation : function(){
6738 if(this.browserEvent){
6739 if(this.type == 'mousedown'){
6740 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6742 E.stopPropagation(this.browserEvent);
6747 * Gets the key code for the event.
6750 getCharCode : function(){
6751 return this.charCode || this.keyCode;
6755 * Returns a normalized keyCode for the event.
6756 * @return {Number} The key code
6758 getKey : function(){
6759 var k = this.keyCode || this.charCode;
6760 return Roo.isSafari ? (safariKeys[k] || k) : k;
6764 * Gets the x coordinate of the event.
6767 getPageX : function(){
6772 * Gets the y coordinate of the event.
6775 getPageY : function(){
6780 * Gets the time of the event.
6783 getTime : function(){
6784 if(this.browserEvent){
6785 return E.getTime(this.browserEvent);
6791 * Gets the page coordinates of the event.
6792 * @return {Array} The xy values like [x, y]
6799 * Gets the target for the event.
6800 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6801 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6802 search as a number or element (defaults to 10 || document.body)
6803 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6804 * @return {HTMLelement}
6806 getTarget : function(selector, maxDepth, returnEl){
6807 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6810 * Gets the related target.
6811 * @return {HTMLElement}
6813 getRelatedTarget : function(){
6814 if(this.browserEvent){
6815 return E.getRelatedTarget(this.browserEvent);
6821 * Normalizes mouse wheel delta across browsers
6822 * @return {Number} The delta
6824 getWheelDelta : function(){
6825 var e = this.browserEvent;
6827 if(e.wheelDelta){ /* IE/Opera. */
6828 delta = e.wheelDelta/120;
6829 }else if(e.detail){ /* Mozilla case. */
6830 delta = -e.detail/3;
6836 * Returns true if the control, meta, shift or alt key was pressed during this event.
6839 hasModifier : function(){
6840 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6844 * Returns true if the target of this event equals el or is a child of el
6845 * @param {String/HTMLElement/Element} el
6846 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6849 within : function(el, related){
6850 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6851 return t && Roo.fly(el).contains(t);
6854 getPoint : function(){
6855 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6859 return new Roo.EventObjectImpl();
6864 * Ext JS Library 1.1.1
6865 * Copyright(c) 2006-2007, Ext JS, LLC.
6867 * Originally Released Under LGPL - original licence link has changed is not relivant.
6870 * <script type="text/javascript">
6874 // was in Composite Element!??!?!
6877 var D = Roo.lib.Dom;
6878 var E = Roo.lib.Event;
6879 var A = Roo.lib.Anim;
6881 // local style camelizing for speed
6883 var camelRe = /(-[a-z])/gi;
6884 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6885 var view = document.defaultView;
6888 * @class Roo.Element
6889 * Represents an Element in the DOM.<br><br>
6892 var el = Roo.get("my-div");
6895 var el = getEl("my-div");
6897 // or with a DOM element
6898 var el = Roo.get(myDivElement);
6900 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6901 * each call instead of constructing a new one.<br><br>
6902 * <b>Animations</b><br />
6903 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6904 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6906 Option Default Description
6907 --------- -------- ---------------------------------------------
6908 duration .35 The duration of the animation in seconds
6909 easing easeOut The YUI easing method
6910 callback none A function to execute when the anim completes
6911 scope this The scope (this) of the callback function
6913 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6914 * manipulate the animation. Here's an example:
6916 var el = Roo.get("my-div");
6921 // default animation
6922 el.setWidth(100, true);
6924 // animation with some options set
6931 // using the "anim" property to get the Anim object
6937 el.setWidth(100, opt);
6939 if(opt.anim.isAnimated()){
6943 * <b> Composite (Collections of) Elements</b><br />
6944 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6945 * @constructor Create a new Element directly.
6946 * @param {String/HTMLElement} element
6947 * @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).
6949 Roo.Element = function(element, forceNew){
6950 var dom = typeof element == "string" ?
6951 document.getElementById(element) : element;
6952 if(!dom){ // invalid id/element
6956 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6957 return Roo.Element.cache[id];
6967 * The DOM element ID
6970 this.id = id || Roo.id(dom);
6973 var El = Roo.Element;
6977 * The element's default display mode (defaults to "")
6980 originalDisplay : "",
6984 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6989 * Sets the element's visibility mode. When setVisible() is called it
6990 * will use this to determine whether to set the visibility or the display property.
6991 * @param visMode Element.VISIBILITY or Element.DISPLAY
6992 * @return {Roo.Element} this
6994 setVisibilityMode : function(visMode){
6995 this.visibilityMode = visMode;
6999 * Convenience method for setVisibilityMode(Element.DISPLAY)
7000 * @param {String} display (optional) What to set display to when visible
7001 * @return {Roo.Element} this
7003 enableDisplayMode : function(display){
7004 this.setVisibilityMode(El.DISPLAY);
7005 if(typeof display != "undefined") this.originalDisplay = display;
7010 * 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)
7011 * @param {String} selector The simple selector to test
7012 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7013 search as a number or element (defaults to 10 || document.body)
7014 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7015 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7017 findParent : function(simpleSelector, maxDepth, returnEl){
7018 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7019 maxDepth = maxDepth || 50;
7020 if(typeof maxDepth != "number"){
7021 stopEl = Roo.getDom(maxDepth);
7024 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7025 if(dq.is(p, simpleSelector)){
7026 return returnEl ? Roo.get(p) : p;
7036 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7037 * @param {String} selector The simple selector to test
7038 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7039 search as a number or element (defaults to 10 || document.body)
7040 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7041 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7043 findParentNode : function(simpleSelector, maxDepth, returnEl){
7044 var p = Roo.fly(this.dom.parentNode, '_internal');
7045 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7049 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7050 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7051 * @param {String} selector The simple selector to test
7052 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7053 search as a number or element (defaults to 10 || document.body)
7054 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7056 up : function(simpleSelector, maxDepth){
7057 return this.findParentNode(simpleSelector, maxDepth, true);
7063 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7064 * @param {String} selector The simple selector to test
7065 * @return {Boolean} True if this element matches the selector, else false
7067 is : function(simpleSelector){
7068 return Roo.DomQuery.is(this.dom, simpleSelector);
7072 * Perform animation on this element.
7073 * @param {Object} args The YUI animation control args
7074 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7075 * @param {Function} onComplete (optional) Function to call when animation completes
7076 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7077 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7078 * @return {Roo.Element} this
7080 animate : function(args, duration, onComplete, easing, animType){
7081 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7086 * @private Internal animation call
7088 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7089 animType = animType || 'run';
7091 var anim = Roo.lib.Anim[animType](
7093 (opt.duration || defaultDur) || .35,
7094 (opt.easing || defaultEase) || 'easeOut',
7096 Roo.callback(cb, this);
7097 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7105 // private legacy anim prep
7106 preanim : function(a, i){
7107 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7111 * Removes worthless text nodes
7112 * @param {Boolean} forceReclean (optional) By default the element
7113 * keeps track if it has been cleaned already so
7114 * you can call this over and over. However, if you update the element and
7115 * need to force a reclean, you can pass true.
7117 clean : function(forceReclean){
7118 if(this.isCleaned && forceReclean !== true){
7122 var d = this.dom, n = d.firstChild, ni = -1;
7124 var nx = n.nextSibling;
7125 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7132 this.isCleaned = true;
7137 calcOffsetsTo : function(el){
7140 var restorePos = false;
7141 if(el.getStyle('position') == 'static'){
7142 el.position('relative');
7147 while(op && op != d && op.tagName != 'HTML'){
7150 op = op.offsetParent;
7153 el.position('static');
7159 * Scrolls this element into view within the passed container.
7160 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7161 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7162 * @return {Roo.Element} this
7164 scrollIntoView : function(container, hscroll){
7165 var c = Roo.getDom(container) || document.body;
7168 var o = this.calcOffsetsTo(c),
7171 b = t+el.offsetHeight,
7172 r = l+el.offsetWidth;
7174 var ch = c.clientHeight;
7175 var ct = parseInt(c.scrollTop, 10);
7176 var cl = parseInt(c.scrollLeft, 10);
7178 var cr = cl + c.clientWidth;
7186 if(hscroll !== false){
7190 c.scrollLeft = r-c.clientWidth;
7197 scrollChildIntoView : function(child, hscroll){
7198 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7202 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7203 * the new height may not be available immediately.
7204 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7205 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7206 * @param {Function} onComplete (optional) Function to call when animation completes
7207 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7208 * @return {Roo.Element} this
7210 autoHeight : function(animate, duration, onComplete, easing){
7211 var oldHeight = this.getHeight();
7213 this.setHeight(1); // force clipping
7214 setTimeout(function(){
7215 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7217 this.setHeight(height);
7219 if(typeof onComplete == "function"){
7223 this.setHeight(oldHeight); // restore original height
7224 this.setHeight(height, animate, duration, function(){
7226 if(typeof onComplete == "function") onComplete();
7227 }.createDelegate(this), easing);
7229 }.createDelegate(this), 0);
7234 * Returns true if this element is an ancestor of the passed element
7235 * @param {HTMLElement/String} el The element to check
7236 * @return {Boolean} True if this element is an ancestor of el, else false
7238 contains : function(el){
7239 if(!el){return false;}
7240 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7244 * Checks whether the element is currently visible using both visibility and display properties.
7245 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7246 * @return {Boolean} True if the element is currently visible, else false
7248 isVisible : function(deep) {
7249 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7250 if(deep !== true || !vis){
7253 var p = this.dom.parentNode;
7254 while(p && p.tagName.toLowerCase() != "body"){
7255 if(!Roo.fly(p, '_isVisible').isVisible()){
7264 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7265 * @param {String} selector The CSS selector
7266 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7267 * @return {CompositeElement/CompositeElementLite} The composite element
7269 select : function(selector, unique){
7270 return El.select(selector, unique, this.dom);
7274 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7275 * @param {String} selector The CSS selector
7276 * @return {Array} An array of the matched nodes
7278 query : function(selector, unique){
7279 return Roo.DomQuery.select(selector, this.dom);
7283 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7284 * @param {String} selector The CSS selector
7285 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7286 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7288 child : function(selector, returnDom){
7289 var n = Roo.DomQuery.selectNode(selector, this.dom);
7290 return returnDom ? n : Roo.get(n);
7294 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7295 * @param {String} selector The CSS selector
7296 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7297 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7299 down : function(selector, returnDom){
7300 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7301 return returnDom ? n : Roo.get(n);
7305 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7306 * @param {String} group The group the DD object is member of
7307 * @param {Object} config The DD config object
7308 * @param {Object} overrides An object containing methods to override/implement on the DD object
7309 * @return {Roo.dd.DD} The DD object
7311 initDD : function(group, config, overrides){
7312 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7313 return Roo.apply(dd, overrides);
7317 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7318 * @param {String} group The group the DDProxy object is member of
7319 * @param {Object} config The DDProxy config object
7320 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7321 * @return {Roo.dd.DDProxy} The DDProxy object
7323 initDDProxy : function(group, config, overrides){
7324 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7325 return Roo.apply(dd, overrides);
7329 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7330 * @param {String} group The group the DDTarget object is member of
7331 * @param {Object} config The DDTarget config object
7332 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7333 * @return {Roo.dd.DDTarget} The DDTarget object
7335 initDDTarget : function(group, config, overrides){
7336 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7337 return Roo.apply(dd, overrides);
7341 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7342 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7343 * @param {Boolean} visible Whether the element is visible
7344 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7345 * @return {Roo.Element} this
7347 setVisible : function(visible, animate){
7349 if(this.visibilityMode == El.DISPLAY){
7350 this.setDisplayed(visible);
7353 this.dom.style.visibility = visible ? "visible" : "hidden";
7356 // closure for composites
7358 var visMode = this.visibilityMode;
7360 this.setOpacity(.01);
7361 this.setVisible(true);
7363 this.anim({opacity: { to: (visible?1:0) }},
7364 this.preanim(arguments, 1),
7365 null, .35, 'easeIn', function(){
7367 if(visMode == El.DISPLAY){
7368 dom.style.display = "none";
7370 dom.style.visibility = "hidden";
7372 Roo.get(dom).setOpacity(1);
7380 * Returns true if display is not "none"
7383 isDisplayed : function() {
7384 return this.getStyle("display") != "none";
7388 * Toggles the element's visibility or display, depending on visibility mode.
7389 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7390 * @return {Roo.Element} this
7392 toggle : function(animate){
7393 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7398 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7399 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7400 * @return {Roo.Element} this
7402 setDisplayed : function(value) {
7403 if(typeof value == "boolean"){
7404 value = value ? this.originalDisplay : "none";
7406 this.setStyle("display", value);
7411 * Tries to focus the element. Any exceptions are caught and ignored.
7412 * @return {Roo.Element} this
7414 focus : function() {
7422 * Tries to blur the element. Any exceptions are caught and ignored.
7423 * @return {Roo.Element} this
7433 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7434 * @param {String/Array} className The CSS class to add, or an array of classes
7435 * @return {Roo.Element} this
7437 addClass : function(className){
7438 if(className instanceof Array){
7439 for(var i = 0, len = className.length; i < len; i++) {
7440 this.addClass(className[i]);
7443 if(className && !this.hasClass(className)){
7444 this.dom.className = this.dom.className + " " + className;
7451 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7452 * @param {String/Array} className The CSS class to add, or an array of classes
7453 * @return {Roo.Element} this
7455 radioClass : function(className){
7456 var siblings = this.dom.parentNode.childNodes;
7457 for(var i = 0; i < siblings.length; i++) {
7458 var s = siblings[i];
7459 if(s.nodeType == 1){
7460 Roo.get(s).removeClass(className);
7463 this.addClass(className);
7468 * Removes one or more CSS classes from the element.
7469 * @param {String/Array} className The CSS class to remove, or an array of classes
7470 * @return {Roo.Element} this
7472 removeClass : function(className){
7473 if(!className || !this.dom.className){
7476 if(className instanceof Array){
7477 for(var i = 0, len = className.length; i < len; i++) {
7478 this.removeClass(className[i]);
7481 if(this.hasClass(className)){
7482 var re = this.classReCache[className];
7484 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7485 this.classReCache[className] = re;
7487 this.dom.className =
7488 this.dom.className.replace(re, " ");
7498 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7499 * @param {String} className The CSS class to toggle
7500 * @return {Roo.Element} this
7502 toggleClass : function(className){
7503 if(this.hasClass(className)){
7504 this.removeClass(className);
7506 this.addClass(className);
7512 * Checks if the specified CSS class exists on this element's DOM node.
7513 * @param {String} className The CSS class to check for
7514 * @return {Boolean} True if the class exists, else false
7516 hasClass : function(className){
7517 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7521 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7522 * @param {String} oldClassName The CSS class to replace
7523 * @param {String} newClassName The replacement CSS class
7524 * @return {Roo.Element} this
7526 replaceClass : function(oldClassName, newClassName){
7527 this.removeClass(oldClassName);
7528 this.addClass(newClassName);
7533 * Returns an object with properties matching the styles requested.
7534 * For example, el.getStyles('color', 'font-size', 'width') might return
7535 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7536 * @param {String} style1 A style name
7537 * @param {String} style2 A style name
7538 * @param {String} etc.
7539 * @return {Object} The style object
7541 getStyles : function(){
7542 var a = arguments, len = a.length, r = {};
7543 for(var i = 0; i < len; i++){
7544 r[a[i]] = this.getStyle(a[i]);
7550 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7551 * @param {String} property The style property whose value is returned.
7552 * @return {String} The current value of the style property for this element.
7554 getStyle : function(){
7555 return view && view.getComputedStyle ?
7557 var el = this.dom, v, cs, camel;
7558 if(prop == 'float'){
7561 if(el.style && (v = el.style[prop])){
7564 if(cs = view.getComputedStyle(el, "")){
7565 if(!(camel = propCache[prop])){
7566 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7573 var el = this.dom, v, cs, camel;
7574 if(prop == 'opacity'){
7575 if(typeof el.style.filter == 'string'){
7576 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7578 var fv = parseFloat(m[1]);
7580 return fv ? fv / 100 : 0;
7585 }else if(prop == 'float'){
7586 prop = "styleFloat";
7588 if(!(camel = propCache[prop])){
7589 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7591 if(v = el.style[camel]){
7594 if(cs = el.currentStyle){
7602 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7603 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7604 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7605 * @return {Roo.Element} this
7607 setStyle : function(prop, value){
7608 if(typeof prop == "string"){
7610 if (prop == 'float') {
7611 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7616 if(!(camel = propCache[prop])){
7617 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7620 if(camel == 'opacity') {
7621 this.setOpacity(value);
7623 this.dom.style[camel] = value;
7626 for(var style in prop){
7627 if(typeof prop[style] != "function"){
7628 this.setStyle(style, prop[style]);
7636 * More flexible version of {@link #setStyle} for setting style properties.
7637 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7638 * a function which returns such a specification.
7639 * @return {Roo.Element} this
7641 applyStyles : function(style){
7642 Roo.DomHelper.applyStyles(this.dom, style);
7647 * 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).
7648 * @return {Number} The X position of the element
7651 return D.getX(this.dom);
7655 * 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).
7656 * @return {Number} The Y position of the element
7659 return D.getY(this.dom);
7663 * 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).
7664 * @return {Array} The XY position of the element
7667 return D.getXY(this.dom);
7671 * 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).
7672 * @param {Number} The X position of the element
7673 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7674 * @return {Roo.Element} this
7676 setX : function(x, animate){
7678 D.setX(this.dom, x);
7680 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7686 * 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).
7687 * @param {Number} The Y position of the element
7688 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7689 * @return {Roo.Element} this
7691 setY : function(y, animate){
7693 D.setY(this.dom, y);
7695 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7701 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7702 * @param {String} left The left CSS property value
7703 * @return {Roo.Element} this
7705 setLeft : function(left){
7706 this.setStyle("left", this.addUnits(left));
7711 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7712 * @param {String} top The top CSS property value
7713 * @return {Roo.Element} this
7715 setTop : function(top){
7716 this.setStyle("top", this.addUnits(top));
7721 * Sets the element's CSS right style.
7722 * @param {String} right The right CSS property value
7723 * @return {Roo.Element} this
7725 setRight : function(right){
7726 this.setStyle("right", this.addUnits(right));
7731 * Sets the element's CSS bottom style.
7732 * @param {String} bottom The bottom CSS property value
7733 * @return {Roo.Element} this
7735 setBottom : function(bottom){
7736 this.setStyle("bottom", this.addUnits(bottom));
7741 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7742 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7743 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7744 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7745 * @return {Roo.Element} this
7747 setXY : function(pos, animate){
7749 D.setXY(this.dom, pos);
7751 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7757 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7758 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7759 * @param {Number} x X value for new position (coordinates are page-based)
7760 * @param {Number} y Y value for new position (coordinates are page-based)
7761 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7762 * @return {Roo.Element} this
7764 setLocation : function(x, y, animate){
7765 this.setXY([x, y], this.preanim(arguments, 2));
7770 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7771 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7772 * @param {Number} x X value for new position (coordinates are page-based)
7773 * @param {Number} y Y value for new position (coordinates are page-based)
7774 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7775 * @return {Roo.Element} this
7777 moveTo : function(x, y, animate){
7778 this.setXY([x, y], this.preanim(arguments, 2));
7783 * Returns the region of the given element.
7784 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7785 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7787 getRegion : function(){
7788 return D.getRegion(this.dom);
7792 * Returns the offset height of the element
7793 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7794 * @return {Number} The element's height
7796 getHeight : function(contentHeight){
7797 var h = this.dom.offsetHeight || 0;
7798 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7802 * Returns the offset width of the element
7803 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7804 * @return {Number} The element's width
7806 getWidth : function(contentWidth){
7807 var w = this.dom.offsetWidth || 0;
7808 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7812 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7813 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7814 * if a height has not been set using CSS.
7817 getComputedHeight : function(){
7818 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7820 h = parseInt(this.getStyle('height'), 10) || 0;
7821 if(!this.isBorderBox()){
7822 h += this.getFrameWidth('tb');
7829 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7830 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7831 * if a width has not been set using CSS.
7834 getComputedWidth : function(){
7835 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7837 w = parseInt(this.getStyle('width'), 10) || 0;
7838 if(!this.isBorderBox()){
7839 w += this.getFrameWidth('lr');
7846 * Returns the size of the element.
7847 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7848 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7850 getSize : function(contentSize){
7851 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7855 * Returns the width and height of the viewport.
7856 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7858 getViewSize : function(){
7859 var d = this.dom, doc = document, aw = 0, ah = 0;
7860 if(d == doc || d == doc.body){
7861 return {width : D.getViewWidth(), height: D.getViewHeight()};
7864 width : d.clientWidth,
7865 height: d.clientHeight
7871 * Returns the value of the "value" attribute
7872 * @param {Boolean} asNumber true to parse the value as a number
7873 * @return {String/Number}
7875 getValue : function(asNumber){
7876 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7880 adjustWidth : function(width){
7881 if(typeof width == "number"){
7882 if(this.autoBoxAdjust && !this.isBorderBox()){
7883 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7893 adjustHeight : function(height){
7894 if(typeof height == "number"){
7895 if(this.autoBoxAdjust && !this.isBorderBox()){
7896 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7906 * Set the width of the element
7907 * @param {Number} width The new width
7908 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7909 * @return {Roo.Element} this
7911 setWidth : function(width, animate){
7912 width = this.adjustWidth(width);
7914 this.dom.style.width = this.addUnits(width);
7916 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7922 * Set the height of the element
7923 * @param {Number} height The new height
7924 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7925 * @return {Roo.Element} this
7927 setHeight : function(height, animate){
7928 height = this.adjustHeight(height);
7930 this.dom.style.height = this.addUnits(height);
7932 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7938 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7939 * @param {Number} width The new width
7940 * @param {Number} height The new height
7941 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7942 * @return {Roo.Element} this
7944 setSize : function(width, height, animate){
7945 if(typeof width == "object"){ // in case of object from getSize()
7946 height = width.height; width = width.width;
7948 width = this.adjustWidth(width); height = this.adjustHeight(height);
7950 this.dom.style.width = this.addUnits(width);
7951 this.dom.style.height = this.addUnits(height);
7953 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7959 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7960 * @param {Number} x X value for new position (coordinates are page-based)
7961 * @param {Number} y Y value for new position (coordinates are page-based)
7962 * @param {Number} width The new width
7963 * @param {Number} height The new height
7964 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7965 * @return {Roo.Element} this
7967 setBounds : function(x, y, width, height, animate){
7969 this.setSize(width, height);
7970 this.setLocation(x, y);
7972 width = this.adjustWidth(width); height = this.adjustHeight(height);
7973 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7974 this.preanim(arguments, 4), 'motion');
7980 * 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.
7981 * @param {Roo.lib.Region} region The region to fill
7982 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7983 * @return {Roo.Element} this
7985 setRegion : function(region, animate){
7986 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7991 * Appends an event handler
7993 * @param {String} eventName The type of event to append
7994 * @param {Function} fn The method the event invokes
7995 * @param {Object} scope (optional) The scope (this object) of the fn
7996 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7998 addListener : function(eventName, fn, scope, options){
8000 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8005 * Removes an event handler from this element
8006 * @param {String} eventName the type of event to remove
8007 * @param {Function} fn the method the event invokes
8008 * @return {Roo.Element} this
8010 removeListener : function(eventName, fn){
8011 Roo.EventManager.removeListener(this.dom, eventName, fn);
8016 * Removes all previous added listeners from this element
8017 * @return {Roo.Element} this
8019 removeAllListeners : function(){
8020 E.purgeElement(this.dom);
8024 relayEvent : function(eventName, observable){
8025 this.on(eventName, function(e){
8026 observable.fireEvent(eventName, e);
8031 * Set the opacity of the element
8032 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8033 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8034 * @return {Roo.Element} this
8036 setOpacity : function(opacity, animate){
8038 var s = this.dom.style;
8041 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8042 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8044 s.opacity = opacity;
8047 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8053 * Gets the left X coordinate
8054 * @param {Boolean} local True to get the local css position instead of page coordinate
8057 getLeft : function(local){
8061 return parseInt(this.getStyle("left"), 10) || 0;
8066 * Gets the right X coordinate of the element (element X position + element width)
8067 * @param {Boolean} local True to get the local css position instead of page coordinate
8070 getRight : function(local){
8072 return this.getX() + this.getWidth();
8074 return (this.getLeft(true) + this.getWidth()) || 0;
8079 * Gets the top Y coordinate
8080 * @param {Boolean} local True to get the local css position instead of page coordinate
8083 getTop : function(local) {
8087 return parseInt(this.getStyle("top"), 10) || 0;
8092 * Gets the bottom Y coordinate of the element (element Y position + element height)
8093 * @param {Boolean} local True to get the local css position instead of page coordinate
8096 getBottom : function(local){
8098 return this.getY() + this.getHeight();
8100 return (this.getTop(true) + this.getHeight()) || 0;
8105 * Initializes positioning on this element. If a desired position is not passed, it will make the
8106 * the element positioned relative IF it is not already positioned.
8107 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8108 * @param {Number} zIndex (optional) The zIndex to apply
8109 * @param {Number} x (optional) Set the page X position
8110 * @param {Number} y (optional) Set the page Y position
8112 position : function(pos, zIndex, x, y){
8114 if(this.getStyle('position') == 'static'){
8115 this.setStyle('position', 'relative');
8118 this.setStyle("position", pos);
8121 this.setStyle("z-index", zIndex);
8123 if(x !== undefined && y !== undefined){
8125 }else if(x !== undefined){
8127 }else if(y !== undefined){
8133 * Clear positioning back to the default when the document was loaded
8134 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8135 * @return {Roo.Element} this
8137 clearPositioning : function(value){
8145 "position" : "static"
8151 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8152 * snapshot before performing an update and then restoring the element.
8155 getPositioning : function(){
8156 var l = this.getStyle("left");
8157 var t = this.getStyle("top");
8159 "position" : this.getStyle("position"),
8161 "right" : l ? "" : this.getStyle("right"),
8163 "bottom" : t ? "" : this.getStyle("bottom"),
8164 "z-index" : this.getStyle("z-index")
8169 * Gets the width of the border(s) for the specified side(s)
8170 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8171 * passing lr would get the border (l)eft width + the border (r)ight width.
8172 * @return {Number} The width of the sides passed added together
8174 getBorderWidth : function(side){
8175 return this.addStyles(side, El.borders);
8179 * Gets the width of the padding(s) for the specified side(s)
8180 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8181 * passing lr would get the padding (l)eft + the padding (r)ight.
8182 * @return {Number} The padding of the sides passed added together
8184 getPadding : function(side){
8185 return this.addStyles(side, El.paddings);
8189 * Set positioning with an object returned by getPositioning().
8190 * @param {Object} posCfg
8191 * @return {Roo.Element} this
8193 setPositioning : function(pc){
8194 this.applyStyles(pc);
8195 if(pc.right == "auto"){
8196 this.dom.style.right = "";
8198 if(pc.bottom == "auto"){
8199 this.dom.style.bottom = "";
8205 fixDisplay : function(){
8206 if(this.getStyle("display") == "none"){
8207 this.setStyle("visibility", "hidden");
8208 this.setStyle("display", this.originalDisplay); // first try reverting to default
8209 if(this.getStyle("display") == "none"){ // if that fails, default to block
8210 this.setStyle("display", "block");
8216 * Quick set left and top adding default units
8217 * @param {String} left The left CSS property value
8218 * @param {String} top The top CSS property value
8219 * @return {Roo.Element} this
8221 setLeftTop : function(left, top){
8222 this.dom.style.left = this.addUnits(left);
8223 this.dom.style.top = this.addUnits(top);
8228 * Move this element relative to its current position.
8229 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8230 * @param {Number} distance How far to move the element in pixels
8231 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8232 * @return {Roo.Element} this
8234 move : function(direction, distance, animate){
8235 var xy = this.getXY();
8236 direction = direction.toLowerCase();
8240 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8244 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8249 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8254 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8261 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8262 * @return {Roo.Element} this
8265 if(!this.isClipped){
8266 this.isClipped = true;
8267 this.originalClip = {
8268 "o": this.getStyle("overflow"),
8269 "x": this.getStyle("overflow-x"),
8270 "y": this.getStyle("overflow-y")
8272 this.setStyle("overflow", "hidden");
8273 this.setStyle("overflow-x", "hidden");
8274 this.setStyle("overflow-y", "hidden");
8280 * Return clipping (overflow) to original clipping before clip() was called
8281 * @return {Roo.Element} this
8283 unclip : function(){
8285 this.isClipped = false;
8286 var o = this.originalClip;
8287 if(o.o){this.setStyle("overflow", o.o);}
8288 if(o.x){this.setStyle("overflow-x", o.x);}
8289 if(o.y){this.setStyle("overflow-y", o.y);}
8296 * Gets the x,y coordinates specified by the anchor position on the element.
8297 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8298 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8299 * {width: (target width), height: (target height)} (defaults to the element's current size)
8300 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8301 * @return {Array} [x, y] An array containing the element's x and y coordinates
8303 getAnchorXY : function(anchor, local, s){
8304 //Passing a different size is useful for pre-calculating anchors,
8305 //especially for anchored animations that change the el size.
8307 var w, h, vp = false;
8310 if(d == document.body || d == document){
8312 w = D.getViewWidth(); h = D.getViewHeight();
8314 w = this.getWidth(); h = this.getHeight();
8317 w = s.width; h = s.height;
8319 var x = 0, y = 0, r = Math.round;
8320 switch((anchor || "tl").toLowerCase()){
8362 var sc = this.getScroll();
8363 return [x + sc.left, y + sc.top];
8365 //Add the element's offset xy
8366 var o = this.getXY();
8367 return [x+o[0], y+o[1]];
8371 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8372 * supported position values.
8373 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8374 * @param {String} position The position to align to.
8375 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8376 * @return {Array} [x, y]
8378 getAlignToXY : function(el, p, o){
8382 throw "Element.alignTo with an element that doesn't exist";
8384 var c = false; //constrain to viewport
8385 var p1 = "", p2 = "";
8392 }else if(p.indexOf("-") == -1){
8395 p = p.toLowerCase();
8396 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8398 throw "Element.alignTo with an invalid alignment " + p;
8400 p1 = m[1]; p2 = m[2]; c = !!m[3];
8402 //Subtract the aligned el's internal xy from the target's offset xy
8403 //plus custom offset to get the aligned el's new offset xy
8404 var a1 = this.getAnchorXY(p1, true);
8405 var a2 = el.getAnchorXY(p2, false);
8406 var x = a2[0] - a1[0] + o[0];
8407 var y = a2[1] - a1[1] + o[1];
8409 //constrain the aligned el to viewport if necessary
8410 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8411 // 5px of margin for ie
8412 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8414 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8415 //perpendicular to the vp border, allow the aligned el to slide on that border,
8416 //otherwise swap the aligned el to the opposite border of the target.
8417 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8418 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8419 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8420 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8423 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8424 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8426 if((x+w) > dw + scrollX){
8427 x = swapX ? r.left-w : dw+scrollX-w;
8430 x = swapX ? r.right : scrollX;
8432 if((y+h) > dh + scrollY){
8433 y = swapY ? r.top-h : dh+scrollY-h;
8436 y = swapY ? r.bottom : scrollY;
8443 getConstrainToXY : function(){
8444 var os = {top:0, left:0, bottom:0, right: 0};
8446 return function(el, local, offsets, proposedXY){
8448 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8450 var vw, vh, vx = 0, vy = 0;
8451 if(el.dom == document.body || el.dom == document){
8452 vw = Roo.lib.Dom.getViewWidth();
8453 vh = Roo.lib.Dom.getViewHeight();
8455 vw = el.dom.clientWidth;
8456 vh = el.dom.clientHeight;
8458 var vxy = el.getXY();
8464 var s = el.getScroll();
8466 vx += offsets.left + s.left;
8467 vy += offsets.top + s.top;
8469 vw -= offsets.right;
8470 vh -= offsets.bottom;
8475 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8476 var x = xy[0], y = xy[1];
8477 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8479 // only move it if it needs it
8482 // first validate right/bottom
8491 // then make sure top/left isn't negative
8500 return moved ? [x, y] : false;
8505 adjustForConstraints : function(xy, parent, offsets){
8506 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8510 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8511 * document it aligns it to the viewport.
8512 * The position parameter is optional, and can be specified in any one of the following formats:
8514 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8515 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8516 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8517 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8518 * <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
8519 * element's anchor point, and the second value is used as the target's anchor point.</li>
8521 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8522 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8523 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8524 * that specified in order to enforce the viewport constraints.
8525 * Following are all of the supported anchor positions:
8528 ----- -----------------------------
8529 tl The top left corner (default)
8530 t The center of the top edge
8531 tr The top right corner
8532 l The center of the left edge
8533 c In the center of the element
8534 r The center of the right edge
8535 bl The bottom left corner
8536 b The center of the bottom edge
8537 br The bottom right corner
8541 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8542 el.alignTo("other-el");
8544 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8545 el.alignTo("other-el", "tr?");
8547 // align the bottom right corner of el with the center left edge of other-el
8548 el.alignTo("other-el", "br-l?");
8550 // align the center of el with the bottom left corner of other-el and
8551 // adjust the x position by -6 pixels (and the y position by 0)
8552 el.alignTo("other-el", "c-bl", [-6, 0]);
8554 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8555 * @param {String} position The position to align to.
8556 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8557 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8558 * @return {Roo.Element} this
8560 alignTo : function(element, position, offsets, animate){
8561 var xy = this.getAlignToXY(element, position, offsets);
8562 this.setXY(xy, this.preanim(arguments, 3));
8567 * Anchors an element to another element and realigns it when the window is resized.
8568 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8569 * @param {String} position The position to align to.
8570 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8571 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8572 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8573 * is a number, it is used as the buffer delay (defaults to 50ms).
8574 * @param {Function} callback The function to call after the animation finishes
8575 * @return {Roo.Element} this
8577 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8578 var action = function(){
8579 this.alignTo(el, alignment, offsets, animate);
8580 Roo.callback(callback, this);
8582 Roo.EventManager.onWindowResize(action, this);
8583 var tm = typeof monitorScroll;
8584 if(tm != 'undefined'){
8585 Roo.EventManager.on(window, 'scroll', action, this,
8586 {buffer: tm == 'number' ? monitorScroll : 50});
8588 action.call(this); // align immediately
8592 * Clears any opacity settings from this element. Required in some cases for IE.
8593 * @return {Roo.Element} this
8595 clearOpacity : function(){
8596 if (window.ActiveXObject) {
8597 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8598 this.dom.style.filter = "";
8601 this.dom.style.opacity = "";
8602 this.dom.style["-moz-opacity"] = "";
8603 this.dom.style["-khtml-opacity"] = "";
8609 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8610 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8611 * @return {Roo.Element} this
8613 hide : function(animate){
8614 this.setVisible(false, this.preanim(arguments, 0));
8619 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8620 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8621 * @return {Roo.Element} this
8623 show : function(animate){
8624 this.setVisible(true, this.preanim(arguments, 0));
8629 * @private Test if size has a unit, otherwise appends the default
8631 addUnits : function(size){
8632 return Roo.Element.addUnits(size, this.defaultUnit);
8636 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8637 * @return {Roo.Element} this
8639 beginMeasure : function(){
8641 if(el.offsetWidth || el.offsetHeight){
8642 return this; // offsets work already
8645 var p = this.dom, b = document.body; // start with this element
8646 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8647 var pe = Roo.get(p);
8648 if(pe.getStyle('display') == 'none'){
8649 changed.push({el: p, visibility: pe.getStyle("visibility")});
8650 p.style.visibility = "hidden";
8651 p.style.display = "block";
8655 this._measureChanged = changed;
8661 * Restores displays to before beginMeasure was called
8662 * @return {Roo.Element} this
8664 endMeasure : function(){
8665 var changed = this._measureChanged;
8667 for(var i = 0, len = changed.length; i < len; i++) {
8669 r.el.style.visibility = r.visibility;
8670 r.el.style.display = "none";
8672 this._measureChanged = null;
8678 * Update the innerHTML of this element, optionally searching for and processing scripts
8679 * @param {String} html The new HTML
8680 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8681 * @param {Function} callback For async script loading you can be noticed when the update completes
8682 * @return {Roo.Element} this
8684 update : function(html, loadScripts, callback){
8685 if(typeof html == "undefined"){
8688 if(loadScripts !== true){
8689 this.dom.innerHTML = html;
8690 if(typeof callback == "function"){
8698 html += '<span id="' + id + '"></span>';
8700 E.onAvailable(id, function(){
8701 var hd = document.getElementsByTagName("head")[0];
8702 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8703 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8704 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8707 while(match = re.exec(html)){
8708 var attrs = match[1];
8709 var srcMatch = attrs ? attrs.match(srcRe) : false;
8710 if(srcMatch && srcMatch[2]){
8711 var s = document.createElement("script");
8712 s.src = srcMatch[2];
8713 var typeMatch = attrs.match(typeRe);
8714 if(typeMatch && typeMatch[2]){
8715 s.type = typeMatch[2];
8718 }else if(match[2] && match[2].length > 0){
8719 if(window.execScript) {
8720 window.execScript(match[2]);
8728 window.eval(match[2]);
8732 var el = document.getElementById(id);
8733 if(el){el.parentNode.removeChild(el);}
8734 if(typeof callback == "function"){
8738 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8743 * Direct access to the UpdateManager update() method (takes the same parameters).
8744 * @param {String/Function} url The url for this request or a function to call to get the url
8745 * @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}
8746 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8747 * @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.
8748 * @return {Roo.Element} this
8751 var um = this.getUpdateManager();
8752 um.update.apply(um, arguments);
8757 * Gets this element's UpdateManager
8758 * @return {Roo.UpdateManager} The UpdateManager
8760 getUpdateManager : function(){
8761 if(!this.updateManager){
8762 this.updateManager = new Roo.UpdateManager(this);
8764 return this.updateManager;
8768 * Disables text selection for this element (normalized across browsers)
8769 * @return {Roo.Element} this
8771 unselectable : function(){
8772 this.dom.unselectable = "on";
8773 this.swallowEvent("selectstart", true);
8774 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8775 this.addClass("x-unselectable");
8780 * Calculates the x, y to center this element on the screen
8781 * @return {Array} The x, y values [x, y]
8783 getCenterXY : function(){
8784 return this.getAlignToXY(document, 'c-c');
8788 * Centers the Element in either the viewport, or another Element.
8789 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8791 center : function(centerIn){
8792 this.alignTo(centerIn || document, 'c-c');
8797 * Tests various css rules/browsers to determine if this element uses a border box
8800 isBorderBox : function(){
8801 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8805 * Return a box {x, y, width, height} that can be used to set another elements
8806 * size/location to match this element.
8807 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8808 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8809 * @return {Object} box An object in the format {x, y, width, height}
8811 getBox : function(contentBox, local){
8816 var left = parseInt(this.getStyle("left"), 10) || 0;
8817 var top = parseInt(this.getStyle("top"), 10) || 0;
8820 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8822 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8824 var l = this.getBorderWidth("l")+this.getPadding("l");
8825 var r = this.getBorderWidth("r")+this.getPadding("r");
8826 var t = this.getBorderWidth("t")+this.getPadding("t");
8827 var b = this.getBorderWidth("b")+this.getPadding("b");
8828 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)};
8830 bx.right = bx.x + bx.width;
8831 bx.bottom = bx.y + bx.height;
8836 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8837 for more information about the sides.
8838 * @param {String} sides
8841 getFrameWidth : function(sides, onlyContentBox){
8842 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8846 * 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.
8847 * @param {Object} box The box to fill {x, y, width, height}
8848 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8849 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8850 * @return {Roo.Element} this
8852 setBox : function(box, adjust, animate){
8853 var w = box.width, h = box.height;
8854 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8855 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8856 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8858 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8863 * Forces the browser to repaint this element
8864 * @return {Roo.Element} this
8866 repaint : function(){
8868 this.addClass("x-repaint");
8869 setTimeout(function(){
8870 Roo.get(dom).removeClass("x-repaint");
8876 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8877 * then it returns the calculated width of the sides (see getPadding)
8878 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8879 * @return {Object/Number}
8881 getMargins : function(side){
8884 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8885 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8886 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8887 right: parseInt(this.getStyle("margin-right"), 10) || 0
8890 return this.addStyles(side, El.margins);
8895 addStyles : function(sides, styles){
8897 for(var i = 0, len = sides.length; i < len; i++){
8898 v = this.getStyle(styles[sides.charAt(i)]);
8900 w = parseInt(v, 10);
8908 * Creates a proxy element of this element
8909 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8910 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8911 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8912 * @return {Roo.Element} The new proxy element
8914 createProxy : function(config, renderTo, matchBox){
8916 renderTo = Roo.getDom(renderTo);
8918 renderTo = document.body;
8920 config = typeof config == "object" ?
8921 config : {tag : "div", cls: config};
8922 var proxy = Roo.DomHelper.append(renderTo, config, true);
8924 proxy.setBox(this.getBox());
8930 * Puts a mask over this element to disable user interaction. Requires core.css.
8931 * This method can only be applied to elements which accept child nodes.
8932 * @param {String} msg (optional) A message to display in the mask
8933 * @param {String} msgCls (optional) A css class to apply to the msg element
8934 * @return {Element} The mask element
8936 mask : function(msg, msgCls)
8938 if(this.getStyle("position") == "static"){
8939 this.setStyle("position", "relative");
8942 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8944 this.addClass("x-masked");
8945 this._mask.setDisplayed(true);
8950 while (dom && dom.style) {
8951 if (!isNaN(parseInt(dom.style.zIndex))) {
8952 z = Math.max(z, parseInt(dom.style.zIndex));
8954 dom = dom.parentNode;
8956 // if we are masking the body - then it hides everything..
8957 if (this.dom == document.body) {
8959 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8960 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8963 if(typeof msg == 'string'){
8965 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8967 var mm = this._maskMsg;
8968 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8969 mm.dom.firstChild.innerHTML = msg;
8970 mm.setDisplayed(true);
8972 mm.setStyle('z-index', z + 102);
8974 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8975 this._mask.setHeight(this.getHeight());
8977 this._mask.setStyle('z-index', z + 100);
8983 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8984 * it is cached for reuse.
8986 unmask : function(removeEl){
8988 if(removeEl === true){
8989 this._mask.remove();
8992 this._maskMsg.remove();
8993 delete this._maskMsg;
8996 this._mask.setDisplayed(false);
8998 this._maskMsg.setDisplayed(false);
9002 this.removeClass("x-masked");
9006 * Returns true if this element is masked
9009 isMasked : function(){
9010 return this._mask && this._mask.isVisible();
9014 * Creates an iframe shim for this element to keep selects and other windowed objects from
9016 * @return {Roo.Element} The new shim element
9018 createShim : function(){
9019 var el = document.createElement('iframe');
9020 el.frameBorder = 'no';
9021 el.className = 'roo-shim';
9022 if(Roo.isIE && Roo.isSecure){
9023 el.src = Roo.SSL_SECURE_URL;
9025 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9026 shim.autoBoxAdjust = false;
9031 * Removes this element from the DOM and deletes it from the cache
9033 remove : function(){
9034 if(this.dom.parentNode){
9035 this.dom.parentNode.removeChild(this.dom);
9037 delete El.cache[this.dom.id];
9041 * Sets up event handlers to add and remove a css class when the mouse is over this element
9042 * @param {String} className
9043 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9044 * mouseout events for children elements
9045 * @return {Roo.Element} this
9047 addClassOnOver : function(className, preventFlicker){
9048 this.on("mouseover", function(){
9049 Roo.fly(this, '_internal').addClass(className);
9051 var removeFn = function(e){
9052 if(preventFlicker !== true || !e.within(this, true)){
9053 Roo.fly(this, '_internal').removeClass(className);
9056 this.on("mouseout", removeFn, this.dom);
9061 * Sets up event handlers to add and remove a css class when this element has the focus
9062 * @param {String} className
9063 * @return {Roo.Element} this
9065 addClassOnFocus : function(className){
9066 this.on("focus", function(){
9067 Roo.fly(this, '_internal').addClass(className);
9069 this.on("blur", function(){
9070 Roo.fly(this, '_internal').removeClass(className);
9075 * 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)
9076 * @param {String} className
9077 * @return {Roo.Element} this
9079 addClassOnClick : function(className){
9081 this.on("mousedown", function(){
9082 Roo.fly(dom, '_internal').addClass(className);
9083 var d = Roo.get(document);
9084 var fn = function(){
9085 Roo.fly(dom, '_internal').removeClass(className);
9086 d.removeListener("mouseup", fn);
9088 d.on("mouseup", fn);
9094 * Stops the specified event from bubbling and optionally prevents the default action
9095 * @param {String} eventName
9096 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9097 * @return {Roo.Element} this
9099 swallowEvent : function(eventName, preventDefault){
9100 var fn = function(e){
9101 e.stopPropagation();
9106 if(eventName instanceof Array){
9107 for(var i = 0, len = eventName.length; i < len; i++){
9108 this.on(eventName[i], fn);
9112 this.on(eventName, fn);
9119 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9122 * Sizes this element to its parent element's dimensions performing
9123 * neccessary box adjustments.
9124 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9125 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9126 * @return {Roo.Element} this
9128 fitToParent : function(monitorResize, targetParent) {
9129 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9130 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9131 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9134 var p = Roo.get(targetParent || this.dom.parentNode);
9135 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9136 if (monitorResize === true) {
9137 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9138 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9144 * Gets the next sibling, skipping text nodes
9145 * @return {HTMLElement} The next sibling or null
9147 getNextSibling : function(){
9148 var n = this.dom.nextSibling;
9149 while(n && n.nodeType != 1){
9156 * Gets the previous sibling, skipping text nodes
9157 * @return {HTMLElement} The previous sibling or null
9159 getPrevSibling : function(){
9160 var n = this.dom.previousSibling;
9161 while(n && n.nodeType != 1){
9162 n = n.previousSibling;
9169 * Appends the passed element(s) to this element
9170 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9171 * @return {Roo.Element} this
9173 appendChild: function(el){
9180 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9181 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9182 * automatically generated with the specified attributes.
9183 * @param {HTMLElement} insertBefore (optional) a child element of this element
9184 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9185 * @return {Roo.Element} The new child element
9187 createChild: function(config, insertBefore, returnDom){
9188 config = config || {tag:'div'};
9190 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9192 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9196 * Appends this element to the passed element
9197 * @param {String/HTMLElement/Element} el The new parent element
9198 * @return {Roo.Element} this
9200 appendTo: function(el){
9201 el = Roo.getDom(el);
9202 el.appendChild(this.dom);
9207 * Inserts this element before the passed element in the DOM
9208 * @param {String/HTMLElement/Element} el The element to insert before
9209 * @return {Roo.Element} this
9211 insertBefore: function(el){
9212 el = Roo.getDom(el);
9213 el.parentNode.insertBefore(this.dom, el);
9218 * Inserts this element after the passed element in the DOM
9219 * @param {String/HTMLElement/Element} el The element to insert after
9220 * @return {Roo.Element} this
9222 insertAfter: function(el){
9223 el = Roo.getDom(el);
9224 el.parentNode.insertBefore(this.dom, el.nextSibling);
9229 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9230 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9231 * @return {Roo.Element} The new child
9233 insertFirst: function(el, returnDom){
9235 if(typeof el == 'object' && !el.nodeType){ // dh config
9236 return this.createChild(el, this.dom.firstChild, returnDom);
9238 el = Roo.getDom(el);
9239 this.dom.insertBefore(el, this.dom.firstChild);
9240 return !returnDom ? Roo.get(el) : el;
9245 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9246 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9247 * @param {String} where (optional) 'before' or 'after' defaults to before
9248 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9249 * @return {Roo.Element} the inserted Element
9251 insertSibling: function(el, where, returnDom){
9252 where = where ? where.toLowerCase() : 'before';
9254 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9256 if(typeof el == 'object' && !el.nodeType){ // dh config
9257 if(where == 'after' && !this.dom.nextSibling){
9258 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9260 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9264 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9265 where == 'before' ? this.dom : this.dom.nextSibling);
9274 * Creates and wraps this element with another element
9275 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9276 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9277 * @return {HTMLElement/Element} The newly created wrapper element
9279 wrap: function(config, returnDom){
9281 config = {tag: "div"};
9283 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9284 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9289 * Replaces the passed element with this element
9290 * @param {String/HTMLElement/Element} el The element to replace
9291 * @return {Roo.Element} this
9293 replace: function(el){
9295 this.insertBefore(el);
9301 * Inserts an html fragment into this element
9302 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9303 * @param {String} html The HTML fragment
9304 * @param {Boolean} returnEl True to return an Roo.Element
9305 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9307 insertHtml : function(where, html, returnEl){
9308 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9309 return returnEl ? Roo.get(el) : el;
9313 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9314 * @param {Object} o The object with the attributes
9315 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9316 * @return {Roo.Element} this
9318 set : function(o, useSet){
9320 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9322 if(attr == "style" || typeof o[attr] == "function") continue;
9324 el.className = o["cls"];
9326 if(useSet) el.setAttribute(attr, o[attr]);
9327 else el[attr] = o[attr];
9331 Roo.DomHelper.applyStyles(el, o.style);
9337 * Convenience method for constructing a KeyMap
9338 * @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:
9339 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9340 * @param {Function} fn The function to call
9341 * @param {Object} scope (optional) The scope of the function
9342 * @return {Roo.KeyMap} The KeyMap created
9344 addKeyListener : function(key, fn, scope){
9346 if(typeof key != "object" || key instanceof Array){
9362 return new Roo.KeyMap(this, config);
9366 * Creates a KeyMap for this element
9367 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9368 * @return {Roo.KeyMap} The KeyMap created
9370 addKeyMap : function(config){
9371 return new Roo.KeyMap(this, config);
9375 * Returns true if this element is scrollable.
9378 isScrollable : function(){
9380 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9384 * 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().
9385 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9386 * @param {Number} value The new scroll value
9387 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9388 * @return {Element} this
9391 scrollTo : function(side, value, animate){
9392 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9394 this.dom[prop] = value;
9396 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9397 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9403 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9404 * within this element's scrollable range.
9405 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9406 * @param {Number} distance How far to scroll the element in pixels
9407 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9408 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9409 * was scrolled as far as it could go.
9411 scroll : function(direction, distance, animate){
9412 if(!this.isScrollable()){
9416 var l = el.scrollLeft, t = el.scrollTop;
9417 var w = el.scrollWidth, h = el.scrollHeight;
9418 var cw = el.clientWidth, ch = el.clientHeight;
9419 direction = direction.toLowerCase();
9420 var scrolled = false;
9421 var a = this.preanim(arguments, 2);
9426 var v = Math.min(l + distance, w-cw);
9427 this.scrollTo("left", v, a);
9434 var v = Math.max(l - distance, 0);
9435 this.scrollTo("left", v, a);
9443 var v = Math.max(t - distance, 0);
9444 this.scrollTo("top", v, a);
9452 var v = Math.min(t + distance, h-ch);
9453 this.scrollTo("top", v, a);
9462 * Translates the passed page coordinates into left/top css values for this element
9463 * @param {Number/Array} x The page x or an array containing [x, y]
9464 * @param {Number} y The page y
9465 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9467 translatePoints : function(x, y){
9468 if(typeof x == 'object' || x instanceof Array){
9471 var p = this.getStyle('position');
9472 var o = this.getXY();
9474 var l = parseInt(this.getStyle('left'), 10);
9475 var t = parseInt(this.getStyle('top'), 10);
9478 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9481 t = (p == "relative") ? 0 : this.dom.offsetTop;
9484 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9488 * Returns the current scroll position of the element.
9489 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9491 getScroll : function(){
9492 var d = this.dom, doc = document;
9493 if(d == doc || d == doc.body){
9494 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9495 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9496 return {left: l, top: t};
9498 return {left: d.scrollLeft, top: d.scrollTop};
9503 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9504 * are convert to standard 6 digit hex color.
9505 * @param {String} attr The css attribute
9506 * @param {String} defaultValue The default value to use when a valid color isn't found
9507 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9510 getColor : function(attr, defaultValue, prefix){
9511 var v = this.getStyle(attr);
9512 if(!v || v == "transparent" || v == "inherit") {
9513 return defaultValue;
9515 var color = typeof prefix == "undefined" ? "#" : prefix;
9516 if(v.substr(0, 4) == "rgb("){
9517 var rvs = v.slice(4, v.length -1).split(",");
9518 for(var i = 0; i < 3; i++){
9519 var h = parseInt(rvs[i]).toString(16);
9526 if(v.substr(0, 1) == "#"){
9528 for(var i = 1; i < 4; i++){
9529 var c = v.charAt(i);
9532 }else if(v.length == 7){
9533 color += v.substr(1);
9537 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9541 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9542 * gradient background, rounded corners and a 4-way shadow.
9543 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9544 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9545 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9546 * @return {Roo.Element} this
9548 boxWrap : function(cls){
9549 cls = cls || 'x-box';
9550 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9551 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9556 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9557 * @param {String} namespace The namespace in which to look for the attribute
9558 * @param {String} name The attribute name
9559 * @return {String} The attribute value
9561 getAttributeNS : Roo.isIE ? function(ns, name){
9563 var type = typeof d[ns+":"+name];
9564 if(type != 'undefined' && type != 'unknown'){
9565 return d[ns+":"+name];
9568 } : function(ns, name){
9570 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9575 * Sets or Returns the value the dom attribute value
9576 * @param {String} name The attribute name
9577 * @param {String} value (optional) The value to set the attribute to
9578 * @return {String} The attribute value
9580 attr : function(name){
9581 if (arguments.length > 1) {
9582 this.dom.setAttribute(name, arguments[1]);
9583 return arguments[1];
9585 if (!this.dom.hasAttribute(name)) {
9588 return this.dom.getAttribute(name);
9595 var ep = El.prototype;
9598 * Appends an event handler (Shorthand for addListener)
9599 * @param {String} eventName The type of event to append
9600 * @param {Function} fn The method the event invokes
9601 * @param {Object} scope (optional) The scope (this object) of the fn
9602 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9605 ep.on = ep.addListener;
9607 ep.mon = ep.addListener;
9610 * Removes an event handler from this element (shorthand for removeListener)
9611 * @param {String} eventName the type of event to remove
9612 * @param {Function} fn the method the event invokes
9613 * @return {Roo.Element} this
9616 ep.un = ep.removeListener;
9619 * true to automatically adjust width and height settings for box-model issues (default to true)
9621 ep.autoBoxAdjust = true;
9624 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9627 El.addUnits = function(v, defaultUnit){
9628 if(v === "" || v == "auto"){
9631 if(v === undefined){
9634 if(typeof v == "number" || !El.unitPattern.test(v)){
9635 return v + (defaultUnit || 'px');
9640 // special markup used throughout Roo when box wrapping elements
9641 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>';
9643 * Visibility mode constant - Use visibility to hide element
9649 * Visibility mode constant - Use display to hide element
9655 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9656 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9657 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9669 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9670 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9671 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9672 * @return {Element} The Element object
9675 El.get = function(el){
9677 if(!el){ return null; }
9678 if(typeof el == "string"){ // element id
9679 if(!(elm = document.getElementById(el))){
9682 if(ex = El.cache[el]){
9685 ex = El.cache[el] = new El(elm);
9688 }else if(el.tagName){ // dom element
9692 if(ex = El.cache[id]){
9695 ex = El.cache[id] = new El(el);
9698 }else if(el instanceof El){
9700 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9701 // catch case where it hasn't been appended
9702 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9705 }else if(el.isComposite){
9707 }else if(el instanceof Array){
9708 return El.select(el);
9709 }else if(el == document){
9710 // create a bogus element object representing the document object
9712 var f = function(){};
9713 f.prototype = El.prototype;
9715 docEl.dom = document;
9723 El.uncache = function(el){
9724 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9726 delete El.cache[a[i].id || a[i]];
9732 // Garbage collection - uncache elements/purge listeners on orphaned elements
9733 // so we don't hold a reference and cause the browser to retain them
9734 El.garbageCollect = function(){
9735 if(!Roo.enableGarbageCollector){
9736 clearInterval(El.collectorThread);
9739 for(var eid in El.cache){
9740 var el = El.cache[eid], d = el.dom;
9741 // -------------------------------------------------------
9742 // Determining what is garbage:
9743 // -------------------------------------------------------
9745 // dom node is null, definitely garbage
9746 // -------------------------------------------------------
9748 // no parentNode == direct orphan, definitely garbage
9749 // -------------------------------------------------------
9750 // !d.offsetParent && !document.getElementById(eid)
9751 // display none elements have no offsetParent so we will
9752 // also try to look it up by it's id. However, check
9753 // offsetParent first so we don't do unneeded lookups.
9754 // This enables collection of elements that are not orphans
9755 // directly, but somewhere up the line they have an orphan
9757 // -------------------------------------------------------
9758 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9759 delete El.cache[eid];
9760 if(d && Roo.enableListenerCollection){
9766 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9770 El.Flyweight = function(dom){
9773 El.Flyweight.prototype = El.prototype;
9775 El._flyweights = {};
9777 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9778 * the dom node can be overwritten by other code.
9779 * @param {String/HTMLElement} el The dom node or id
9780 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9781 * prevent conflicts (e.g. internally Roo uses "_internal")
9783 * @return {Element} The shared Element object
9785 El.fly = function(el, named){
9786 named = named || '_global';
9787 el = Roo.getDom(el);
9791 if(!El._flyweights[named]){
9792 El._flyweights[named] = new El.Flyweight();
9794 El._flyweights[named].dom = el;
9795 return El._flyweights[named];
9799 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9800 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9801 * Shorthand of {@link Roo.Element#get}
9802 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9803 * @return {Element} The Element object
9809 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9810 * the dom node can be overwritten by other code.
9811 * Shorthand of {@link Roo.Element#fly}
9812 * @param {String/HTMLElement} el The dom node or id
9813 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9814 * prevent conflicts (e.g. internally Roo uses "_internal")
9816 * @return {Element} The shared Element object
9822 // speedy lookup for elements never to box adjust
9823 var noBoxAdjust = Roo.isStrict ? {
9826 input:1, select:1, textarea:1
9828 if(Roo.isIE || Roo.isGecko){
9829 noBoxAdjust['button'] = 1;
9833 Roo.EventManager.on(window, 'unload', function(){
9835 delete El._flyweights;
9843 Roo.Element.selectorFunction = Roo.DomQuery.select;
9846 Roo.Element.select = function(selector, unique, root){
9848 if(typeof selector == "string"){
9849 els = Roo.Element.selectorFunction(selector, root);
9850 }else if(selector.length !== undefined){
9853 throw "Invalid selector";
9855 if(unique === true){
9856 return new Roo.CompositeElement(els);
9858 return new Roo.CompositeElementLite(els);
9862 * Selects elements based on the passed CSS selector to enable working on them as 1.
9863 * @param {String/Array} selector The CSS selector or an array of elements
9864 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9865 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9866 * @return {CompositeElementLite/CompositeElement}
9870 Roo.select = Roo.Element.select;
9887 * Ext JS Library 1.1.1
9888 * Copyright(c) 2006-2007, Ext JS, LLC.
9890 * Originally Released Under LGPL - original licence link has changed is not relivant.
9893 * <script type="text/javascript">
9898 //Notifies Element that fx methods are available
9899 Roo.enableFx = true;
9903 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9904 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9905 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9906 * Element effects to work.</p><br/>
9908 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9909 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9910 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9911 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9912 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9913 * expected results and should be done with care.</p><br/>
9915 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9916 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9919 ----- -----------------------------
9920 tl The top left corner
9921 t The center of the top edge
9922 tr The top right corner
9923 l The center of the left edge
9924 r The center of the right edge
9925 bl The bottom left corner
9926 b The center of the bottom edge
9927 br The bottom right corner
9929 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9930 * below are common options that can be passed to any Fx method.</b>
9931 * @cfg {Function} callback A function called when the effect is finished
9932 * @cfg {Object} scope The scope of the effect function
9933 * @cfg {String} easing A valid Easing value for the effect
9934 * @cfg {String} afterCls A css class to apply after the effect
9935 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9936 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9937 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9938 * effects that end with the element being visually hidden, ignored otherwise)
9939 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9940 * a function which returns such a specification that will be applied to the Element after the effect finishes
9941 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9942 * @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
9943 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9947 * Slides the element into view. An anchor point can be optionally passed to set the point of
9948 * origin for the slide effect. This function automatically handles wrapping the element with
9949 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9952 // default: slide the element in from the top
9955 // custom: slide the element in from the right with a 2-second duration
9956 el.slideIn('r', { duration: 2 });
9958 // common config options shown with default values
9964 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9965 * @param {Object} options (optional) Object literal with any of the Fx config options
9966 * @return {Roo.Element} The Element
9968 slideIn : function(anchor, o){
9969 var el = this.getFxEl();
9972 el.queueFx(o, function(){
9974 anchor = anchor || "t";
9976 // fix display to visibility
9979 // restore values after effect
9980 var r = this.getFxRestore();
9981 var b = this.getBox();
9982 // fixed size for slide
9986 var wrap = this.fxWrap(r.pos, o, "hidden");
9988 var st = this.dom.style;
9989 st.visibility = "visible";
9990 st.position = "absolute";
9992 // clear out temp styles after slide and unwrap
9993 var after = function(){
9994 el.fxUnwrap(wrap, r.pos, o);
9996 st.height = r.height;
9999 // time to calc the positions
10000 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10002 switch(anchor.toLowerCase()){
10004 wrap.setSize(b.width, 0);
10005 st.left = st.bottom = "0";
10009 wrap.setSize(0, b.height);
10010 st.right = st.top = "0";
10014 wrap.setSize(0, b.height);
10015 wrap.setX(b.right);
10016 st.left = st.top = "0";
10017 a = {width: bw, points: pt};
10020 wrap.setSize(b.width, 0);
10021 wrap.setY(b.bottom);
10022 st.left = st.top = "0";
10023 a = {height: bh, points: pt};
10026 wrap.setSize(0, 0);
10027 st.right = st.bottom = "0";
10028 a = {width: bw, height: bh};
10031 wrap.setSize(0, 0);
10032 wrap.setY(b.y+b.height);
10033 st.right = st.top = "0";
10034 a = {width: bw, height: bh, points: pt};
10037 wrap.setSize(0, 0);
10038 wrap.setXY([b.right, b.bottom]);
10039 st.left = st.top = "0";
10040 a = {width: bw, height: bh, points: pt};
10043 wrap.setSize(0, 0);
10044 wrap.setX(b.x+b.width);
10045 st.left = st.bottom = "0";
10046 a = {width: bw, height: bh, points: pt};
10049 this.dom.style.visibility = "visible";
10052 arguments.callee.anim = wrap.fxanim(a,
10062 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10063 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10064 * 'hidden') but block elements will still take up space in the document. The element must be removed
10065 * from the DOM using the 'remove' config option if desired. This function automatically handles
10066 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10069 // default: slide the element out to the top
10072 // custom: slide the element out to the right with a 2-second duration
10073 el.slideOut('r', { duration: 2 });
10075 // common config options shown with default values
10083 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10084 * @param {Object} options (optional) Object literal with any of the Fx config options
10085 * @return {Roo.Element} The Element
10087 slideOut : function(anchor, o){
10088 var el = this.getFxEl();
10091 el.queueFx(o, function(){
10093 anchor = anchor || "t";
10095 // restore values after effect
10096 var r = this.getFxRestore();
10098 var b = this.getBox();
10099 // fixed size for slide
10103 var wrap = this.fxWrap(r.pos, o, "visible");
10105 var st = this.dom.style;
10106 st.visibility = "visible";
10107 st.position = "absolute";
10111 var after = function(){
10113 el.setDisplayed(false);
10118 el.fxUnwrap(wrap, r.pos, o);
10120 st.width = r.width;
10121 st.height = r.height;
10126 var a, zero = {to: 0};
10127 switch(anchor.toLowerCase()){
10129 st.left = st.bottom = "0";
10130 a = {height: zero};
10133 st.right = st.top = "0";
10137 st.left = st.top = "0";
10138 a = {width: zero, points: {to:[b.right, b.y]}};
10141 st.left = st.top = "0";
10142 a = {height: zero, points: {to:[b.x, b.bottom]}};
10145 st.right = st.bottom = "0";
10146 a = {width: zero, height: zero};
10149 st.right = st.top = "0";
10150 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10153 st.left = st.top = "0";
10154 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10157 st.left = st.bottom = "0";
10158 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10162 arguments.callee.anim = wrap.fxanim(a,
10172 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10173 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10174 * The element must be removed from the DOM using the 'remove' config option if desired.
10180 // common config options shown with default values
10188 * @param {Object} options (optional) Object literal with any of the Fx config options
10189 * @return {Roo.Element} The Element
10191 puff : function(o){
10192 var el = this.getFxEl();
10195 el.queueFx(o, function(){
10196 this.clearOpacity();
10199 // restore values after effect
10200 var r = this.getFxRestore();
10201 var st = this.dom.style;
10203 var after = function(){
10205 el.setDisplayed(false);
10212 el.setPositioning(r.pos);
10213 st.width = r.width;
10214 st.height = r.height;
10219 var width = this.getWidth();
10220 var height = this.getHeight();
10222 arguments.callee.anim = this.fxanim({
10223 width : {to: this.adjustWidth(width * 2)},
10224 height : {to: this.adjustHeight(height * 2)},
10225 points : {by: [-(width * .5), -(height * .5)]},
10227 fontSize: {to:200, unit: "%"}
10238 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10239 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10240 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10246 // all config options shown with default values
10254 * @param {Object} options (optional) Object literal with any of the Fx config options
10255 * @return {Roo.Element} The Element
10257 switchOff : function(o){
10258 var el = this.getFxEl();
10261 el.queueFx(o, function(){
10262 this.clearOpacity();
10265 // restore values after effect
10266 var r = this.getFxRestore();
10267 var st = this.dom.style;
10269 var after = function(){
10271 el.setDisplayed(false);
10277 el.setPositioning(r.pos);
10278 st.width = r.width;
10279 st.height = r.height;
10284 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10285 this.clearOpacity();
10289 points:{by:[0, this.getHeight() * .5]}
10290 }, o, 'motion', 0.3, 'easeIn', after);
10291 }).defer(100, this);
10298 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10299 * changed using the "attr" config option) and then fading back to the original color. If no original
10300 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10303 // default: highlight background to yellow
10306 // custom: highlight foreground text to blue for 2 seconds
10307 el.highlight("0000ff", { attr: 'color', duration: 2 });
10309 // common config options shown with default values
10310 el.highlight("ffff9c", {
10311 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10312 endColor: (current color) or "ffffff",
10317 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10318 * @param {Object} options (optional) Object literal with any of the Fx config options
10319 * @return {Roo.Element} The Element
10321 highlight : function(color, o){
10322 var el = this.getFxEl();
10325 el.queueFx(o, function(){
10326 color = color || "ffff9c";
10327 attr = o.attr || "backgroundColor";
10329 this.clearOpacity();
10332 var origColor = this.getColor(attr);
10333 var restoreColor = this.dom.style[attr];
10334 endColor = (o.endColor || origColor) || "ffffff";
10336 var after = function(){
10337 el.dom.style[attr] = restoreColor;
10342 a[attr] = {from: color, to: endColor};
10343 arguments.callee.anim = this.fxanim(a,
10353 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10356 // default: a single light blue ripple
10359 // custom: 3 red ripples lasting 3 seconds total
10360 el.frame("ff0000", 3, { duration: 3 });
10362 // common config options shown with default values
10363 el.frame("C3DAF9", 1, {
10364 duration: 1 //duration of entire animation (not each individual ripple)
10365 // Note: Easing is not configurable and will be ignored if included
10368 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10369 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10370 * @param {Object} options (optional) Object literal with any of the Fx config options
10371 * @return {Roo.Element} The Element
10373 frame : function(color, count, o){
10374 var el = this.getFxEl();
10377 el.queueFx(o, function(){
10378 color = color || "#C3DAF9";
10379 if(color.length == 6){
10380 color = "#" + color;
10382 count = count || 1;
10383 duration = o.duration || 1;
10386 var b = this.getBox();
10387 var animFn = function(){
10388 var proxy = this.createProxy({
10391 visbility:"hidden",
10392 position:"absolute",
10393 "z-index":"35000", // yee haw
10394 border:"0px solid " + color
10397 var scale = Roo.isBorderBox ? 2 : 1;
10399 top:{from:b.y, to:b.y - 20},
10400 left:{from:b.x, to:b.x - 20},
10401 borderWidth:{from:0, to:10},
10402 opacity:{from:1, to:0},
10403 height:{from:b.height, to:(b.height + (20*scale))},
10404 width:{from:b.width, to:(b.width + (20*scale))}
10405 }, duration, function(){
10409 animFn.defer((duration/2)*1000, this);
10420 * Creates a pause before any subsequent queued effects begin. If there are
10421 * no effects queued after the pause it will have no effect.
10426 * @param {Number} seconds The length of time to pause (in seconds)
10427 * @return {Roo.Element} The Element
10429 pause : function(seconds){
10430 var el = this.getFxEl();
10433 el.queueFx(o, function(){
10434 setTimeout(function(){
10436 }, seconds * 1000);
10442 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10443 * using the "endOpacity" config option.
10446 // default: fade in from opacity 0 to 100%
10449 // custom: fade in from opacity 0 to 75% over 2 seconds
10450 el.fadeIn({ endOpacity: .75, duration: 2});
10452 // common config options shown with default values
10454 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10459 * @param {Object} options (optional) Object literal with any of the Fx config options
10460 * @return {Roo.Element} The Element
10462 fadeIn : function(o){
10463 var el = this.getFxEl();
10465 el.queueFx(o, function(){
10466 this.setOpacity(0);
10468 this.dom.style.visibility = 'visible';
10469 var to = o.endOpacity || 1;
10470 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10471 o, null, .5, "easeOut", function(){
10473 this.clearOpacity();
10482 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10483 * using the "endOpacity" config option.
10486 // default: fade out from the element's current opacity to 0
10489 // custom: fade out from the element's current opacity to 25% over 2 seconds
10490 el.fadeOut({ endOpacity: .25, duration: 2});
10492 // common config options shown with default values
10494 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10501 * @param {Object} options (optional) Object literal with any of the Fx config options
10502 * @return {Roo.Element} The Element
10504 fadeOut : function(o){
10505 var el = this.getFxEl();
10507 el.queueFx(o, function(){
10508 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10509 o, null, .5, "easeOut", function(){
10510 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10511 this.dom.style.display = "none";
10513 this.dom.style.visibility = "hidden";
10515 this.clearOpacity();
10523 * Animates the transition of an element's dimensions from a starting height/width
10524 * to an ending height/width.
10527 // change height and width to 100x100 pixels
10528 el.scale(100, 100);
10530 // common config options shown with default values. The height and width will default to
10531 // the element's existing values if passed as null.
10534 [element's height], {
10539 * @param {Number} width The new width (pass undefined to keep the original width)
10540 * @param {Number} height The new height (pass undefined to keep the original height)
10541 * @param {Object} options (optional) Object literal with any of the Fx config options
10542 * @return {Roo.Element} The Element
10544 scale : function(w, h, o){
10545 this.shift(Roo.apply({}, o, {
10553 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10554 * Any of these properties not specified in the config object will not be changed. This effect
10555 * requires that at least one new dimension, position or opacity setting must be passed in on
10556 * the config object in order for the function to have any effect.
10559 // slide the element horizontally to x position 200 while changing the height and opacity
10560 el.shift({ x: 200, height: 50, opacity: .8 });
10562 // common config options shown with default values.
10564 width: [element's width],
10565 height: [element's height],
10566 x: [element's x position],
10567 y: [element's y position],
10568 opacity: [element's opacity],
10573 * @param {Object} options Object literal with any of the Fx config options
10574 * @return {Roo.Element} The Element
10576 shift : function(o){
10577 var el = this.getFxEl();
10579 el.queueFx(o, function(){
10580 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10581 if(w !== undefined){
10582 a.width = {to: this.adjustWidth(w)};
10584 if(h !== undefined){
10585 a.height = {to: this.adjustHeight(h)};
10587 if(x !== undefined || y !== undefined){
10589 x !== undefined ? x : this.getX(),
10590 y !== undefined ? y : this.getY()
10593 if(op !== undefined){
10594 a.opacity = {to: op};
10596 if(o.xy !== undefined){
10597 a.points = {to: o.xy};
10599 arguments.callee.anim = this.fxanim(a,
10600 o, 'motion', .35, "easeOut", function(){
10608 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10609 * ending point of the effect.
10612 // default: slide the element downward while fading out
10615 // custom: slide the element out to the right with a 2-second duration
10616 el.ghost('r', { duration: 2 });
10618 // common config options shown with default values
10626 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10627 * @param {Object} options (optional) Object literal with any of the Fx config options
10628 * @return {Roo.Element} The Element
10630 ghost : function(anchor, o){
10631 var el = this.getFxEl();
10634 el.queueFx(o, function(){
10635 anchor = anchor || "b";
10637 // restore values after effect
10638 var r = this.getFxRestore();
10639 var w = this.getWidth(),
10640 h = this.getHeight();
10642 var st = this.dom.style;
10644 var after = function(){
10646 el.setDisplayed(false);
10652 el.setPositioning(r.pos);
10653 st.width = r.width;
10654 st.height = r.height;
10659 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10660 switch(anchor.toLowerCase()){
10687 arguments.callee.anim = this.fxanim(a,
10697 * Ensures that all effects queued after syncFx is called on the element are
10698 * run concurrently. This is the opposite of {@link #sequenceFx}.
10699 * @return {Roo.Element} The Element
10701 syncFx : function(){
10702 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10711 * Ensures that all effects queued after sequenceFx is called on the element are
10712 * run in sequence. This is the opposite of {@link #syncFx}.
10713 * @return {Roo.Element} The Element
10715 sequenceFx : function(){
10716 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10718 concurrent : false,
10725 nextFx : function(){
10726 var ef = this.fxQueue[0];
10733 * Returns true if the element has any effects actively running or queued, else returns false.
10734 * @return {Boolean} True if element has active effects, else false
10736 hasActiveFx : function(){
10737 return this.fxQueue && this.fxQueue[0];
10741 * Stops any running effects and clears the element's internal effects queue if it contains
10742 * any additional effects that haven't started yet.
10743 * @return {Roo.Element} The Element
10745 stopFx : function(){
10746 if(this.hasActiveFx()){
10747 var cur = this.fxQueue[0];
10748 if(cur && cur.anim && cur.anim.isAnimated()){
10749 this.fxQueue = [cur]; // clear out others
10750 cur.anim.stop(true);
10757 beforeFx : function(o){
10758 if(this.hasActiveFx() && !o.concurrent){
10769 * Returns true if the element is currently blocking so that no other effect can be queued
10770 * until this effect is finished, else returns false if blocking is not set. This is commonly
10771 * used to ensure that an effect initiated by a user action runs to completion prior to the
10772 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10773 * @return {Boolean} True if blocking, else false
10775 hasFxBlock : function(){
10776 var q = this.fxQueue;
10777 return q && q[0] && q[0].block;
10781 queueFx : function(o, fn){
10785 if(!this.hasFxBlock()){
10786 Roo.applyIf(o, this.fxDefaults);
10788 var run = this.beforeFx(o);
10789 fn.block = o.block;
10790 this.fxQueue.push(fn);
10802 fxWrap : function(pos, o, vis){
10804 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10807 wrapXY = this.getXY();
10809 var div = document.createElement("div");
10810 div.style.visibility = vis;
10811 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10812 wrap.setPositioning(pos);
10813 if(wrap.getStyle("position") == "static"){
10814 wrap.position("relative");
10816 this.clearPositioning('auto');
10818 wrap.dom.appendChild(this.dom);
10820 wrap.setXY(wrapXY);
10827 fxUnwrap : function(wrap, pos, o){
10828 this.clearPositioning();
10829 this.setPositioning(pos);
10831 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10837 getFxRestore : function(){
10838 var st = this.dom.style;
10839 return {pos: this.getPositioning(), width: st.width, height : st.height};
10843 afterFx : function(o){
10845 this.applyStyles(o.afterStyle);
10848 this.addClass(o.afterCls);
10850 if(o.remove === true){
10853 Roo.callback(o.callback, o.scope, [this]);
10855 this.fxQueue.shift();
10861 getFxEl : function(){ // support for composite element fx
10862 return Roo.get(this.dom);
10866 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10867 animType = animType || 'run';
10869 var anim = Roo.lib.Anim[animType](
10871 (opt.duration || defaultDur) || .35,
10872 (opt.easing || defaultEase) || 'easeOut',
10874 Roo.callback(cb, this);
10883 // backwords compat
10884 Roo.Fx.resize = Roo.Fx.scale;
10886 //When included, Roo.Fx is automatically applied to Element so that all basic
10887 //effects are available directly via the Element API
10888 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10890 * Ext JS Library 1.1.1
10891 * Copyright(c) 2006-2007, Ext JS, LLC.
10893 * Originally Released Under LGPL - original licence link has changed is not relivant.
10896 * <script type="text/javascript">
10901 * @class Roo.CompositeElement
10902 * Standard composite class. Creates a Roo.Element for every element in the collection.
10904 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10905 * actions will be performed on all the elements in this collection.</b>
10907 * All methods return <i>this</i> and can be chained.
10909 var els = Roo.select("#some-el div.some-class", true);
10910 // or select directly from an existing element
10911 var el = Roo.get('some-el');
10912 el.select('div.some-class', true);
10914 els.setWidth(100); // all elements become 100 width
10915 els.hide(true); // all elements fade out and hide
10917 els.setWidth(100).hide(true);
10920 Roo.CompositeElement = function(els){
10921 this.elements = [];
10922 this.addElements(els);
10924 Roo.CompositeElement.prototype = {
10926 addElements : function(els){
10927 if(!els) return this;
10928 if(typeof els == "string"){
10929 els = Roo.Element.selectorFunction(els);
10931 var yels = this.elements;
10932 var index = yels.length-1;
10933 for(var i = 0, len = els.length; i < len; i++) {
10934 yels[++index] = Roo.get(els[i]);
10940 * Clears this composite and adds the elements returned by the passed selector.
10941 * @param {String/Array} els A string CSS selector, an array of elements or an element
10942 * @return {CompositeElement} this
10944 fill : function(els){
10945 this.elements = [];
10951 * Filters this composite to only elements that match the passed selector.
10952 * @param {String} selector A string CSS selector
10953 * @return {CompositeElement} this
10955 filter : function(selector){
10957 this.each(function(el){
10958 if(el.is(selector)){
10959 els[els.length] = el.dom;
10966 invoke : function(fn, args){
10967 var els = this.elements;
10968 for(var i = 0, len = els.length; i < len; i++) {
10969 Roo.Element.prototype[fn].apply(els[i], args);
10974 * Adds elements to this composite.
10975 * @param {String/Array} els A string CSS selector, an array of elements or an element
10976 * @return {CompositeElement} this
10978 add : function(els){
10979 if(typeof els == "string"){
10980 this.addElements(Roo.Element.selectorFunction(els));
10981 }else if(els.length !== undefined){
10982 this.addElements(els);
10984 this.addElements([els]);
10989 * Calls the passed function passing (el, this, index) for each element in this composite.
10990 * @param {Function} fn The function to call
10991 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10992 * @return {CompositeElement} this
10994 each : function(fn, scope){
10995 var els = this.elements;
10996 for(var i = 0, len = els.length; i < len; i++){
10997 if(fn.call(scope || els[i], els[i], this, i) === false) {
11005 * Returns the Element object at the specified index
11006 * @param {Number} index
11007 * @return {Roo.Element}
11009 item : function(index){
11010 return this.elements[index] || null;
11014 * Returns the first Element
11015 * @return {Roo.Element}
11017 first : function(){
11018 return this.item(0);
11022 * Returns the last Element
11023 * @return {Roo.Element}
11026 return this.item(this.elements.length-1);
11030 * Returns the number of elements in this composite
11033 getCount : function(){
11034 return this.elements.length;
11038 * Returns true if this composite contains the passed element
11041 contains : function(el){
11042 return this.indexOf(el) !== -1;
11046 * Returns true if this composite contains the passed element
11049 indexOf : function(el){
11050 return this.elements.indexOf(Roo.get(el));
11055 * Removes the specified element(s).
11056 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11057 * or an array of any of those.
11058 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11059 * @return {CompositeElement} this
11061 removeElement : function(el, removeDom){
11062 if(el instanceof Array){
11063 for(var i = 0, len = el.length; i < len; i++){
11064 this.removeElement(el[i]);
11068 var index = typeof el == 'number' ? el : this.indexOf(el);
11071 var d = this.elements[index];
11075 d.parentNode.removeChild(d);
11078 this.elements.splice(index, 1);
11084 * Replaces the specified element with the passed element.
11085 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11087 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11088 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11089 * @return {CompositeElement} this
11091 replaceElement : function(el, replacement, domReplace){
11092 var index = typeof el == 'number' ? el : this.indexOf(el);
11095 this.elements[index].replaceWith(replacement);
11097 this.elements.splice(index, 1, Roo.get(replacement))
11104 * Removes all elements.
11106 clear : function(){
11107 this.elements = [];
11111 Roo.CompositeElement.createCall = function(proto, fnName){
11112 if(!proto[fnName]){
11113 proto[fnName] = function(){
11114 return this.invoke(fnName, arguments);
11118 for(var fnName in Roo.Element.prototype){
11119 if(typeof Roo.Element.prototype[fnName] == "function"){
11120 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11126 * Ext JS Library 1.1.1
11127 * Copyright(c) 2006-2007, Ext JS, LLC.
11129 * Originally Released Under LGPL - original licence link has changed is not relivant.
11132 * <script type="text/javascript">
11136 * @class Roo.CompositeElementLite
11137 * @extends Roo.CompositeElement
11138 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11140 var els = Roo.select("#some-el div.some-class");
11141 // or select directly from an existing element
11142 var el = Roo.get('some-el');
11143 el.select('div.some-class');
11145 els.setWidth(100); // all elements become 100 width
11146 els.hide(true); // all elements fade out and hide
11148 els.setWidth(100).hide(true);
11149 </code></pre><br><br>
11150 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11151 * actions will be performed on all the elements in this collection.</b>
11153 Roo.CompositeElementLite = function(els){
11154 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11155 this.el = new Roo.Element.Flyweight();
11157 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11158 addElements : function(els){
11160 if(els instanceof Array){
11161 this.elements = this.elements.concat(els);
11163 var yels = this.elements;
11164 var index = yels.length-1;
11165 for(var i = 0, len = els.length; i < len; i++) {
11166 yels[++index] = els[i];
11172 invoke : function(fn, args){
11173 var els = this.elements;
11175 for(var i = 0, len = els.length; i < len; i++) {
11177 Roo.Element.prototype[fn].apply(el, args);
11182 * Returns a flyweight Element of the dom element object at the specified index
11183 * @param {Number} index
11184 * @return {Roo.Element}
11186 item : function(index){
11187 if(!this.elements[index]){
11190 this.el.dom = this.elements[index];
11194 // fixes scope with flyweight
11195 addListener : function(eventName, handler, scope, opt){
11196 var els = this.elements;
11197 for(var i = 0, len = els.length; i < len; i++) {
11198 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11204 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11205 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11206 * a reference to the dom node, use el.dom.</b>
11207 * @param {Function} fn The function to call
11208 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11209 * @return {CompositeElement} this
11211 each : function(fn, scope){
11212 var els = this.elements;
11214 for(var i = 0, len = els.length; i < len; i++){
11216 if(fn.call(scope || el, el, this, i) === false){
11223 indexOf : function(el){
11224 return this.elements.indexOf(Roo.getDom(el));
11227 replaceElement : function(el, replacement, domReplace){
11228 var index = typeof el == 'number' ? el : this.indexOf(el);
11230 replacement = Roo.getDom(replacement);
11232 var d = this.elements[index];
11233 d.parentNode.insertBefore(replacement, d);
11234 d.parentNode.removeChild(d);
11236 this.elements.splice(index, 1, replacement);
11241 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11245 * Ext JS Library 1.1.1
11246 * Copyright(c) 2006-2007, Ext JS, LLC.
11248 * Originally Released Under LGPL - original licence link has changed is not relivant.
11251 * <script type="text/javascript">
11257 * @class Roo.data.Connection
11258 * @extends Roo.util.Observable
11259 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11260 * either to a configured URL, or to a URL specified at request time.<br><br>
11262 * Requests made by this class are asynchronous, and will return immediately. No data from
11263 * the server will be available to the statement immediately following the {@link #request} call.
11264 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11266 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11267 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11268 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11269 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11270 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11271 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11272 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11273 * standard DOM methods.
11275 * @param {Object} config a configuration object.
11277 Roo.data.Connection = function(config){
11278 Roo.apply(this, config);
11281 * @event beforerequest
11282 * Fires before a network request is made to retrieve a data object.
11283 * @param {Connection} conn This Connection object.
11284 * @param {Object} options The options config object passed to the {@link #request} method.
11286 "beforerequest" : true,
11288 * @event requestcomplete
11289 * Fires if the request was successfully completed.
11290 * @param {Connection} conn This Connection object.
11291 * @param {Object} response The XHR object containing the response data.
11292 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11293 * @param {Object} options The options config object passed to the {@link #request} method.
11295 "requestcomplete" : true,
11297 * @event requestexception
11298 * Fires if an error HTTP status was returned from the server.
11299 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11300 * @param {Connection} conn This Connection object.
11301 * @param {Object} response The XHR object containing the response data.
11302 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11303 * @param {Object} options The options config object passed to the {@link #request} method.
11305 "requestexception" : true
11307 Roo.data.Connection.superclass.constructor.call(this);
11310 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11312 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11315 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11316 * extra parameters to each request made by this object. (defaults to undefined)
11319 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11320 * to each request made by this object. (defaults to undefined)
11323 * @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)
11326 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11330 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11336 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11339 disableCaching: true,
11342 * Sends an HTTP request to a remote server.
11343 * @param {Object} options An object which may contain the following properties:<ul>
11344 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11345 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11346 * request, a url encoded string or a function to call to get either.</li>
11347 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11348 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11349 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11350 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11351 * <li>options {Object} The parameter to the request call.</li>
11352 * <li>success {Boolean} True if the request succeeded.</li>
11353 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11355 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11356 * The callback is passed the following parameters:<ul>
11357 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11358 * <li>options {Object} The parameter to the request call.</li>
11360 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11361 * The callback is passed the following parameters:<ul>
11362 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11363 * <li>options {Object} The parameter to the request call.</li>
11365 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11366 * for the callback function. Defaults to the browser window.</li>
11367 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11368 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11369 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11370 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11371 * params for the post data. Any params will be appended to the URL.</li>
11372 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11374 * @return {Number} transactionId
11376 request : function(o){
11377 if(this.fireEvent("beforerequest", this, o) !== false){
11380 if(typeof p == "function"){
11381 p = p.call(o.scope||window, o);
11383 if(typeof p == "object"){
11384 p = Roo.urlEncode(o.params);
11386 if(this.extraParams){
11387 var extras = Roo.urlEncode(this.extraParams);
11388 p = p ? (p + '&' + extras) : extras;
11391 var url = o.url || this.url;
11392 if(typeof url == 'function'){
11393 url = url.call(o.scope||window, o);
11397 var form = Roo.getDom(o.form);
11398 url = url || form.action;
11400 var enctype = form.getAttribute("enctype");
11401 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11402 return this.doFormUpload(o, p, url);
11404 var f = Roo.lib.Ajax.serializeForm(form);
11405 p = p ? (p + '&' + f) : f;
11408 var hs = o.headers;
11409 if(this.defaultHeaders){
11410 hs = Roo.apply(hs || {}, this.defaultHeaders);
11417 success: this.handleResponse,
11418 failure: this.handleFailure,
11420 argument: {options: o},
11421 timeout : o.timeout || this.timeout
11424 var method = o.method||this.method||(p ? "POST" : "GET");
11426 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11427 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11430 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11434 }else if(this.autoAbort !== false){
11438 if((method == 'GET' && p) || o.xmlData){
11439 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11442 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11443 return this.transId;
11445 Roo.callback(o.callback, o.scope, [o, null, null]);
11451 * Determine whether this object has a request outstanding.
11452 * @param {Number} transactionId (Optional) defaults to the last transaction
11453 * @return {Boolean} True if there is an outstanding request.
11455 isLoading : function(transId){
11457 return Roo.lib.Ajax.isCallInProgress(transId);
11459 return this.transId ? true : false;
11464 * Aborts any outstanding request.
11465 * @param {Number} transactionId (Optional) defaults to the last transaction
11467 abort : function(transId){
11468 if(transId || this.isLoading()){
11469 Roo.lib.Ajax.abort(transId || this.transId);
11474 handleResponse : function(response){
11475 this.transId = false;
11476 var options = response.argument.options;
11477 response.argument = options ? options.argument : null;
11478 this.fireEvent("requestcomplete", this, response, options);
11479 Roo.callback(options.success, options.scope, [response, options]);
11480 Roo.callback(options.callback, options.scope, [options, true, response]);
11484 handleFailure : function(response, e){
11485 this.transId = false;
11486 var options = response.argument.options;
11487 response.argument = options ? options.argument : null;
11488 this.fireEvent("requestexception", this, response, options, e);
11489 Roo.callback(options.failure, options.scope, [response, options]);
11490 Roo.callback(options.callback, options.scope, [options, false, response]);
11494 doFormUpload : function(o, ps, url){
11496 var frame = document.createElement('iframe');
11499 frame.className = 'x-hidden';
11501 frame.src = Roo.SSL_SECURE_URL;
11503 document.body.appendChild(frame);
11506 document.frames[id].name = id;
11509 var form = Roo.getDom(o.form);
11511 form.method = 'POST';
11512 form.enctype = form.encoding = 'multipart/form-data';
11518 if(ps){ // add dynamic params
11520 ps = Roo.urlDecode(ps, false);
11522 if(ps.hasOwnProperty(k)){
11523 hd = document.createElement('input');
11524 hd.type = 'hidden';
11527 form.appendChild(hd);
11534 var r = { // bogus response object
11539 r.argument = o ? o.argument : null;
11544 doc = frame.contentWindow.document;
11546 doc = (frame.contentDocument || window.frames[id].document);
11548 if(doc && doc.body){
11549 r.responseText = doc.body.innerHTML;
11551 if(doc && doc.XMLDocument){
11552 r.responseXML = doc.XMLDocument;
11554 r.responseXML = doc;
11561 Roo.EventManager.removeListener(frame, 'load', cb, this);
11563 this.fireEvent("requestcomplete", this, r, o);
11564 Roo.callback(o.success, o.scope, [r, o]);
11565 Roo.callback(o.callback, o.scope, [o, true, r]);
11567 setTimeout(function(){document.body.removeChild(frame);}, 100);
11570 Roo.EventManager.on(frame, 'load', cb, this);
11573 if(hiddens){ // remove dynamic params
11574 for(var i = 0, len = hiddens.length; i < len; i++){
11575 form.removeChild(hiddens[i]);
11582 * Ext JS Library 1.1.1
11583 * Copyright(c) 2006-2007, Ext JS, LLC.
11585 * Originally Released Under LGPL - original licence link has changed is not relivant.
11588 * <script type="text/javascript">
11592 * Global Ajax request class.
11595 * @extends Roo.data.Connection
11598 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11599 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11600 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11601 * @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)
11602 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11603 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11604 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11606 Roo.Ajax = new Roo.data.Connection({
11615 * Serialize the passed form into a url encoded string
11617 * @param {String/HTMLElement} form
11620 serializeForm : function(form){
11621 return Roo.lib.Ajax.serializeForm(form);
11625 * Ext JS Library 1.1.1
11626 * Copyright(c) 2006-2007, Ext JS, LLC.
11628 * Originally Released Under LGPL - original licence link has changed is not relivant.
11631 * <script type="text/javascript">
11636 * @class Roo.UpdateManager
11637 * @extends Roo.util.Observable
11638 * Provides AJAX-style update for Element object.<br><br>
11641 * // Get it from a Roo.Element object
11642 * var el = Roo.get("foo");
11643 * var mgr = el.getUpdateManager();
11644 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11646 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11648 * // or directly (returns the same UpdateManager instance)
11649 * var mgr = new Roo.UpdateManager("myElementId");
11650 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11651 * mgr.on("update", myFcnNeedsToKnow);
11653 // short handed call directly from the element object
11654 Roo.get("foo").load({
11658 text: "Loading Foo..."
11662 * Create new UpdateManager directly.
11663 * @param {String/HTMLElement/Roo.Element} el The element to update
11664 * @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).
11666 Roo.UpdateManager = function(el, forceNew){
11668 if(!forceNew && el.updateManager){
11669 return el.updateManager;
11672 * The Element object
11673 * @type Roo.Element
11677 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11680 this.defaultUrl = null;
11684 * @event beforeupdate
11685 * Fired before an update is made, return false from your handler and the update is cancelled.
11686 * @param {Roo.Element} el
11687 * @param {String/Object/Function} url
11688 * @param {String/Object} params
11690 "beforeupdate": true,
11693 * Fired after successful update is made.
11694 * @param {Roo.Element} el
11695 * @param {Object} oResponseObject The response Object
11700 * Fired on update failure.
11701 * @param {Roo.Element} el
11702 * @param {Object} oResponseObject The response Object
11706 var d = Roo.UpdateManager.defaults;
11708 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11711 this.sslBlankUrl = d.sslBlankUrl;
11713 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11716 this.disableCaching = d.disableCaching;
11718 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11721 this.indicatorText = d.indicatorText;
11723 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11726 this.showLoadIndicator = d.showLoadIndicator;
11728 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11731 this.timeout = d.timeout;
11734 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11737 this.loadScripts = d.loadScripts;
11740 * Transaction object of current executing transaction
11742 this.transaction = null;
11747 this.autoRefreshProcId = null;
11749 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11752 this.refreshDelegate = this.refresh.createDelegate(this);
11754 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11757 this.updateDelegate = this.update.createDelegate(this);
11759 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11762 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11766 this.successDelegate = this.processSuccess.createDelegate(this);
11770 this.failureDelegate = this.processFailure.createDelegate(this);
11772 if(!this.renderer){
11774 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11776 this.renderer = new Roo.UpdateManager.BasicRenderer();
11779 Roo.UpdateManager.superclass.constructor.call(this);
11782 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11784 * Get the Element this UpdateManager is bound to
11785 * @return {Roo.Element} The element
11787 getEl : function(){
11791 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11792 * @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:
11795 url: "your-url.php",<br/>
11796 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11797 callback: yourFunction,<br/>
11798 scope: yourObject, //(optional scope) <br/>
11799 discardUrl: false, <br/>
11800 nocache: false,<br/>
11801 text: "Loading...",<br/>
11803 scripts: false<br/>
11806 * The only required property is url. The optional properties nocache, text and scripts
11807 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11808 * @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}
11809 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11810 * @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.
11812 update : function(url, params, callback, discardUrl){
11813 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11814 var method = this.method,
11816 if(typeof url == "object"){ // must be config object
11819 params = params || cfg.params;
11820 callback = callback || cfg.callback;
11821 discardUrl = discardUrl || cfg.discardUrl;
11822 if(callback && cfg.scope){
11823 callback = callback.createDelegate(cfg.scope);
11825 if(typeof cfg.method != "undefined"){method = cfg.method;};
11826 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11827 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11828 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11829 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11831 this.showLoading();
11833 this.defaultUrl = url;
11835 if(typeof url == "function"){
11836 url = url.call(this);
11839 method = method || (params ? "POST" : "GET");
11840 if(method == "GET"){
11841 url = this.prepareUrl(url);
11844 var o = Roo.apply(cfg ||{}, {
11847 success: this.successDelegate,
11848 failure: this.failureDelegate,
11849 callback: undefined,
11850 timeout: (this.timeout*1000),
11851 argument: {"url": url, "form": null, "callback": callback, "params": params}
11853 Roo.log("updated manager called with timeout of " + o.timeout);
11854 this.transaction = Roo.Ajax.request(o);
11859 * 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.
11860 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11861 * @param {String/HTMLElement} form The form Id or form element
11862 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11863 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11864 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11866 formUpdate : function(form, url, reset, callback){
11867 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11868 if(typeof url == "function"){
11869 url = url.call(this);
11871 form = Roo.getDom(form);
11872 this.transaction = Roo.Ajax.request({
11875 success: this.successDelegate,
11876 failure: this.failureDelegate,
11877 timeout: (this.timeout*1000),
11878 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11880 this.showLoading.defer(1, this);
11885 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11886 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11888 refresh : function(callback){
11889 if(this.defaultUrl == null){
11892 this.update(this.defaultUrl, null, callback, true);
11896 * Set this element to auto refresh.
11897 * @param {Number} interval How often to update (in seconds).
11898 * @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)
11899 * @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}
11900 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11901 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11903 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11905 this.update(url || this.defaultUrl, params, callback, true);
11907 if(this.autoRefreshProcId){
11908 clearInterval(this.autoRefreshProcId);
11910 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11914 * Stop auto refresh on this element.
11916 stopAutoRefresh : function(){
11917 if(this.autoRefreshProcId){
11918 clearInterval(this.autoRefreshProcId);
11919 delete this.autoRefreshProcId;
11923 isAutoRefreshing : function(){
11924 return this.autoRefreshProcId ? true : false;
11927 * Called to update the element to "Loading" state. Override to perform custom action.
11929 showLoading : function(){
11930 if(this.showLoadIndicator){
11931 this.el.update(this.indicatorText);
11936 * Adds unique parameter to query string if disableCaching = true
11939 prepareUrl : function(url){
11940 if(this.disableCaching){
11941 var append = "_dc=" + (new Date().getTime());
11942 if(url.indexOf("?") !== -1){
11943 url += "&" + append;
11945 url += "?" + append;
11954 processSuccess : function(response){
11955 this.transaction = null;
11956 if(response.argument.form && response.argument.reset){
11957 try{ // put in try/catch since some older FF releases had problems with this
11958 response.argument.form.reset();
11961 if(this.loadScripts){
11962 this.renderer.render(this.el, response, this,
11963 this.updateComplete.createDelegate(this, [response]));
11965 this.renderer.render(this.el, response, this);
11966 this.updateComplete(response);
11970 updateComplete : function(response){
11971 this.fireEvent("update", this.el, response);
11972 if(typeof response.argument.callback == "function"){
11973 response.argument.callback(this.el, true, response);
11980 processFailure : function(response){
11981 this.transaction = null;
11982 this.fireEvent("failure", this.el, response);
11983 if(typeof response.argument.callback == "function"){
11984 response.argument.callback(this.el, false, response);
11989 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11990 * @param {Object} renderer The object implementing the render() method
11992 setRenderer : function(renderer){
11993 this.renderer = renderer;
11996 getRenderer : function(){
11997 return this.renderer;
12001 * Set the defaultUrl used for updates
12002 * @param {String/Function} defaultUrl The url or a function to call to get the url
12004 setDefaultUrl : function(defaultUrl){
12005 this.defaultUrl = defaultUrl;
12009 * Aborts the executing transaction
12011 abort : function(){
12012 if(this.transaction){
12013 Roo.Ajax.abort(this.transaction);
12018 * Returns true if an update is in progress
12019 * @return {Boolean}
12021 isUpdating : function(){
12022 if(this.transaction){
12023 return Roo.Ajax.isLoading(this.transaction);
12030 * @class Roo.UpdateManager.defaults
12031 * @static (not really - but it helps the doc tool)
12032 * The defaults collection enables customizing the default properties of UpdateManager
12034 Roo.UpdateManager.defaults = {
12036 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12042 * True to process scripts by default (Defaults to false).
12045 loadScripts : false,
12048 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12051 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12053 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12056 disableCaching : false,
12058 * Whether to show indicatorText when loading (Defaults to true).
12061 showLoadIndicator : true,
12063 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12066 indicatorText : '<div class="loading-indicator">Loading...</div>'
12070 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12072 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12073 * @param {String/HTMLElement/Roo.Element} el The element to update
12074 * @param {String} url The url
12075 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12076 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12079 * @member Roo.UpdateManager
12081 Roo.UpdateManager.updateElement = function(el, url, params, options){
12082 var um = Roo.get(el, true).getUpdateManager();
12083 Roo.apply(um, options);
12084 um.update(url, params, options ? options.callback : null);
12086 // alias for backwards compat
12087 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12089 * @class Roo.UpdateManager.BasicRenderer
12090 * Default Content renderer. Updates the elements innerHTML with the responseText.
12092 Roo.UpdateManager.BasicRenderer = function(){};
12094 Roo.UpdateManager.BasicRenderer.prototype = {
12096 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12097 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12098 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12099 * @param {Roo.Element} el The element being rendered
12100 * @param {Object} response The YUI Connect response object
12101 * @param {UpdateManager} updateManager The calling update manager
12102 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12104 render : function(el, response, updateManager, callback){
12105 el.update(response.responseText, updateManager.loadScripts, callback);
12111 * (c)) Alan Knowles
12117 * @class Roo.DomTemplate
12118 * @extends Roo.Template
12119 * An effort at a dom based template engine..
12121 * Similar to XTemplate, except it uses dom parsing to create the template..
12123 * Supported features:
12128 {a_variable} - output encoded.
12129 {a_variable.format:("Y-m-d")} - call a method on the variable
12130 {a_variable:raw} - unencoded output
12131 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12132 {a_variable:this.method_on_template(...)} - call a method on the template object.
12137 <div roo-for="a_variable or condition.."></div>
12138 <div roo-if="a_variable or condition"></div>
12139 <div roo-exec="some javascript"></div>
12140 <div roo-name="named_template"></div>
12145 Roo.DomTemplate = function()
12147 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12154 Roo.extend(Roo.DomTemplate, Roo.Template, {
12156 * id counter for sub templates.
12160 * flag to indicate if dom parser is inside a pre,
12161 * it will strip whitespace if not.
12166 * The various sub templates
12174 * basic tag replacing syntax
12177 * // you can fake an object call by doing this
12181 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12182 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12184 iterChild : function (node, method) {
12186 var oldPre = this.inPre;
12187 if (node.tagName == 'PRE') {
12190 for( var i = 0; i < node.childNodes.length; i++) {
12191 method.call(this, node.childNodes[i]);
12193 this.inPre = oldPre;
12199 * compile the template
12201 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12204 compile: function()
12208 // covert the html into DOM...
12212 doc = document.implementation.createHTMLDocument("");
12213 doc.documentElement.innerHTML = this.html ;
12214 div = doc.documentElement;
12216 // old IE... - nasty -- it causes all sorts of issues.. with
12217 // images getting pulled from server..
12218 div = document.createElement('div');
12219 div.innerHTML = this.html;
12221 //doc.documentElement.innerHTML = htmlBody
12227 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12229 var tpls = this.tpls;
12231 // create a top level template from the snippet..
12233 //Roo.log(div.innerHTML);
12240 body : div.innerHTML,
12253 Roo.each(tpls, function(tp){
12254 this.compileTpl(tp);
12255 this.tpls[tp.id] = tp;
12258 this.master = tpls[0];
12264 compileNode : function(node, istop) {
12269 // skip anything not a tag..
12270 if (node.nodeType != 1) {
12271 if (node.nodeType == 3 && !this.inPre) {
12272 // reduce white space..
12273 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12296 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12297 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12298 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12299 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12305 // just itterate children..
12306 this.iterChild(node,this.compileNode);
12309 tpl.uid = this.id++;
12310 tpl.value = node.getAttribute('roo-' + tpl.attr);
12311 node.removeAttribute('roo-'+ tpl.attr);
12312 if (tpl.attr != 'name') {
12313 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12314 node.parentNode.replaceChild(placeholder, node);
12317 var placeholder = document.createElement('span');
12318 placeholder.className = 'roo-tpl-' + tpl.value;
12319 node.parentNode.replaceChild(placeholder, node);
12322 // parent now sees '{domtplXXXX}
12323 this.iterChild(node,this.compileNode);
12325 // we should now have node body...
12326 var div = document.createElement('div');
12327 div.appendChild(node);
12329 // this has the unfortunate side effect of converting tagged attributes
12330 // eg. href="{...}" into %7C...%7D
12331 // this has been fixed by searching for those combo's although it's a bit hacky..
12334 tpl.body = div.innerHTML;
12341 switch (tpl.value) {
12342 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12343 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12344 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12349 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12353 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12357 tpl.id = tpl.value; // replace non characters???
12363 this.tpls.push(tpl);
12373 * Compile a segment of the template into a 'sub-template'
12379 compileTpl : function(tpl)
12381 var fm = Roo.util.Format;
12382 var useF = this.disableFormats !== true;
12384 var sep = Roo.isGecko ? "+\n" : ",\n";
12386 var undef = function(str) {
12387 Roo.debug && Roo.log("Property not found :" + str);
12391 //Roo.log(tpl.body);
12395 var fn = function(m, lbrace, name, format, args)
12398 //Roo.log(arguments);
12399 args = args ? args.replace(/\\'/g,"'") : args;
12400 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12401 if (typeof(format) == 'undefined') {
12402 format = 'htmlEncode';
12404 if (format == 'raw' ) {
12408 if(name.substr(0, 6) == 'domtpl'){
12409 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12412 // build an array of options to determine if value is undefined..
12414 // basically get 'xxxx.yyyy' then do
12415 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12416 // (function () { Roo.log("Property not found"); return ''; })() :
12421 Roo.each(name.split('.'), function(st) {
12422 lookfor += (lookfor.length ? '.': '') + st;
12423 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12426 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12429 if(format && useF){
12431 args = args ? ',' + args : "";
12433 if(format.substr(0, 5) != "this."){
12434 format = "fm." + format + '(';
12436 format = 'this.call("'+ format.substr(5) + '", ';
12440 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12443 if (args && args.length) {
12444 // called with xxyx.yuu:(test,test)
12446 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12448 // raw.. - :raw modifier..
12449 return "'"+ sep + udef_st + name + ")"+sep+"'";
12453 // branched to use + in gecko and [].join() in others
12455 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12456 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12459 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12460 body.push(tpl.body.replace(/(\r\n|\n)/g,
12461 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12462 body.push("'].join('');};};");
12463 body = body.join('');
12466 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12468 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12475 * same as applyTemplate, except it's done to one of the subTemplates
12476 * when using named templates, you can do:
12478 * var str = pl.applySubTemplate('your-name', values);
12481 * @param {Number} id of the template
12482 * @param {Object} values to apply to template
12483 * @param {Object} parent (normaly the instance of this object)
12485 applySubTemplate : function(id, values, parent)
12489 var t = this.tpls[id];
12493 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12494 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12498 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12505 if(t.execCall && t.execCall.call(this, values, parent)){
12509 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12515 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12516 parent = t.target ? values : parent;
12517 if(t.forCall && vs instanceof Array){
12519 for(var i = 0, len = vs.length; i < len; i++){
12521 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12523 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12525 //Roo.log(t.compiled);
12529 return buf.join('');
12532 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12537 return t.compiled.call(this, vs, parent);
12539 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12541 //Roo.log(t.compiled);
12549 applyTemplate : function(values){
12550 return this.master.compiled.call(this, values, {});
12551 //var s = this.subs;
12554 apply : function(){
12555 return this.applyTemplate.apply(this, arguments);
12560 Roo.DomTemplate.from = function(el){
12561 el = Roo.getDom(el);
12562 return new Roo.Domtemplate(el.value || el.innerHTML);
12565 * Ext JS Library 1.1.1
12566 * Copyright(c) 2006-2007, Ext JS, LLC.
12568 * Originally Released Under LGPL - original licence link has changed is not relivant.
12571 * <script type="text/javascript">
12575 * @class Roo.util.DelayedTask
12576 * Provides a convenient method of performing setTimeout where a new
12577 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12578 * You can use this class to buffer
12579 * the keypress events for a certain number of milliseconds, and perform only if they stop
12580 * for that amount of time.
12581 * @constructor The parameters to this constructor serve as defaults and are not required.
12582 * @param {Function} fn (optional) The default function to timeout
12583 * @param {Object} scope (optional) The default scope of that timeout
12584 * @param {Array} args (optional) The default Array of arguments
12586 Roo.util.DelayedTask = function(fn, scope, args){
12587 var id = null, d, t;
12589 var call = function(){
12590 var now = new Date().getTime();
12594 fn.apply(scope, args || []);
12598 * Cancels any pending timeout and queues a new one
12599 * @param {Number} delay The milliseconds to delay
12600 * @param {Function} newFn (optional) Overrides function passed to constructor
12601 * @param {Object} newScope (optional) Overrides scope passed to constructor
12602 * @param {Array} newArgs (optional) Overrides args passed to constructor
12604 this.delay = function(delay, newFn, newScope, newArgs){
12605 if(id && delay != d){
12609 t = new Date().getTime();
12611 scope = newScope || scope;
12612 args = newArgs || args;
12614 id = setInterval(call, d);
12619 * Cancel the last queued timeout
12621 this.cancel = function(){
12629 * Ext JS Library 1.1.1
12630 * Copyright(c) 2006-2007, Ext JS, LLC.
12632 * Originally Released Under LGPL - original licence link has changed is not relivant.
12635 * <script type="text/javascript">
12639 Roo.util.TaskRunner = function(interval){
12640 interval = interval || 10;
12641 var tasks = [], removeQueue = [];
12643 var running = false;
12645 var stopThread = function(){
12651 var startThread = function(){
12654 id = setInterval(runTasks, interval);
12658 var removeTask = function(task){
12659 removeQueue.push(task);
12665 var runTasks = function(){
12666 if(removeQueue.length > 0){
12667 for(var i = 0, len = removeQueue.length; i < len; i++){
12668 tasks.remove(removeQueue[i]);
12671 if(tasks.length < 1){
12676 var now = new Date().getTime();
12677 for(var i = 0, len = tasks.length; i < len; ++i){
12679 var itime = now - t.taskRunTime;
12680 if(t.interval <= itime){
12681 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12682 t.taskRunTime = now;
12683 if(rt === false || t.taskRunCount === t.repeat){
12688 if(t.duration && t.duration <= (now - t.taskStartTime)){
12695 * Queues a new task.
12696 * @param {Object} task
12698 this.start = function(task){
12700 task.taskStartTime = new Date().getTime();
12701 task.taskRunTime = 0;
12702 task.taskRunCount = 0;
12707 this.stop = function(task){
12712 this.stopAll = function(){
12714 for(var i = 0, len = tasks.length; i < len; i++){
12715 if(tasks[i].onStop){
12724 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12726 * Ext JS Library 1.1.1
12727 * Copyright(c) 2006-2007, Ext JS, LLC.
12729 * Originally Released Under LGPL - original licence link has changed is not relivant.
12732 * <script type="text/javascript">
12737 * @class Roo.util.MixedCollection
12738 * @extends Roo.util.Observable
12739 * A Collection class that maintains both numeric indexes and keys and exposes events.
12741 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12742 * collection (defaults to false)
12743 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12744 * and return the key value for that item. This is used when available to look up the key on items that
12745 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12746 * equivalent to providing an implementation for the {@link #getKey} method.
12748 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12756 * Fires when the collection is cleared.
12761 * Fires when an item is added to the collection.
12762 * @param {Number} index The index at which the item was added.
12763 * @param {Object} o The item added.
12764 * @param {String} key The key associated with the added item.
12769 * Fires when an item is replaced in the collection.
12770 * @param {String} key he key associated with the new added.
12771 * @param {Object} old The item being replaced.
12772 * @param {Object} new The new item.
12777 * Fires when an item is removed from the collection.
12778 * @param {Object} o The item being removed.
12779 * @param {String} key (optional) The key associated with the removed item.
12784 this.allowFunctions = allowFunctions === true;
12786 this.getKey = keyFn;
12788 Roo.util.MixedCollection.superclass.constructor.call(this);
12791 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12792 allowFunctions : false,
12795 * Adds an item to the collection.
12796 * @param {String} key The key to associate with the item
12797 * @param {Object} o The item to add.
12798 * @return {Object} The item added.
12800 add : function(key, o){
12801 if(arguments.length == 1){
12803 key = this.getKey(o);
12805 if(typeof key == "undefined" || key === null){
12807 this.items.push(o);
12808 this.keys.push(null);
12810 var old = this.map[key];
12812 return this.replace(key, o);
12815 this.items.push(o);
12817 this.keys.push(key);
12819 this.fireEvent("add", this.length-1, o, key);
12824 * MixedCollection has a generic way to fetch keys if you implement getKey.
12827 var mc = new Roo.util.MixedCollection();
12828 mc.add(someEl.dom.id, someEl);
12829 mc.add(otherEl.dom.id, otherEl);
12833 var mc = new Roo.util.MixedCollection();
12834 mc.getKey = function(el){
12840 // or via the constructor
12841 var mc = new Roo.util.MixedCollection(false, function(el){
12847 * @param o {Object} The item for which to find the key.
12848 * @return {Object} The key for the passed item.
12850 getKey : function(o){
12855 * Replaces an item in the collection.
12856 * @param {String} key The key associated with the item to replace, or the item to replace.
12857 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12858 * @return {Object} The new item.
12860 replace : function(key, o){
12861 if(arguments.length == 1){
12863 key = this.getKey(o);
12865 var old = this.item(key);
12866 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12867 return this.add(key, o);
12869 var index = this.indexOfKey(key);
12870 this.items[index] = o;
12872 this.fireEvent("replace", key, old, o);
12877 * Adds all elements of an Array or an Object to the collection.
12878 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12879 * an Array of values, each of which are added to the collection.
12881 addAll : function(objs){
12882 if(arguments.length > 1 || objs instanceof Array){
12883 var args = arguments.length > 1 ? arguments : objs;
12884 for(var i = 0, len = args.length; i < len; i++){
12888 for(var key in objs){
12889 if(this.allowFunctions || typeof objs[key] != "function"){
12890 this.add(key, objs[key]);
12897 * Executes the specified function once for every item in the collection, passing each
12898 * item as the first and only parameter. returning false from the function will stop the iteration.
12899 * @param {Function} fn The function to execute for each item.
12900 * @param {Object} scope (optional) The scope in which to execute the function.
12902 each : function(fn, scope){
12903 var items = [].concat(this.items); // each safe for removal
12904 for(var i = 0, len = items.length; i < len; i++){
12905 if(fn.call(scope || items[i], items[i], i, len) === false){
12912 * Executes the specified function once for every key in the collection, passing each
12913 * key, and its associated item as the first two parameters.
12914 * @param {Function} fn The function to execute for each item.
12915 * @param {Object} scope (optional) The scope in which to execute the function.
12917 eachKey : function(fn, scope){
12918 for(var i = 0, len = this.keys.length; i < len; i++){
12919 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12924 * Returns the first item in the collection which elicits a true return value from the
12925 * passed selection function.
12926 * @param {Function} fn The selection function to execute for each item.
12927 * @param {Object} scope (optional) The scope in which to execute the function.
12928 * @return {Object} The first item in the collection which returned true from the selection function.
12930 find : function(fn, scope){
12931 for(var i = 0, len = this.items.length; i < len; i++){
12932 if(fn.call(scope || window, this.items[i], this.keys[i])){
12933 return this.items[i];
12940 * Inserts an item at the specified index in the collection.
12941 * @param {Number} index The index to insert the item at.
12942 * @param {String} key The key to associate with the new item, or the item itself.
12943 * @param {Object} o (optional) If the second parameter was a key, the new item.
12944 * @return {Object} The item inserted.
12946 insert : function(index, key, o){
12947 if(arguments.length == 2){
12949 key = this.getKey(o);
12951 if(index >= this.length){
12952 return this.add(key, o);
12955 this.items.splice(index, 0, o);
12956 if(typeof key != "undefined" && key != null){
12959 this.keys.splice(index, 0, key);
12960 this.fireEvent("add", index, o, key);
12965 * Removed an item from the collection.
12966 * @param {Object} o The item to remove.
12967 * @return {Object} The item removed.
12969 remove : function(o){
12970 return this.removeAt(this.indexOf(o));
12974 * Remove an item from a specified index in the collection.
12975 * @param {Number} index The index within the collection of the item to remove.
12977 removeAt : function(index){
12978 if(index < this.length && index >= 0){
12980 var o = this.items[index];
12981 this.items.splice(index, 1);
12982 var key = this.keys[index];
12983 if(typeof key != "undefined"){
12984 delete this.map[key];
12986 this.keys.splice(index, 1);
12987 this.fireEvent("remove", o, key);
12992 * Removed an item associated with the passed key fom the collection.
12993 * @param {String} key The key of the item to remove.
12995 removeKey : function(key){
12996 return this.removeAt(this.indexOfKey(key));
13000 * Returns the number of items in the collection.
13001 * @return {Number} the number of items in the collection.
13003 getCount : function(){
13004 return this.length;
13008 * Returns index within the collection of the passed Object.
13009 * @param {Object} o The item to find the index of.
13010 * @return {Number} index of the item.
13012 indexOf : function(o){
13013 if(!this.items.indexOf){
13014 for(var i = 0, len = this.items.length; i < len; i++){
13015 if(this.items[i] == o) return i;
13019 return this.items.indexOf(o);
13024 * Returns index within the collection of the passed key.
13025 * @param {String} key The key to find the index of.
13026 * @return {Number} index of the key.
13028 indexOfKey : function(key){
13029 if(!this.keys.indexOf){
13030 for(var i = 0, len = this.keys.length; i < len; i++){
13031 if(this.keys[i] == key) return i;
13035 return this.keys.indexOf(key);
13040 * Returns the item associated with the passed key OR index. Key has priority over index.
13041 * @param {String/Number} key The key or index of the item.
13042 * @return {Object} The item associated with the passed key.
13044 item : function(key){
13045 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13046 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13050 * Returns the item at the specified index.
13051 * @param {Number} index The index of the item.
13054 itemAt : function(index){
13055 return this.items[index];
13059 * Returns the item associated with the passed key.
13060 * @param {String/Number} key The key of the item.
13061 * @return {Object} The item associated with the passed key.
13063 key : function(key){
13064 return this.map[key];
13068 * Returns true if the collection contains the passed Object as an item.
13069 * @param {Object} o The Object to look for in the collection.
13070 * @return {Boolean} True if the collection contains the Object as an item.
13072 contains : function(o){
13073 return this.indexOf(o) != -1;
13077 * Returns true if the collection contains the passed Object as a key.
13078 * @param {String} key The key to look for in the collection.
13079 * @return {Boolean} True if the collection contains the Object as a key.
13081 containsKey : function(key){
13082 return typeof this.map[key] != "undefined";
13086 * Removes all items from the collection.
13088 clear : function(){
13093 this.fireEvent("clear");
13097 * Returns the first item in the collection.
13098 * @return {Object} the first item in the collection..
13100 first : function(){
13101 return this.items[0];
13105 * Returns the last item in the collection.
13106 * @return {Object} the last item in the collection..
13109 return this.items[this.length-1];
13112 _sort : function(property, dir, fn){
13113 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13114 fn = fn || function(a, b){
13117 var c = [], k = this.keys, items = this.items;
13118 for(var i = 0, len = items.length; i < len; i++){
13119 c[c.length] = {key: k[i], value: items[i], index: i};
13121 c.sort(function(a, b){
13122 var v = fn(a[property], b[property]) * dsc;
13124 v = (a.index < b.index ? -1 : 1);
13128 for(var i = 0, len = c.length; i < len; i++){
13129 items[i] = c[i].value;
13132 this.fireEvent("sort", this);
13136 * Sorts this collection with the passed comparison function
13137 * @param {String} direction (optional) "ASC" or "DESC"
13138 * @param {Function} fn (optional) comparison function
13140 sort : function(dir, fn){
13141 this._sort("value", dir, fn);
13145 * Sorts this collection by keys
13146 * @param {String} direction (optional) "ASC" or "DESC"
13147 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13149 keySort : function(dir, fn){
13150 this._sort("key", dir, fn || function(a, b){
13151 return String(a).toUpperCase()-String(b).toUpperCase();
13156 * Returns a range of items in this collection
13157 * @param {Number} startIndex (optional) defaults to 0
13158 * @param {Number} endIndex (optional) default to the last item
13159 * @return {Array} An array of items
13161 getRange : function(start, end){
13162 var items = this.items;
13163 if(items.length < 1){
13166 start = start || 0;
13167 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13170 for(var i = start; i <= end; i++) {
13171 r[r.length] = items[i];
13174 for(var i = start; i >= end; i--) {
13175 r[r.length] = items[i];
13182 * Filter the <i>objects</i> in this collection by a specific property.
13183 * Returns a new collection that has been filtered.
13184 * @param {String} property A property on your objects
13185 * @param {String/RegExp} value Either string that the property values
13186 * should start with or a RegExp to test against the property
13187 * @return {MixedCollection} The new filtered collection
13189 filter : function(property, value){
13190 if(!value.exec){ // not a regex
13191 value = String(value);
13192 if(value.length == 0){
13193 return this.clone();
13195 value = new RegExp("^" + Roo.escapeRe(value), "i");
13197 return this.filterBy(function(o){
13198 return o && value.test(o[property]);
13203 * Filter by a function. * Returns a new collection that has been filtered.
13204 * The passed function will be called with each
13205 * object in the collection. If the function returns true, the value is included
13206 * otherwise it is filtered.
13207 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13208 * @param {Object} scope (optional) The scope of the function (defaults to this)
13209 * @return {MixedCollection} The new filtered collection
13211 filterBy : function(fn, scope){
13212 var r = new Roo.util.MixedCollection();
13213 r.getKey = this.getKey;
13214 var k = this.keys, it = this.items;
13215 for(var i = 0, len = it.length; i < len; i++){
13216 if(fn.call(scope||this, it[i], k[i])){
13217 r.add(k[i], it[i]);
13224 * Creates a duplicate of this collection
13225 * @return {MixedCollection}
13227 clone : function(){
13228 var r = new Roo.util.MixedCollection();
13229 var k = this.keys, it = this.items;
13230 for(var i = 0, len = it.length; i < len; i++){
13231 r.add(k[i], it[i]);
13233 r.getKey = this.getKey;
13238 * Returns the item associated with the passed key or index.
13240 * @param {String/Number} key The key or index of the item.
13241 * @return {Object} The item associated with the passed key.
13243 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13245 * Ext JS Library 1.1.1
13246 * Copyright(c) 2006-2007, Ext JS, LLC.
13248 * Originally Released Under LGPL - original licence link has changed is not relivant.
13251 * <script type="text/javascript">
13254 * @class Roo.util.JSON
13255 * Modified version of Douglas Crockford"s json.js that doesn"t
13256 * mess with the Object prototype
13257 * http://www.json.org/js.html
13260 Roo.util.JSON = new (function(){
13261 var useHasOwn = {}.hasOwnProperty ? true : false;
13263 // crashes Safari in some instances
13264 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13266 var pad = function(n) {
13267 return n < 10 ? "0" + n : n;
13280 var encodeString = function(s){
13281 if (/["\\\x00-\x1f]/.test(s)) {
13282 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13287 c = b.charCodeAt();
13289 Math.floor(c / 16).toString(16) +
13290 (c % 16).toString(16);
13293 return '"' + s + '"';
13296 var encodeArray = function(o){
13297 var a = ["["], b, i, l = o.length, v;
13298 for (i = 0; i < l; i += 1) {
13300 switch (typeof v) {
13309 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13317 var encodeDate = function(o){
13318 return '"' + o.getFullYear() + "-" +
13319 pad(o.getMonth() + 1) + "-" +
13320 pad(o.getDate()) + "T" +
13321 pad(o.getHours()) + ":" +
13322 pad(o.getMinutes()) + ":" +
13323 pad(o.getSeconds()) + '"';
13327 * Encodes an Object, Array or other value
13328 * @param {Mixed} o The variable to encode
13329 * @return {String} The JSON string
13331 this.encode = function(o)
13333 // should this be extended to fully wrap stringify..
13335 if(typeof o == "undefined" || o === null){
13337 }else if(o instanceof Array){
13338 return encodeArray(o);
13339 }else if(o instanceof Date){
13340 return encodeDate(o);
13341 }else if(typeof o == "string"){
13342 return encodeString(o);
13343 }else if(typeof o == "number"){
13344 return isFinite(o) ? String(o) : "null";
13345 }else if(typeof o == "boolean"){
13348 var a = ["{"], b, i, v;
13350 if(!useHasOwn || o.hasOwnProperty(i)) {
13352 switch (typeof v) {
13361 a.push(this.encode(i), ":",
13362 v === null ? "null" : this.encode(v));
13373 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13374 * @param {String} json The JSON string
13375 * @return {Object} The resulting object
13377 this.decode = function(json){
13379 return /** eval:var:json */ eval("(" + json + ')');
13383 * Shorthand for {@link Roo.util.JSON#encode}
13384 * @member Roo encode
13386 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13388 * Shorthand for {@link Roo.util.JSON#decode}
13389 * @member Roo decode
13391 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13394 * Ext JS Library 1.1.1
13395 * Copyright(c) 2006-2007, Ext JS, LLC.
13397 * Originally Released Under LGPL - original licence link has changed is not relivant.
13400 * <script type="text/javascript">
13404 * @class Roo.util.Format
13405 * Reusable data formatting functions
13408 Roo.util.Format = function(){
13409 var trimRe = /^\s+|\s+$/g;
13412 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13413 * @param {String} value The string to truncate
13414 * @param {Number} length The maximum length to allow before truncating
13415 * @return {String} The converted text
13417 ellipsis : function(value, len){
13418 if(value && value.length > len){
13419 return value.substr(0, len-3)+"...";
13425 * Checks a reference and converts it to empty string if it is undefined
13426 * @param {Mixed} value Reference to check
13427 * @return {Mixed} Empty string if converted, otherwise the original value
13429 undef : function(value){
13430 return typeof value != "undefined" ? value : "";
13434 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13435 * @param {String} value The string to encode
13436 * @return {String} The encoded text
13438 htmlEncode : function(value){
13439 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13443 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13444 * @param {String} value The string to decode
13445 * @return {String} The decoded text
13447 htmlDecode : function(value){
13448 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13452 * Trims any whitespace from either side of a string
13453 * @param {String} value The text to trim
13454 * @return {String} The trimmed text
13456 trim : function(value){
13457 return String(value).replace(trimRe, "");
13461 * Returns a substring from within an original string
13462 * @param {String} value The original text
13463 * @param {Number} start The start index of the substring
13464 * @param {Number} length The length of the substring
13465 * @return {String} The substring
13467 substr : function(value, start, length){
13468 return String(value).substr(start, length);
13472 * Converts a string to all lower case letters
13473 * @param {String} value The text to convert
13474 * @return {String} The converted text
13476 lowercase : function(value){
13477 return String(value).toLowerCase();
13481 * Converts a string to all upper case letters
13482 * @param {String} value The text to convert
13483 * @return {String} The converted text
13485 uppercase : function(value){
13486 return String(value).toUpperCase();
13490 * Converts the first character only of a string to upper case
13491 * @param {String} value The text to convert
13492 * @return {String} The converted text
13494 capitalize : function(value){
13495 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13499 call : function(value, fn){
13500 if(arguments.length > 2){
13501 var args = Array.prototype.slice.call(arguments, 2);
13502 args.unshift(value);
13504 return /** eval:var:value */ eval(fn).apply(window, args);
13506 /** eval:var:value */
13507 return /** eval:var:value */ eval(fn).call(window, value);
13513 * safer version of Math.toFixed..??/
13514 * @param {Number/String} value The numeric value to format
13515 * @param {Number/String} value Decimal places
13516 * @return {String} The formatted currency string
13518 toFixed : function(v, n)
13520 // why not use to fixed - precision is buggered???
13522 return Math.round(v-0);
13524 var fact = Math.pow(10,n+1);
13525 v = (Math.round((v-0)*fact))/fact;
13526 var z = (''+fact).substring(2);
13527 if (v == Math.floor(v)) {
13528 return Math.floor(v) + '.' + z;
13531 // now just padd decimals..
13532 var ps = String(v).split('.');
13533 var fd = (ps[1] + z);
13534 var r = fd.substring(0,n);
13535 var rm = fd.substring(n);
13537 return ps[0] + '.' + r;
13539 r*=1; // turn it into a number;
13541 if (String(r).length != n) {
13544 r = String(r).substring(1); // chop the end off.
13547 return ps[0] + '.' + r;
13552 * Format a number as US currency
13553 * @param {Number/String} value The numeric value to format
13554 * @return {String} The formatted currency string
13556 usMoney : function(v){
13557 return '$' + Roo.util.Format.number(v);
13562 * eventually this should probably emulate php's number_format
13563 * @param {Number/String} value The numeric value to format
13564 * @param {Number} decimals number of decimal places
13565 * @return {String} The formatted currency string
13567 number : function(v,decimals)
13569 // multiply and round.
13570 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13571 var mul = Math.pow(10, decimals);
13572 var zero = String(mul).substring(1);
13573 v = (Math.round((v-0)*mul))/mul;
13575 // if it's '0' number.. then
13577 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13579 var ps = v.split('.');
13583 var r = /(\d+)(\d{3})/;
13585 while (r.test(whole)) {
13586 whole = whole.replace(r, '$1' + ',' + '$2');
13592 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13593 // does not have decimals
13594 (decimals ? ('.' + zero) : '');
13597 return whole + sub ;
13601 * Parse a value into a formatted date using the specified format pattern.
13602 * @param {Mixed} value The value to format
13603 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13604 * @return {String} The formatted date string
13606 date : function(v, format){
13610 if(!(v instanceof Date)){
13611 v = new Date(Date.parse(v));
13613 return v.dateFormat(format || Roo.util.Format.defaults.date);
13617 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13618 * @param {String} format Any valid date format string
13619 * @return {Function} The date formatting function
13621 dateRenderer : function(format){
13622 return function(v){
13623 return Roo.util.Format.date(v, format);
13628 stripTagsRE : /<\/?[^>]+>/gi,
13631 * Strips all HTML tags
13632 * @param {Mixed} value The text from which to strip tags
13633 * @return {String} The stripped text
13635 stripTags : function(v){
13636 return !v ? v : String(v).replace(this.stripTagsRE, "");
13640 Roo.util.Format.defaults = {
13644 * Ext JS Library 1.1.1
13645 * Copyright(c) 2006-2007, Ext JS, LLC.
13647 * Originally Released Under LGPL - original licence link has changed is not relivant.
13650 * <script type="text/javascript">
13657 * @class Roo.MasterTemplate
13658 * @extends Roo.Template
13659 * Provides a template that can have child templates. The syntax is:
13661 var t = new Roo.MasterTemplate(
13662 '<select name="{name}">',
13663 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13666 t.add('options', {value: 'foo', text: 'bar'});
13667 // or you can add multiple child elements in one shot
13668 t.addAll('options', [
13669 {value: 'foo', text: 'bar'},
13670 {value: 'foo2', text: 'bar2'},
13671 {value: 'foo3', text: 'bar3'}
13673 // then append, applying the master template values
13674 t.append('my-form', {name: 'my-select'});
13676 * A name attribute for the child template is not required if you have only one child
13677 * template or you want to refer to them by index.
13679 Roo.MasterTemplate = function(){
13680 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13681 this.originalHtml = this.html;
13683 var m, re = this.subTemplateRe;
13686 while(m = re.exec(this.html)){
13687 var name = m[1], content = m[2];
13692 tpl : new Roo.Template(content)
13695 st[name] = st[subIndex];
13697 st[subIndex].tpl.compile();
13698 st[subIndex].tpl.call = this.call.createDelegate(this);
13701 this.subCount = subIndex;
13704 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13706 * The regular expression used to match sub templates
13710 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13713 * Applies the passed values to a child template.
13714 * @param {String/Number} name (optional) The name or index of the child template
13715 * @param {Array/Object} values The values to be applied to the template
13716 * @return {MasterTemplate} this
13718 add : function(name, values){
13719 if(arguments.length == 1){
13720 values = arguments[0];
13723 var s = this.subs[name];
13724 s.buffer[s.buffer.length] = s.tpl.apply(values);
13729 * Applies all the passed values to a child template.
13730 * @param {String/Number} name (optional) The name or index of the child template
13731 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13732 * @param {Boolean} reset (optional) True to reset the template first
13733 * @return {MasterTemplate} this
13735 fill : function(name, values, reset){
13737 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13745 for(var i = 0, len = values.length; i < len; i++){
13746 this.add(name, values[i]);
13752 * Resets the template for reuse
13753 * @return {MasterTemplate} this
13755 reset : function(){
13757 for(var i = 0; i < this.subCount; i++){
13763 applyTemplate : function(values){
13765 var replaceIndex = -1;
13766 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13767 return s[++replaceIndex].buffer.join("");
13769 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13772 apply : function(){
13773 return this.applyTemplate.apply(this, arguments);
13776 compile : function(){return this;}
13780 * Alias for fill().
13783 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13785 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13786 * var tpl = Roo.MasterTemplate.from('element-id');
13787 * @param {String/HTMLElement} el
13788 * @param {Object} config
13791 Roo.MasterTemplate.from = function(el, config){
13792 el = Roo.getDom(el);
13793 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13796 * Ext JS Library 1.1.1
13797 * Copyright(c) 2006-2007, Ext JS, LLC.
13799 * Originally Released Under LGPL - original licence link has changed is not relivant.
13802 * <script type="text/javascript">
13807 * @class Roo.util.CSS
13808 * Utility class for manipulating CSS rules
13811 Roo.util.CSS = function(){
13813 var doc = document;
13815 var camelRe = /(-[a-z])/gi;
13816 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13820 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13821 * tag and appended to the HEAD of the document.
13822 * @param {String|Object} cssText The text containing the css rules
13823 * @param {String} id An id to add to the stylesheet for later removal
13824 * @return {StyleSheet}
13826 createStyleSheet : function(cssText, id){
13828 var head = doc.getElementsByTagName("head")[0];
13829 var nrules = doc.createElement("style");
13830 nrules.setAttribute("type", "text/css");
13832 nrules.setAttribute("id", id);
13834 if (typeof(cssText) != 'string') {
13835 // support object maps..
13836 // not sure if this a good idea..
13837 // perhaps it should be merged with the general css handling
13838 // and handle js style props.
13839 var cssTextNew = [];
13840 for(var n in cssText) {
13842 for(var k in cssText[n]) {
13843 citems.push( k + ' : ' +cssText[n][k] + ';' );
13845 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13848 cssText = cssTextNew.join("\n");
13854 head.appendChild(nrules);
13855 ss = nrules.styleSheet;
13856 ss.cssText = cssText;
13859 nrules.appendChild(doc.createTextNode(cssText));
13861 nrules.cssText = cssText;
13863 head.appendChild(nrules);
13864 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13866 this.cacheStyleSheet(ss);
13871 * Removes a style or link tag by id
13872 * @param {String} id The id of the tag
13874 removeStyleSheet : function(id){
13875 var existing = doc.getElementById(id);
13877 existing.parentNode.removeChild(existing);
13882 * Dynamically swaps an existing stylesheet reference for a new one
13883 * @param {String} id The id of an existing link tag to remove
13884 * @param {String} url The href of the new stylesheet to include
13886 swapStyleSheet : function(id, url){
13887 this.removeStyleSheet(id);
13888 var ss = doc.createElement("link");
13889 ss.setAttribute("rel", "stylesheet");
13890 ss.setAttribute("type", "text/css");
13891 ss.setAttribute("id", id);
13892 ss.setAttribute("href", url);
13893 doc.getElementsByTagName("head")[0].appendChild(ss);
13897 * Refresh the rule cache if you have dynamically added stylesheets
13898 * @return {Object} An object (hash) of rules indexed by selector
13900 refreshCache : function(){
13901 return this.getRules(true);
13905 cacheStyleSheet : function(stylesheet){
13909 try{// try catch for cross domain access issue
13910 var ssRules = stylesheet.cssRules || stylesheet.rules;
13911 for(var j = ssRules.length-1; j >= 0; --j){
13912 rules[ssRules[j].selectorText] = ssRules[j];
13918 * Gets all css rules for the document
13919 * @param {Boolean} refreshCache true to refresh the internal cache
13920 * @return {Object} An object (hash) of rules indexed by selector
13922 getRules : function(refreshCache){
13923 if(rules == null || refreshCache){
13925 var ds = doc.styleSheets;
13926 for(var i =0, len = ds.length; i < len; i++){
13928 this.cacheStyleSheet(ds[i]);
13936 * Gets an an individual CSS rule by selector(s)
13937 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13938 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13939 * @return {CSSRule} The CSS rule or null if one is not found
13941 getRule : function(selector, refreshCache){
13942 var rs = this.getRules(refreshCache);
13943 if(!(selector instanceof Array)){
13944 return rs[selector];
13946 for(var i = 0; i < selector.length; i++){
13947 if(rs[selector[i]]){
13948 return rs[selector[i]];
13956 * Updates a rule property
13957 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13958 * @param {String} property The css property
13959 * @param {String} value The new value for the property
13960 * @return {Boolean} true If a rule was found and updated
13962 updateRule : function(selector, property, value){
13963 if(!(selector instanceof Array)){
13964 var rule = this.getRule(selector);
13966 rule.style[property.replace(camelRe, camelFn)] = value;
13970 for(var i = 0; i < selector.length; i++){
13971 if(this.updateRule(selector[i], property, value)){
13981 * Ext JS Library 1.1.1
13982 * Copyright(c) 2006-2007, Ext JS, LLC.
13984 * Originally Released Under LGPL - original licence link has changed is not relivant.
13987 * <script type="text/javascript">
13993 * @class Roo.util.ClickRepeater
13994 * @extends Roo.util.Observable
13996 * A wrapper class which can be applied to any element. Fires a "click" event while the
13997 * mouse is pressed. The interval between firings may be specified in the config but
13998 * defaults to 10 milliseconds.
14000 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14002 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14003 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14004 * Similar to an autorepeat key delay.
14005 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14006 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14007 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14008 * "interval" and "delay" are ignored. "immediate" is honored.
14009 * @cfg {Boolean} preventDefault True to prevent the default click event
14010 * @cfg {Boolean} stopDefault True to stop the default click event
14013 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14014 * 2007-02-02 jvs Renamed to ClickRepeater
14015 * 2007-02-03 jvs Modifications for FF Mac and Safari
14018 * @param {String/HTMLElement/Element} el The element to listen on
14019 * @param {Object} config
14021 Roo.util.ClickRepeater = function(el, config)
14023 this.el = Roo.get(el);
14024 this.el.unselectable();
14026 Roo.apply(this, config);
14031 * Fires when the mouse button is depressed.
14032 * @param {Roo.util.ClickRepeater} this
14034 "mousedown" : true,
14037 * Fires on a specified interval during the time the element is pressed.
14038 * @param {Roo.util.ClickRepeater} this
14043 * Fires when the mouse key is released.
14044 * @param {Roo.util.ClickRepeater} this
14049 this.el.on("mousedown", this.handleMouseDown, this);
14050 if(this.preventDefault || this.stopDefault){
14051 this.el.on("click", function(e){
14052 if(this.preventDefault){
14053 e.preventDefault();
14055 if(this.stopDefault){
14061 // allow inline handler
14063 this.on("click", this.handler, this.scope || this);
14066 Roo.util.ClickRepeater.superclass.constructor.call(this);
14069 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14072 preventDefault : true,
14073 stopDefault : false,
14077 handleMouseDown : function(){
14078 clearTimeout(this.timer);
14080 if(this.pressClass){
14081 this.el.addClass(this.pressClass);
14083 this.mousedownTime = new Date();
14085 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14086 this.el.on("mouseout", this.handleMouseOut, this);
14088 this.fireEvent("mousedown", this);
14089 this.fireEvent("click", this);
14091 this.timer = this.click.defer(this.delay || this.interval, this);
14095 click : function(){
14096 this.fireEvent("click", this);
14097 this.timer = this.click.defer(this.getInterval(), this);
14101 getInterval: function(){
14102 if(!this.accelerate){
14103 return this.interval;
14105 var pressTime = this.mousedownTime.getElapsed();
14106 if(pressTime < 500){
14108 }else if(pressTime < 1700){
14110 }else if(pressTime < 2600){
14112 }else if(pressTime < 3500){
14114 }else if(pressTime < 4400){
14116 }else if(pressTime < 5300){
14118 }else if(pressTime < 6200){
14126 handleMouseOut : function(){
14127 clearTimeout(this.timer);
14128 if(this.pressClass){
14129 this.el.removeClass(this.pressClass);
14131 this.el.on("mouseover", this.handleMouseReturn, this);
14135 handleMouseReturn : function(){
14136 this.el.un("mouseover", this.handleMouseReturn);
14137 if(this.pressClass){
14138 this.el.addClass(this.pressClass);
14144 handleMouseUp : function(){
14145 clearTimeout(this.timer);
14146 this.el.un("mouseover", this.handleMouseReturn);
14147 this.el.un("mouseout", this.handleMouseOut);
14148 Roo.get(document).un("mouseup", this.handleMouseUp);
14149 this.el.removeClass(this.pressClass);
14150 this.fireEvent("mouseup", this);
14154 * Ext JS Library 1.1.1
14155 * Copyright(c) 2006-2007, Ext JS, LLC.
14157 * Originally Released Under LGPL - original licence link has changed is not relivant.
14160 * <script type="text/javascript">
14165 * @class Roo.KeyNav
14166 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14167 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14168 * way to implement custom navigation schemes for any UI component.</p>
14169 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14170 * pageUp, pageDown, del, home, end. Usage:</p>
14172 var nav = new Roo.KeyNav("my-element", {
14173 "left" : function(e){
14174 this.moveLeft(e.ctrlKey);
14176 "right" : function(e){
14177 this.moveRight(e.ctrlKey);
14179 "enter" : function(e){
14186 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14187 * @param {Object} config The config
14189 Roo.KeyNav = function(el, config){
14190 this.el = Roo.get(el);
14191 Roo.apply(this, config);
14192 if(!this.disabled){
14193 this.disabled = true;
14198 Roo.KeyNav.prototype = {
14200 * @cfg {Boolean} disabled
14201 * True to disable this KeyNav instance (defaults to false)
14205 * @cfg {String} defaultEventAction
14206 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14207 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14208 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14210 defaultEventAction: "stopEvent",
14212 * @cfg {Boolean} forceKeyDown
14213 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14214 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14215 * handle keydown instead of keypress.
14217 forceKeyDown : false,
14220 prepareEvent : function(e){
14221 var k = e.getKey();
14222 var h = this.keyToHandler[k];
14223 //if(h && this[h]){
14224 // e.stopPropagation();
14226 if(Roo.isSafari && h && k >= 37 && k <= 40){
14232 relay : function(e){
14233 var k = e.getKey();
14234 var h = this.keyToHandler[k];
14236 if(this.doRelay(e, this[h], h) !== true){
14237 e[this.defaultEventAction]();
14243 doRelay : function(e, h, hname){
14244 return h.call(this.scope || this, e);
14247 // possible handlers
14261 // quick lookup hash
14278 * Enable this KeyNav
14280 enable: function(){
14282 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14283 // the EventObject will normalize Safari automatically
14284 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14285 this.el.on("keydown", this.relay, this);
14287 this.el.on("keydown", this.prepareEvent, this);
14288 this.el.on("keypress", this.relay, this);
14290 this.disabled = false;
14295 * Disable this KeyNav
14297 disable: function(){
14298 if(!this.disabled){
14299 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14300 this.el.un("keydown", this.relay);
14302 this.el.un("keydown", this.prepareEvent);
14303 this.el.un("keypress", this.relay);
14305 this.disabled = true;
14310 * Ext JS Library 1.1.1
14311 * Copyright(c) 2006-2007, Ext JS, LLC.
14313 * Originally Released Under LGPL - original licence link has changed is not relivant.
14316 * <script type="text/javascript">
14321 * @class Roo.KeyMap
14322 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14323 * The constructor accepts the same config object as defined by {@link #addBinding}.
14324 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14325 * combination it will call the function with this signature (if the match is a multi-key
14326 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14327 * A KeyMap can also handle a string representation of keys.<br />
14330 // map one key by key code
14331 var map = new Roo.KeyMap("my-element", {
14332 key: 13, // or Roo.EventObject.ENTER
14337 // map multiple keys to one action by string
14338 var map = new Roo.KeyMap("my-element", {
14344 // map multiple keys to multiple actions by strings and array of codes
14345 var map = new Roo.KeyMap("my-element", [
14348 fn: function(){ alert("Return was pressed"); }
14351 fn: function(){ alert('a, b or c was pressed'); }
14356 fn: function(){ alert('Control + shift + tab was pressed.'); }
14360 * <b>Note: A KeyMap starts enabled</b>
14362 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14363 * @param {Object} config The config (see {@link #addBinding})
14364 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14366 Roo.KeyMap = function(el, config, eventName){
14367 this.el = Roo.get(el);
14368 this.eventName = eventName || "keydown";
14369 this.bindings = [];
14371 this.addBinding(config);
14376 Roo.KeyMap.prototype = {
14378 * True to stop the event from bubbling and prevent the default browser action if the
14379 * key was handled by the KeyMap (defaults to false)
14385 * Add a new binding to this KeyMap. The following config object properties are supported:
14387 Property Type Description
14388 ---------- --------------- ----------------------------------------------------------------------
14389 key String/Array A single keycode or an array of keycodes to handle
14390 shift Boolean True to handle key only when shift is pressed (defaults to false)
14391 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14392 alt Boolean True to handle key only when alt is pressed (defaults to false)
14393 fn Function The function to call when KeyMap finds the expected key combination
14394 scope Object The scope of the callback function
14400 var map = new Roo.KeyMap(document, {
14401 key: Roo.EventObject.ENTER,
14406 //Add a new binding to the existing KeyMap later
14414 * @param {Object/Array} config A single KeyMap config or an array of configs
14416 addBinding : function(config){
14417 if(config instanceof Array){
14418 for(var i = 0, len = config.length; i < len; i++){
14419 this.addBinding(config[i]);
14423 var keyCode = config.key,
14424 shift = config.shift,
14425 ctrl = config.ctrl,
14428 scope = config.scope;
14429 if(typeof keyCode == "string"){
14431 var keyString = keyCode.toUpperCase();
14432 for(var j = 0, len = keyString.length; j < len; j++){
14433 ks.push(keyString.charCodeAt(j));
14437 var keyArray = keyCode instanceof Array;
14438 var handler = function(e){
14439 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14440 var k = e.getKey();
14442 for(var i = 0, len = keyCode.length; i < len; i++){
14443 if(keyCode[i] == k){
14444 if(this.stopEvent){
14447 fn.call(scope || window, k, e);
14453 if(this.stopEvent){
14456 fn.call(scope || window, k, e);
14461 this.bindings.push(handler);
14465 * Shorthand for adding a single key listener
14466 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14467 * following options:
14468 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14469 * @param {Function} fn The function to call
14470 * @param {Object} scope (optional) The scope of the function
14472 on : function(key, fn, scope){
14473 var keyCode, shift, ctrl, alt;
14474 if(typeof key == "object" && !(key instanceof Array)){
14493 handleKeyDown : function(e){
14494 if(this.enabled){ //just in case
14495 var b = this.bindings;
14496 for(var i = 0, len = b.length; i < len; i++){
14497 b[i].call(this, e);
14503 * Returns true if this KeyMap is enabled
14504 * @return {Boolean}
14506 isEnabled : function(){
14507 return this.enabled;
14511 * Enables this KeyMap
14513 enable: function(){
14515 this.el.on(this.eventName, this.handleKeyDown, this);
14516 this.enabled = true;
14521 * Disable this KeyMap
14523 disable: function(){
14525 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14526 this.enabled = false;
14531 * Ext JS Library 1.1.1
14532 * Copyright(c) 2006-2007, Ext JS, LLC.
14534 * Originally Released Under LGPL - original licence link has changed is not relivant.
14537 * <script type="text/javascript">
14542 * @class Roo.util.TextMetrics
14543 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14544 * wide, in pixels, a given block of text will be.
14547 Roo.util.TextMetrics = function(){
14551 * Measures the size of the specified text
14552 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14553 * that can affect the size of the rendered text
14554 * @param {String} text The text to measure
14555 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14556 * in order to accurately measure the text height
14557 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14559 measure : function(el, text, fixedWidth){
14561 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14564 shared.setFixedWidth(fixedWidth || 'auto');
14565 return shared.getSize(text);
14569 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14570 * the overhead of multiple calls to initialize the style properties on each measurement.
14571 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14572 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14573 * in order to accurately measure the text height
14574 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14576 createInstance : function(el, fixedWidth){
14577 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14584 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14585 var ml = new Roo.Element(document.createElement('div'));
14586 document.body.appendChild(ml.dom);
14587 ml.position('absolute');
14588 ml.setLeftTop(-1000, -1000);
14592 ml.setWidth(fixedWidth);
14597 * Returns the size of the specified text based on the internal element's style and width properties
14598 * @memberOf Roo.util.TextMetrics.Instance#
14599 * @param {String} text The text to measure
14600 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14602 getSize : function(text){
14604 var s = ml.getSize();
14610 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14611 * that can affect the size of the rendered text
14612 * @memberOf Roo.util.TextMetrics.Instance#
14613 * @param {String/HTMLElement} el The element, dom node or id
14615 bind : function(el){
14617 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14622 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14623 * to set a fixed width in order to accurately measure the text height.
14624 * @memberOf Roo.util.TextMetrics.Instance#
14625 * @param {Number} width The width to set on the element
14627 setFixedWidth : function(width){
14628 ml.setWidth(width);
14632 * Returns the measured width of the specified text
14633 * @memberOf Roo.util.TextMetrics.Instance#
14634 * @param {String} text The text to measure
14635 * @return {Number} width The width in pixels
14637 getWidth : function(text){
14638 ml.dom.style.width = 'auto';
14639 return this.getSize(text).width;
14643 * Returns the measured height of the specified text. For multiline text, be sure to call
14644 * {@link #setFixedWidth} if necessary.
14645 * @memberOf Roo.util.TextMetrics.Instance#
14646 * @param {String} text The text to measure
14647 * @return {Number} height The height in pixels
14649 getHeight : function(text){
14650 return this.getSize(text).height;
14654 instance.bind(bindTo);
14659 // backwards compat
14660 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14662 * Ext JS Library 1.1.1
14663 * Copyright(c) 2006-2007, Ext JS, LLC.
14665 * Originally Released Under LGPL - original licence link has changed is not relivant.
14668 * <script type="text/javascript">
14672 * @class Roo.state.Provider
14673 * Abstract base class for state provider implementations. This class provides methods
14674 * for encoding and decoding <b>typed</b> variables including dates and defines the
14675 * Provider interface.
14677 Roo.state.Provider = function(){
14679 * @event statechange
14680 * Fires when a state change occurs.
14681 * @param {Provider} this This state provider
14682 * @param {String} key The state key which was changed
14683 * @param {String} value The encoded value for the state
14686 "statechange": true
14689 Roo.state.Provider.superclass.constructor.call(this);
14691 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14693 * Returns the current value for a key
14694 * @param {String} name The key name
14695 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14696 * @return {Mixed} The state data
14698 get : function(name, defaultValue){
14699 return typeof this.state[name] == "undefined" ?
14700 defaultValue : this.state[name];
14704 * Clears a value from the state
14705 * @param {String} name The key name
14707 clear : function(name){
14708 delete this.state[name];
14709 this.fireEvent("statechange", this, name, null);
14713 * Sets the value for a key
14714 * @param {String} name The key name
14715 * @param {Mixed} value The value to set
14717 set : function(name, value){
14718 this.state[name] = value;
14719 this.fireEvent("statechange", this, name, value);
14723 * Decodes a string previously encoded with {@link #encodeValue}.
14724 * @param {String} value The value to decode
14725 * @return {Mixed} The decoded value
14727 decodeValue : function(cookie){
14728 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14729 var matches = re.exec(unescape(cookie));
14730 if(!matches || !matches[1]) return; // non state cookie
14731 var type = matches[1];
14732 var v = matches[2];
14735 return parseFloat(v);
14737 return new Date(Date.parse(v));
14742 var values = v.split("^");
14743 for(var i = 0, len = values.length; i < len; i++){
14744 all.push(this.decodeValue(values[i]));
14749 var values = v.split("^");
14750 for(var i = 0, len = values.length; i < len; i++){
14751 var kv = values[i].split("=");
14752 all[kv[0]] = this.decodeValue(kv[1]);
14761 * Encodes a value including type information. Decode with {@link #decodeValue}.
14762 * @param {Mixed} value The value to encode
14763 * @return {String} The encoded value
14765 encodeValue : function(v){
14767 if(typeof v == "number"){
14769 }else if(typeof v == "boolean"){
14770 enc = "b:" + (v ? "1" : "0");
14771 }else if(v instanceof Date){
14772 enc = "d:" + v.toGMTString();
14773 }else if(v instanceof Array){
14775 for(var i = 0, len = v.length; i < len; i++){
14776 flat += this.encodeValue(v[i]);
14777 if(i != len-1) flat += "^";
14780 }else if(typeof v == "object"){
14783 if(typeof v[key] != "function"){
14784 flat += key + "=" + this.encodeValue(v[key]) + "^";
14787 enc = "o:" + flat.substring(0, flat.length-1);
14791 return escape(enc);
14797 * Ext JS Library 1.1.1
14798 * Copyright(c) 2006-2007, Ext JS, LLC.
14800 * Originally Released Under LGPL - original licence link has changed is not relivant.
14803 * <script type="text/javascript">
14806 * @class Roo.state.Manager
14807 * This is the global state manager. By default all components that are "state aware" check this class
14808 * for state information if you don't pass them a custom state provider. In order for this class
14809 * to be useful, it must be initialized with a provider when your application initializes.
14811 // in your initialization function
14813 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14815 // supposed you have a {@link Roo.BorderLayout}
14816 var layout = new Roo.BorderLayout(...);
14817 layout.restoreState();
14818 // or a {Roo.BasicDialog}
14819 var dialog = new Roo.BasicDialog(...);
14820 dialog.restoreState();
14824 Roo.state.Manager = function(){
14825 var provider = new Roo.state.Provider();
14829 * Configures the default state provider for your application
14830 * @param {Provider} stateProvider The state provider to set
14832 setProvider : function(stateProvider){
14833 provider = stateProvider;
14837 * Returns the current value for a key
14838 * @param {String} name The key name
14839 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14840 * @return {Mixed} The state data
14842 get : function(key, defaultValue){
14843 return provider.get(key, defaultValue);
14847 * Sets the value for a key
14848 * @param {String} name The key name
14849 * @param {Mixed} value The state data
14851 set : function(key, value){
14852 provider.set(key, value);
14856 * Clears a value from the state
14857 * @param {String} name The key name
14859 clear : function(key){
14860 provider.clear(key);
14864 * Gets the currently configured state provider
14865 * @return {Provider} The state provider
14867 getProvider : function(){
14874 * Ext JS Library 1.1.1
14875 * Copyright(c) 2006-2007, Ext JS, LLC.
14877 * Originally Released Under LGPL - original licence link has changed is not relivant.
14880 * <script type="text/javascript">
14883 * @class Roo.state.CookieProvider
14884 * @extends Roo.state.Provider
14885 * The default Provider implementation which saves state via cookies.
14888 var cp = new Roo.state.CookieProvider({
14890 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14891 domain: "roojs.com"
14893 Roo.state.Manager.setProvider(cp);
14895 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14896 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14897 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14898 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14899 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14900 * domain the page is running on including the 'www' like 'www.roojs.com')
14901 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14903 * Create a new CookieProvider
14904 * @param {Object} config The configuration object
14906 Roo.state.CookieProvider = function(config){
14907 Roo.state.CookieProvider.superclass.constructor.call(this);
14909 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14910 this.domain = null;
14911 this.secure = false;
14912 Roo.apply(this, config);
14913 this.state = this.readCookies();
14916 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14918 set : function(name, value){
14919 if(typeof value == "undefined" || value === null){
14923 this.setCookie(name, value);
14924 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14928 clear : function(name){
14929 this.clearCookie(name);
14930 Roo.state.CookieProvider.superclass.clear.call(this, name);
14934 readCookies : function(){
14936 var c = document.cookie + ";";
14937 var re = /\s?(.*?)=(.*?);/g;
14939 while((matches = re.exec(c)) != null){
14940 var name = matches[1];
14941 var value = matches[2];
14942 if(name && name.substring(0,3) == "ys-"){
14943 cookies[name.substr(3)] = this.decodeValue(value);
14950 setCookie : function(name, value){
14951 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14952 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14953 ((this.path == null) ? "" : ("; path=" + this.path)) +
14954 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14955 ((this.secure == true) ? "; secure" : "");
14959 clearCookie : function(name){
14960 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14961 ((this.path == null) ? "" : ("; path=" + this.path)) +
14962 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14963 ((this.secure == true) ? "; secure" : "");
14967 * Ext JS Library 1.1.1
14968 * Copyright(c) 2006-2007, Ext JS, LLC.
14970 * Originally Released Under LGPL - original licence link has changed is not relivant.
14973 * <script type="text/javascript">
14978 * @class Roo.ComponentMgr
14979 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14982 Roo.ComponentMgr = function(){
14983 var all = new Roo.util.MixedCollection();
14987 * Registers a component.
14988 * @param {Roo.Component} c The component
14990 register : function(c){
14995 * Unregisters a component.
14996 * @param {Roo.Component} c The component
14998 unregister : function(c){
15003 * Returns a component by id
15004 * @param {String} id The component id
15006 get : function(id){
15007 return all.get(id);
15011 * Registers a function that will be called when a specified component is added to ComponentMgr
15012 * @param {String} id The component id
15013 * @param {Funtction} fn The callback function
15014 * @param {Object} scope The scope of the callback
15016 onAvailable : function(id, fn, scope){
15017 all.on("add", function(index, o){
15019 fn.call(scope || o, o);
15020 all.un("add", fn, scope);
15027 * Ext JS Library 1.1.1
15028 * Copyright(c) 2006-2007, Ext JS, LLC.
15030 * Originally Released Under LGPL - original licence link has changed is not relivant.
15033 * <script type="text/javascript">
15037 * @class Roo.Component
15038 * @extends Roo.util.Observable
15039 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15040 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15041 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15042 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15043 * All visual components (widgets) that require rendering into a layout should subclass Component.
15045 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15046 * 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
15047 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15049 Roo.Component = function(config){
15050 config = config || {};
15051 if(config.tagName || config.dom || typeof config == "string"){ // element object
15052 config = {el: config, id: config.id || config};
15054 this.initialConfig = config;
15056 Roo.apply(this, config);
15060 * Fires after the component is disabled.
15061 * @param {Roo.Component} this
15066 * Fires after the component is enabled.
15067 * @param {Roo.Component} this
15071 * @event beforeshow
15072 * Fires before the component is shown. Return false to stop the show.
15073 * @param {Roo.Component} this
15078 * Fires after the component is shown.
15079 * @param {Roo.Component} this
15083 * @event beforehide
15084 * Fires before the component is hidden. Return false to stop the hide.
15085 * @param {Roo.Component} this
15090 * Fires after the component is hidden.
15091 * @param {Roo.Component} this
15095 * @event beforerender
15096 * Fires before the component is rendered. Return false to stop the render.
15097 * @param {Roo.Component} this
15099 beforerender : true,
15102 * Fires after the component is rendered.
15103 * @param {Roo.Component} this
15107 * @event beforedestroy
15108 * Fires before the component is destroyed. Return false to stop the destroy.
15109 * @param {Roo.Component} this
15111 beforedestroy : true,
15114 * Fires after the component is destroyed.
15115 * @param {Roo.Component} this
15120 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15122 Roo.ComponentMgr.register(this);
15123 Roo.Component.superclass.constructor.call(this);
15124 this.initComponent();
15125 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15126 this.render(this.renderTo);
15127 delete this.renderTo;
15132 Roo.Component.AUTO_ID = 1000;
15134 Roo.extend(Roo.Component, Roo.util.Observable, {
15136 * @scope Roo.Component.prototype
15138 * true if this component is hidden. Read-only.
15143 * true if this component is disabled. Read-only.
15148 * true if this component has been rendered. Read-only.
15152 /** @cfg {String} disableClass
15153 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15155 disabledClass : "x-item-disabled",
15156 /** @cfg {Boolean} allowDomMove
15157 * Whether the component can move the Dom node when rendering (defaults to true).
15159 allowDomMove : true,
15160 /** @cfg {String} hideMode
15161 * How this component should hidden. Supported values are
15162 * "visibility" (css visibility), "offsets" (negative offset position) and
15163 * "display" (css display) - defaults to "display".
15165 hideMode: 'display',
15168 ctype : "Roo.Component",
15171 * @cfg {String} actionMode
15172 * which property holds the element that used for hide() / show() / disable() / enable()
15178 getActionEl : function(){
15179 return this[this.actionMode];
15182 initComponent : Roo.emptyFn,
15184 * If this is a lazy rendering component, render it to its container element.
15185 * @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.
15187 render : function(container, position){
15188 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15189 if(!container && this.el){
15190 this.el = Roo.get(this.el);
15191 container = this.el.dom.parentNode;
15192 this.allowDomMove = false;
15194 this.container = Roo.get(container);
15195 this.rendered = true;
15196 if(position !== undefined){
15197 if(typeof position == 'number'){
15198 position = this.container.dom.childNodes[position];
15200 position = Roo.getDom(position);
15203 this.onRender(this.container, position || null);
15205 this.el.addClass(this.cls);
15209 this.el.applyStyles(this.style);
15212 this.fireEvent("render", this);
15213 this.afterRender(this.container);
15225 // default function is not really useful
15226 onRender : function(ct, position){
15228 this.el = Roo.get(this.el);
15229 if(this.allowDomMove !== false){
15230 ct.dom.insertBefore(this.el.dom, position);
15236 getAutoCreate : function(){
15237 var cfg = typeof this.autoCreate == "object" ?
15238 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15239 if(this.id && !cfg.id){
15246 afterRender : Roo.emptyFn,
15249 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15250 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15252 destroy : function(){
15253 if(this.fireEvent("beforedestroy", this) !== false){
15254 this.purgeListeners();
15255 this.beforeDestroy();
15257 this.el.removeAllListeners();
15259 if(this.actionMode == "container"){
15260 this.container.remove();
15264 Roo.ComponentMgr.unregister(this);
15265 this.fireEvent("destroy", this);
15270 beforeDestroy : function(){
15275 onDestroy : function(){
15280 * Returns the underlying {@link Roo.Element}.
15281 * @return {Roo.Element} The element
15283 getEl : function(){
15288 * Returns the id of this component.
15291 getId : function(){
15296 * Try to focus this component.
15297 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15298 * @return {Roo.Component} this
15300 focus : function(selectText){
15303 if(selectText === true){
15304 this.el.dom.select();
15319 * Disable this component.
15320 * @return {Roo.Component} this
15322 disable : function(){
15326 this.disabled = true;
15327 this.fireEvent("disable", this);
15332 onDisable : function(){
15333 this.getActionEl().addClass(this.disabledClass);
15334 this.el.dom.disabled = true;
15338 * Enable this component.
15339 * @return {Roo.Component} this
15341 enable : function(){
15345 this.disabled = false;
15346 this.fireEvent("enable", this);
15351 onEnable : function(){
15352 this.getActionEl().removeClass(this.disabledClass);
15353 this.el.dom.disabled = false;
15357 * Convenience function for setting disabled/enabled by boolean.
15358 * @param {Boolean} disabled
15360 setDisabled : function(disabled){
15361 this[disabled ? "disable" : "enable"]();
15365 * Show this component.
15366 * @return {Roo.Component} this
15369 if(this.fireEvent("beforeshow", this) !== false){
15370 this.hidden = false;
15374 this.fireEvent("show", this);
15380 onShow : function(){
15381 var ae = this.getActionEl();
15382 if(this.hideMode == 'visibility'){
15383 ae.dom.style.visibility = "visible";
15384 }else if(this.hideMode == 'offsets'){
15385 ae.removeClass('x-hidden');
15387 ae.dom.style.display = "";
15392 * Hide this component.
15393 * @return {Roo.Component} this
15396 if(this.fireEvent("beforehide", this) !== false){
15397 this.hidden = true;
15401 this.fireEvent("hide", this);
15407 onHide : function(){
15408 var ae = this.getActionEl();
15409 if(this.hideMode == 'visibility'){
15410 ae.dom.style.visibility = "hidden";
15411 }else if(this.hideMode == 'offsets'){
15412 ae.addClass('x-hidden');
15414 ae.dom.style.display = "none";
15419 * Convenience function to hide or show this component by boolean.
15420 * @param {Boolean} visible True to show, false to hide
15421 * @return {Roo.Component} this
15423 setVisible: function(visible){
15433 * Returns true if this component is visible.
15435 isVisible : function(){
15436 return this.getActionEl().isVisible();
15439 cloneConfig : function(overrides){
15440 overrides = overrides || {};
15441 var id = overrides.id || Roo.id();
15442 var cfg = Roo.applyIf(overrides, this.initialConfig);
15443 cfg.id = id; // prevent dup id
15444 return new this.constructor(cfg);
15448 * Ext JS Library 1.1.1
15449 * Copyright(c) 2006-2007, Ext JS, LLC.
15451 * Originally Released Under LGPL - original licence link has changed is not relivant.
15454 * <script type="text/javascript">
15458 * @class Roo.BoxComponent
15459 * @extends Roo.Component
15460 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15461 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15462 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15463 * layout containers.
15465 * @param {Roo.Element/String/Object} config The configuration options.
15467 Roo.BoxComponent = function(config){
15468 Roo.Component.call(this, config);
15472 * Fires after the component is resized.
15473 * @param {Roo.Component} this
15474 * @param {Number} adjWidth The box-adjusted width that was set
15475 * @param {Number} adjHeight The box-adjusted height that was set
15476 * @param {Number} rawWidth The width that was originally specified
15477 * @param {Number} rawHeight The height that was originally specified
15482 * Fires after the component is moved.
15483 * @param {Roo.Component} this
15484 * @param {Number} x The new x position
15485 * @param {Number} y The new y position
15491 Roo.extend(Roo.BoxComponent, Roo.Component, {
15492 // private, set in afterRender to signify that the component has been rendered
15494 // private, used to defer height settings to subclasses
15495 deferHeight: false,
15496 /** @cfg {Number} width
15497 * width (optional) size of component
15499 /** @cfg {Number} height
15500 * height (optional) size of component
15504 * Sets the width and height of the component. This method fires the resize event. This method can accept
15505 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15506 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15507 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15508 * @return {Roo.BoxComponent} this
15510 setSize : function(w, h){
15511 // support for standard size objects
15512 if(typeof w == 'object'){
15517 if(!this.boxReady){
15523 // prevent recalcs when not needed
15524 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15527 this.lastSize = {width: w, height: h};
15529 var adj = this.adjustSize(w, h);
15530 var aw = adj.width, ah = adj.height;
15531 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15532 var rz = this.getResizeEl();
15533 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15534 rz.setSize(aw, ah);
15535 }else if(!this.deferHeight && ah !== undefined){
15537 }else if(aw !== undefined){
15540 this.onResize(aw, ah, w, h);
15541 this.fireEvent('resize', this, aw, ah, w, h);
15547 * Gets the current size of the component's underlying element.
15548 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15550 getSize : function(){
15551 return this.el.getSize();
15555 * Gets the current XY position of the component's underlying element.
15556 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15557 * @return {Array} The XY position of the element (e.g., [100, 200])
15559 getPosition : function(local){
15560 if(local === true){
15561 return [this.el.getLeft(true), this.el.getTop(true)];
15563 return this.xy || this.el.getXY();
15567 * Gets the current box measurements of the component's underlying element.
15568 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15569 * @returns {Object} box An object in the format {x, y, width, height}
15571 getBox : function(local){
15572 var s = this.el.getSize();
15574 s.x = this.el.getLeft(true);
15575 s.y = this.el.getTop(true);
15577 var xy = this.xy || this.el.getXY();
15585 * Sets the current box measurements of the component's underlying element.
15586 * @param {Object} box An object in the format {x, y, width, height}
15587 * @returns {Roo.BoxComponent} this
15589 updateBox : function(box){
15590 this.setSize(box.width, box.height);
15591 this.setPagePosition(box.x, box.y);
15596 getResizeEl : function(){
15597 return this.resizeEl || this.el;
15601 getPositionEl : function(){
15602 return this.positionEl || this.el;
15606 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15607 * This method fires the move event.
15608 * @param {Number} left The new left
15609 * @param {Number} top The new top
15610 * @returns {Roo.BoxComponent} this
15612 setPosition : function(x, y){
15615 if(!this.boxReady){
15618 var adj = this.adjustPosition(x, y);
15619 var ax = adj.x, ay = adj.y;
15621 var el = this.getPositionEl();
15622 if(ax !== undefined || ay !== undefined){
15623 if(ax !== undefined && ay !== undefined){
15624 el.setLeftTop(ax, ay);
15625 }else if(ax !== undefined){
15627 }else if(ay !== undefined){
15630 this.onPosition(ax, ay);
15631 this.fireEvent('move', this, ax, ay);
15637 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15638 * This method fires the move event.
15639 * @param {Number} x The new x position
15640 * @param {Number} y The new y position
15641 * @returns {Roo.BoxComponent} this
15643 setPagePosition : function(x, y){
15646 if(!this.boxReady){
15649 if(x === undefined || y === undefined){ // cannot translate undefined points
15652 var p = this.el.translatePoints(x, y);
15653 this.setPosition(p.left, p.top);
15658 onRender : function(ct, position){
15659 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15661 this.resizeEl = Roo.get(this.resizeEl);
15663 if(this.positionEl){
15664 this.positionEl = Roo.get(this.positionEl);
15669 afterRender : function(){
15670 Roo.BoxComponent.superclass.afterRender.call(this);
15671 this.boxReady = true;
15672 this.setSize(this.width, this.height);
15673 if(this.x || this.y){
15674 this.setPosition(this.x, this.y);
15676 if(this.pageX || this.pageY){
15677 this.setPagePosition(this.pageX, this.pageY);
15682 * Force the component's size to recalculate based on the underlying element's current height and width.
15683 * @returns {Roo.BoxComponent} this
15685 syncSize : function(){
15686 delete this.lastSize;
15687 this.setSize(this.el.getWidth(), this.el.getHeight());
15692 * Called after the component is resized, this method is empty by default but can be implemented by any
15693 * subclass that needs to perform custom logic after a resize occurs.
15694 * @param {Number} adjWidth The box-adjusted width that was set
15695 * @param {Number} adjHeight The box-adjusted height that was set
15696 * @param {Number} rawWidth The width that was originally specified
15697 * @param {Number} rawHeight The height that was originally specified
15699 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15704 * Called after the component is moved, this method is empty by default but can be implemented by any
15705 * subclass that needs to perform custom logic after a move occurs.
15706 * @param {Number} x The new x position
15707 * @param {Number} y The new y position
15709 onPosition : function(x, y){
15714 adjustSize : function(w, h){
15715 if(this.autoWidth){
15718 if(this.autoHeight){
15721 return {width : w, height: h};
15725 adjustPosition : function(x, y){
15726 return {x : x, y: y};
15729 * Original code for Roojs - LGPL
15730 * <script type="text/javascript">
15734 * @class Roo.XComponent
15735 * A delayed Element creator...
15736 * Or a way to group chunks of interface together.
15738 * Mypart.xyx = new Roo.XComponent({
15740 parent : 'Mypart.xyz', // empty == document.element.!!
15744 disabled : function() {}
15746 tree : function() { // return an tree of xtype declared components
15750 xtype : 'NestedLayoutPanel',
15757 * It can be used to build a big heiracy, with parent etc.
15758 * or you can just use this to render a single compoent to a dom element
15759 * MYPART.render(Roo.Element | String(id) | dom_element )
15761 * @extends Roo.util.Observable
15763 * @param cfg {Object} configuration of component
15766 Roo.XComponent = function(cfg) {
15767 Roo.apply(this, cfg);
15771 * Fires when this the componnt is built
15772 * @param {Roo.XComponent} c the component
15777 this.region = this.region || 'center'; // default..
15778 Roo.XComponent.register(this);
15779 this.modules = false;
15780 this.el = false; // where the layout goes..
15784 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15787 * The created element (with Roo.factory())
15788 * @type {Roo.Layout}
15794 * for BC - use el in new code
15795 * @type {Roo.Layout}
15801 * for BC - use el in new code
15802 * @type {Roo.Layout}
15807 * @cfg {Function|boolean} disabled
15808 * If this module is disabled by some rule, return true from the funtion
15813 * @cfg {String} parent
15814 * Name of parent element which it get xtype added to..
15819 * @cfg {String} order
15820 * Used to set the order in which elements are created (usefull for multiple tabs)
15825 * @cfg {String} name
15826 * String to display while loading.
15830 * @cfg {String} region
15831 * Region to render component to (defaults to center)
15836 * @cfg {Array} items
15837 * A single item array - the first element is the root of the tree..
15838 * It's done this way to stay compatible with the Xtype system...
15844 * The method that retuns the tree of parts that make up this compoennt
15851 * render element to dom or tree
15852 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15855 render : function(el)
15859 var hp = this.parent ? 1 : 0;
15861 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15862 // if parent is a '#.....' string, then let's use that..
15863 var ename = this.parent.substr(1)
15864 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15865 el = Roo.get(ename);
15866 if (!el && !this.parent) {
15867 Roo.log("Warning - element can not be found :#" + ename );
15871 var tree = this._tree ? this._tree() : this.tree();
15874 if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15875 //el = Roo.get(document.body);
15876 this.parent = { el : true };
15881 if (!this.parent) {
15883 Roo.log("no parent - creating one");
15885 el = el ? Roo.get(el) : false;
15887 // it's a top level one..
15889 el : new Roo.BorderLayout(el || document.body, {
15895 tabPosition: 'top',
15896 //resizeTabs: true,
15897 alwaysShowTabs: el && hp? false : true,
15898 hideTabs: el || !hp ? true : false,
15905 if (!this.parent.el) {
15906 // probably an old style ctor, which has been disabled.
15910 // The 'tree' method is '_tree now'
15912 tree.region = tree.region || this.region;
15914 if (this.parent.el === true) {
15915 // bootstrap... - body..
15916 this.parent.el = Roo.factory(tree);
15919 this.el = this.parent.el.addxtype(tree);
15920 this.fireEvent('built', this);
15922 this.panel = this.el;
15923 this.layout = this.panel.layout;
15924 this.parentLayout = this.parent.layout || false;
15930 Roo.apply(Roo.XComponent, {
15932 * @property hideProgress
15933 * true to disable the building progress bar.. usefull on single page renders.
15936 hideProgress : false,
15938 * @property buildCompleted
15939 * True when the builder has completed building the interface.
15942 buildCompleted : false,
15945 * @property topModule
15946 * the upper most module - uses document.element as it's constructor.
15953 * @property modules
15954 * array of modules to be created by registration system.
15955 * @type {Array} of Roo.XComponent
15960 * @property elmodules
15961 * array of modules to be created by which use #ID
15962 * @type {Array} of Roo.XComponent
15968 * @property build_from_html
15969 * Build elements from html - used by bootstrap HTML stuff
15970 * - this is cleared after build is completed
15971 * @type {boolean} true (default false)
15974 build_from_html : false,
15977 * Register components to be built later.
15979 * This solves the following issues
15980 * - Building is not done on page load, but after an authentication process has occured.
15981 * - Interface elements are registered on page load
15982 * - Parent Interface elements may not be loaded before child, so this handles that..
15989 module : 'Pman.Tab.projectMgr',
15991 parent : 'Pman.layout',
15992 disabled : false, // or use a function..
15995 * * @param {Object} details about module
15997 register : function(obj) {
15999 Roo.XComponent.event.fireEvent('register', obj);
16000 switch(typeof(obj.disabled) ) {
16006 if ( obj.disabled() ) {
16012 if (obj.disabled) {
16018 this.modules.push(obj);
16022 * convert a string to an object..
16023 * eg. 'AAA.BBB' -> finds AAA.BBB
16027 toObject : function(str)
16029 if (!str || typeof(str) == 'object') {
16032 if (str.substring(0,1) == '#') {
16036 var ar = str.split('.');
16041 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16043 throw "Module not found : " + str;
16047 throw "Module not found : " + str;
16049 Roo.each(ar, function(e) {
16050 if (typeof(o[e]) == 'undefined') {
16051 throw "Module not found : " + str;
16062 * move modules into their correct place in the tree..
16065 preBuild : function ()
16068 Roo.each(this.modules , function (obj)
16070 Roo.XComponent.event.fireEvent('beforebuild', obj);
16072 var opar = obj.parent;
16074 obj.parent = this.toObject(opar);
16076 Roo.log("parent:toObject failed: " + e.toString());
16081 Roo.debug && Roo.log("GOT top level module");
16082 Roo.debug && Roo.log(obj);
16083 obj.modules = new Roo.util.MixedCollection(false,
16084 function(o) { return o.order + '' }
16086 this.topModule = obj;
16089 // parent is a string (usually a dom element name..)
16090 if (typeof(obj.parent) == 'string') {
16091 this.elmodules.push(obj);
16094 if (obj.parent.constructor != Roo.XComponent) {
16095 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16097 if (!obj.parent.modules) {
16098 obj.parent.modules = new Roo.util.MixedCollection(false,
16099 function(o) { return o.order + '' }
16102 if (obj.parent.disabled) {
16103 obj.disabled = true;
16105 obj.parent.modules.add(obj);
16110 * make a list of modules to build.
16111 * @return {Array} list of modules.
16114 buildOrder : function()
16117 var cmp = function(a,b) {
16118 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16120 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16121 throw "No top level modules to build";
16124 // make a flat list in order of modules to build.
16125 var mods = this.topModule ? [ this.topModule ] : [];
16128 // elmodules (is a list of DOM based modules )
16129 Roo.each(this.elmodules, function(e) {
16131 if (!this.topModule &&
16132 typeof(e.parent) == 'string' &&
16133 e.parent.substring(0,1) == '#' &&
16134 Roo.get(e.parent.substr(1))
16137 _this.topModule = e;
16143 // add modules to their parents..
16144 var addMod = function(m) {
16145 Roo.debug && Roo.log("build Order: add: " + m.name);
16148 if (m.modules && !m.disabled) {
16149 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16150 m.modules.keySort('ASC', cmp );
16151 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16153 m.modules.each(addMod);
16155 Roo.debug && Roo.log("build Order: no child modules");
16157 // not sure if this is used any more..
16159 m.finalize.name = m.name + " (clean up) ";
16160 mods.push(m.finalize);
16164 if (this.topModule && this.topModule.modules) {
16165 this.topModule.modules.keySort('ASC', cmp );
16166 this.topModule.modules.each(addMod);
16172 * Build the registered modules.
16173 * @param {Object} parent element.
16174 * @param {Function} optional method to call after module has been added.
16178 build : function(opts)
16181 if (typeof(opts) != 'undefined') {
16182 Roo.apply(this,opts);
16186 var mods = this.buildOrder();
16188 //this.allmods = mods;
16189 //Roo.debug && Roo.log(mods);
16191 if (!mods.length) { // should not happen
16192 throw "NO modules!!!";
16196 var msg = "Building Interface...";
16197 // flash it up as modal - so we store the mask!?
16198 if (!this.hideProgress && Roo.MessageBox) {
16199 Roo.MessageBox.show({ title: 'loading' });
16200 Roo.MessageBox.show({
16201 title: "Please wait...",
16210 var total = mods.length;
16213 var progressRun = function() {
16214 if (!mods.length) {
16215 Roo.debug && Roo.log('hide?');
16216 if (!this.hideProgress && Roo.MessageBox) {
16217 Roo.MessageBox.hide();
16219 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16221 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16227 var m = mods.shift();
16230 Roo.debug && Roo.log(m);
16231 // not sure if this is supported any more.. - modules that are are just function
16232 if (typeof(m) == 'function') {
16234 return progressRun.defer(10, _this);
16238 msg = "Building Interface " + (total - mods.length) +
16240 (m.name ? (' - ' + m.name) : '');
16241 Roo.debug && Roo.log(msg);
16242 if (!this.hideProgress && Roo.MessageBox) {
16243 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16247 // is the module disabled?
16248 var disabled = (typeof(m.disabled) == 'function') ?
16249 m.disabled.call(m.module.disabled) : m.disabled;
16253 return progressRun(); // we do not update the display!
16261 // it's 10 on top level, and 1 on others??? why...
16262 return progressRun.defer(10, _this);
16265 progressRun.defer(1, _this);
16279 * wrapper for event.on - aliased later..
16280 * Typically use to register a event handler for register:
16282 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16291 Roo.XComponent.event = new Roo.util.Observable({
16295 * Fires when an Component is registered,
16296 * set the disable property on the Component to stop registration.
16297 * @param {Roo.XComponent} c the component being registerd.
16302 * @event beforebuild
16303 * Fires before each Component is built
16304 * can be used to apply permissions.
16305 * @param {Roo.XComponent} c the component being registerd.
16308 'beforebuild' : true,
16310 * @event buildcomplete
16311 * Fires on the top level element when all elements have been built
16312 * @param {Roo.XComponent} the top level component.
16314 'buildcomplete' : true
16319 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16322 * Ext JS Library 1.1.1
16323 * Copyright(c) 2006-2007, Ext JS, LLC.
16325 * Originally Released Under LGPL - original licence link has changed is not relivant.
16328 * <script type="text/javascript">
16334 * These classes are derivatives of the similarly named classes in the YUI Library.
16335 * The original license:
16336 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16337 * Code licensed under the BSD License:
16338 * http://developer.yahoo.net/yui/license.txt
16343 var Event=Roo.EventManager;
16344 var Dom=Roo.lib.Dom;
16347 * @class Roo.dd.DragDrop
16348 * @extends Roo.util.Observable
16349 * Defines the interface and base operation of items that that can be
16350 * dragged or can be drop targets. It was designed to be extended, overriding
16351 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16352 * Up to three html elements can be associated with a DragDrop instance:
16354 * <li>linked element: the element that is passed into the constructor.
16355 * This is the element which defines the boundaries for interaction with
16356 * other DragDrop objects.</li>
16357 * <li>handle element(s): The drag operation only occurs if the element that
16358 * was clicked matches a handle element. By default this is the linked
16359 * element, but there are times that you will want only a portion of the
16360 * linked element to initiate the drag operation, and the setHandleElId()
16361 * method provides a way to define this.</li>
16362 * <li>drag element: this represents the element that would be moved along
16363 * with the cursor during a drag operation. By default, this is the linked
16364 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16365 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16368 * This class should not be instantiated until the onload event to ensure that
16369 * the associated elements are available.
16370 * The following would define a DragDrop obj that would interact with any
16371 * other DragDrop obj in the "group1" group:
16373 * dd = new Roo.dd.DragDrop("div1", "group1");
16375 * Since none of the event handlers have been implemented, nothing would
16376 * actually happen if you were to run the code above. Normally you would
16377 * override this class or one of the default implementations, but you can
16378 * also override the methods you want on an instance of the class...
16380 * dd.onDragDrop = function(e, id) {
16381 * alert("dd was dropped on " + id);
16385 * @param {String} id of the element that is linked to this instance
16386 * @param {String} sGroup the group of related DragDrop objects
16387 * @param {object} config an object containing configurable attributes
16388 * Valid properties for DragDrop:
16389 * padding, isTarget, maintainOffset, primaryButtonOnly
16391 Roo.dd.DragDrop = function(id, sGroup, config) {
16393 this.init(id, sGroup, config);
16398 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16401 * The id of the element associated with this object. This is what we
16402 * refer to as the "linked element" because the size and position of
16403 * this element is used to determine when the drag and drop objects have
16411 * Configuration attributes passed into the constructor
16418 * The id of the element that will be dragged. By default this is same
16419 * as the linked element , but could be changed to another element. Ex:
16421 * @property dragElId
16428 * the id of the element that initiates the drag operation. By default
16429 * this is the linked element, but could be changed to be a child of this
16430 * element. This lets us do things like only starting the drag when the
16431 * header element within the linked html element is clicked.
16432 * @property handleElId
16439 * An associative array of HTML tags that will be ignored if clicked.
16440 * @property invalidHandleTypes
16441 * @type {string: string}
16443 invalidHandleTypes: null,
16446 * An associative array of ids for elements that will be ignored if clicked
16447 * @property invalidHandleIds
16448 * @type {string: string}
16450 invalidHandleIds: null,
16453 * An indexted array of css class names for elements that will be ignored
16455 * @property invalidHandleClasses
16458 invalidHandleClasses: null,
16461 * The linked element's absolute X position at the time the drag was
16463 * @property startPageX
16470 * The linked element's absolute X position at the time the drag was
16472 * @property startPageY
16479 * The group defines a logical collection of DragDrop objects that are
16480 * related. Instances only get events when interacting with other
16481 * DragDrop object in the same group. This lets us define multiple
16482 * groups using a single DragDrop subclass if we want.
16484 * @type {string: string}
16489 * Individual drag/drop instances can be locked. This will prevent
16490 * onmousedown start drag.
16498 * Lock this instance
16501 lock: function() { this.locked = true; },
16504 * Unlock this instace
16507 unlock: function() { this.locked = false; },
16510 * By default, all insances can be a drop target. This can be disabled by
16511 * setting isTarget to false.
16518 * The padding configured for this drag and drop object for calculating
16519 * the drop zone intersection with this object.
16526 * Cached reference to the linked element
16527 * @property _domRef
16533 * Internal typeof flag
16534 * @property __ygDragDrop
16537 __ygDragDrop: true,
16540 * Set to true when horizontal contraints are applied
16541 * @property constrainX
16548 * Set to true when vertical contraints are applied
16549 * @property constrainY
16556 * The left constraint
16564 * The right constraint
16572 * The up constraint
16581 * The down constraint
16589 * Maintain offsets when we resetconstraints. Set to true when you want
16590 * the position of the element relative to its parent to stay the same
16591 * when the page changes
16593 * @property maintainOffset
16596 maintainOffset: false,
16599 * Array of pixel locations the element will snap to if we specified a
16600 * horizontal graduation/interval. This array is generated automatically
16601 * when you define a tick interval.
16608 * Array of pixel locations the element will snap to if we specified a
16609 * vertical graduation/interval. This array is generated automatically
16610 * when you define a tick interval.
16617 * By default the drag and drop instance will only respond to the primary
16618 * button click (left button for a right-handed mouse). Set to true to
16619 * allow drag and drop to start with any mouse click that is propogated
16621 * @property primaryButtonOnly
16624 primaryButtonOnly: true,
16627 * The availabe property is false until the linked dom element is accessible.
16628 * @property available
16634 * By default, drags can only be initiated if the mousedown occurs in the
16635 * region the linked element is. This is done in part to work around a
16636 * bug in some browsers that mis-report the mousedown if the previous
16637 * mouseup happened outside of the window. This property is set to true
16638 * if outer handles are defined.
16640 * @property hasOuterHandles
16644 hasOuterHandles: false,
16647 * Code that executes immediately before the startDrag event
16648 * @method b4StartDrag
16651 b4StartDrag: function(x, y) { },
16654 * Abstract method called after a drag/drop object is clicked
16655 * and the drag or mousedown time thresholds have beeen met.
16656 * @method startDrag
16657 * @param {int} X click location
16658 * @param {int} Y click location
16660 startDrag: function(x, y) { /* override this */ },
16663 * Code that executes immediately before the onDrag event
16667 b4Drag: function(e) { },
16670 * Abstract method called during the onMouseMove event while dragging an
16673 * @param {Event} e the mousemove event
16675 onDrag: function(e) { /* override this */ },
16678 * Abstract method called when this element fist begins hovering over
16679 * another DragDrop obj
16680 * @method onDragEnter
16681 * @param {Event} e the mousemove event
16682 * @param {String|DragDrop[]} id In POINT mode, the element
16683 * id this is hovering over. In INTERSECT mode, an array of one or more
16684 * dragdrop items being hovered over.
16686 onDragEnter: function(e, id) { /* override this */ },
16689 * Code that executes immediately before the onDragOver event
16690 * @method b4DragOver
16693 b4DragOver: function(e) { },
16696 * Abstract method called when this element is hovering over another
16698 * @method onDragOver
16699 * @param {Event} e the mousemove event
16700 * @param {String|DragDrop[]} id In POINT mode, the element
16701 * id this is hovering over. In INTERSECT mode, an array of dd items
16702 * being hovered over.
16704 onDragOver: function(e, id) { /* override this */ },
16707 * Code that executes immediately before the onDragOut event
16708 * @method b4DragOut
16711 b4DragOut: function(e) { },
16714 * Abstract method called when we are no longer hovering over an element
16715 * @method onDragOut
16716 * @param {Event} e the mousemove event
16717 * @param {String|DragDrop[]} id In POINT mode, the element
16718 * id this was hovering over. In INTERSECT mode, an array of dd items
16719 * that the mouse is no longer over.
16721 onDragOut: function(e, id) { /* override this */ },
16724 * Code that executes immediately before the onDragDrop event
16725 * @method b4DragDrop
16728 b4DragDrop: function(e) { },
16731 * Abstract method called when this item is dropped on another DragDrop
16733 * @method onDragDrop
16734 * @param {Event} e the mouseup event
16735 * @param {String|DragDrop[]} id In POINT mode, the element
16736 * id this was dropped on. In INTERSECT mode, an array of dd items this
16739 onDragDrop: function(e, id) { /* override this */ },
16742 * Abstract method called when this item is dropped on an area with no
16744 * @method onInvalidDrop
16745 * @param {Event} e the mouseup event
16747 onInvalidDrop: function(e) { /* override this */ },
16750 * Code that executes immediately before the endDrag event
16751 * @method b4EndDrag
16754 b4EndDrag: function(e) { },
16757 * Fired when we are done dragging the object
16759 * @param {Event} e the mouseup event
16761 endDrag: function(e) { /* override this */ },
16764 * Code executed immediately before the onMouseDown event
16765 * @method b4MouseDown
16766 * @param {Event} e the mousedown event
16769 b4MouseDown: function(e) { },
16772 * Event handler that fires when a drag/drop obj gets a mousedown
16773 * @method onMouseDown
16774 * @param {Event} e the mousedown event
16776 onMouseDown: function(e) { /* override this */ },
16779 * Event handler that fires when a drag/drop obj gets a mouseup
16780 * @method onMouseUp
16781 * @param {Event} e the mouseup event
16783 onMouseUp: function(e) { /* override this */ },
16786 * Override the onAvailable method to do what is needed after the initial
16787 * position was determined.
16788 * @method onAvailable
16790 onAvailable: function () {
16794 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16797 defaultPadding : {left:0, right:0, top:0, bottom:0},
16800 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16804 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16805 { dragElId: "existingProxyDiv" });
16806 dd.startDrag = function(){
16807 this.constrainTo("parent-id");
16810 * Or you can initalize it using the {@link Roo.Element} object:
16812 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16813 startDrag : function(){
16814 this.constrainTo("parent-id");
16818 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16819 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16820 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16821 * an object containing the sides to pad. For example: {right:10, bottom:10}
16822 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16824 constrainTo : function(constrainTo, pad, inContent){
16825 if(typeof pad == "number"){
16826 pad = {left: pad, right:pad, top:pad, bottom:pad};
16828 pad = pad || this.defaultPadding;
16829 var b = Roo.get(this.getEl()).getBox();
16830 var ce = Roo.get(constrainTo);
16831 var s = ce.getScroll();
16832 var c, cd = ce.dom;
16833 if(cd == document.body){
16834 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16837 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16841 var topSpace = b.y - c.y;
16842 var leftSpace = b.x - c.x;
16844 this.resetConstraints();
16845 this.setXConstraint(leftSpace - (pad.left||0), // left
16846 c.width - leftSpace - b.width - (pad.right||0) //right
16848 this.setYConstraint(topSpace - (pad.top||0), //top
16849 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16854 * Returns a reference to the linked element
16856 * @return {HTMLElement} the html element
16858 getEl: function() {
16859 if (!this._domRef) {
16860 this._domRef = Roo.getDom(this.id);
16863 return this._domRef;
16867 * Returns a reference to the actual element to drag. By default this is
16868 * the same as the html element, but it can be assigned to another
16869 * element. An example of this can be found in Roo.dd.DDProxy
16870 * @method getDragEl
16871 * @return {HTMLElement} the html element
16873 getDragEl: function() {
16874 return Roo.getDom(this.dragElId);
16878 * Sets up the DragDrop object. Must be called in the constructor of any
16879 * Roo.dd.DragDrop subclass
16881 * @param id the id of the linked element
16882 * @param {String} sGroup the group of related items
16883 * @param {object} config configuration attributes
16885 init: function(id, sGroup, config) {
16886 this.initTarget(id, sGroup, config);
16887 if (!Roo.isTouch) {
16888 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16890 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16891 // Event.on(this.id, "selectstart", Event.preventDefault);
16895 * Initializes Targeting functionality only... the object does not
16896 * get a mousedown handler.
16897 * @method initTarget
16898 * @param id the id of the linked element
16899 * @param {String} sGroup the group of related items
16900 * @param {object} config configuration attributes
16902 initTarget: function(id, sGroup, config) {
16904 // configuration attributes
16905 this.config = config || {};
16907 // create a local reference to the drag and drop manager
16908 this.DDM = Roo.dd.DDM;
16909 // initialize the groups array
16912 // assume that we have an element reference instead of an id if the
16913 // parameter is not a string
16914 if (typeof id !== "string") {
16921 // add to an interaction group
16922 this.addToGroup((sGroup) ? sGroup : "default");
16924 // We don't want to register this as the handle with the manager
16925 // so we just set the id rather than calling the setter.
16926 this.handleElId = id;
16928 // the linked element is the element that gets dragged by default
16929 this.setDragElId(id);
16931 // by default, clicked anchors will not start drag operations.
16932 this.invalidHandleTypes = { A: "A" };
16933 this.invalidHandleIds = {};
16934 this.invalidHandleClasses = [];
16936 this.applyConfig();
16938 this.handleOnAvailable();
16942 * Applies the configuration parameters that were passed into the constructor.
16943 * This is supposed to happen at each level through the inheritance chain. So
16944 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16945 * DragDrop in order to get all of the parameters that are available in
16947 * @method applyConfig
16949 applyConfig: function() {
16951 // configurable properties:
16952 // padding, isTarget, maintainOffset, primaryButtonOnly
16953 this.padding = this.config.padding || [0, 0, 0, 0];
16954 this.isTarget = (this.config.isTarget !== false);
16955 this.maintainOffset = (this.config.maintainOffset);
16956 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16961 * Executed when the linked element is available
16962 * @method handleOnAvailable
16965 handleOnAvailable: function() {
16966 this.available = true;
16967 this.resetConstraints();
16968 this.onAvailable();
16972 * Configures the padding for the target zone in px. Effectively expands
16973 * (or reduces) the virtual object size for targeting calculations.
16974 * Supports css-style shorthand; if only one parameter is passed, all sides
16975 * will have that padding, and if only two are passed, the top and bottom
16976 * will have the first param, the left and right the second.
16977 * @method setPadding
16978 * @param {int} iTop Top pad
16979 * @param {int} iRight Right pad
16980 * @param {int} iBot Bot pad
16981 * @param {int} iLeft Left pad
16983 setPadding: function(iTop, iRight, iBot, iLeft) {
16984 // this.padding = [iLeft, iRight, iTop, iBot];
16985 if (!iRight && 0 !== iRight) {
16986 this.padding = [iTop, iTop, iTop, iTop];
16987 } else if (!iBot && 0 !== iBot) {
16988 this.padding = [iTop, iRight, iTop, iRight];
16990 this.padding = [iTop, iRight, iBot, iLeft];
16995 * Stores the initial placement of the linked element.
16996 * @method setInitialPosition
16997 * @param {int} diffX the X offset, default 0
16998 * @param {int} diffY the Y offset, default 0
17000 setInitPosition: function(diffX, diffY) {
17001 var el = this.getEl();
17003 if (!this.DDM.verifyEl(el)) {
17007 var dx = diffX || 0;
17008 var dy = diffY || 0;
17010 var p = Dom.getXY( el );
17012 this.initPageX = p[0] - dx;
17013 this.initPageY = p[1] - dy;
17015 this.lastPageX = p[0];
17016 this.lastPageY = p[1];
17019 this.setStartPosition(p);
17023 * Sets the start position of the element. This is set when the obj
17024 * is initialized, the reset when a drag is started.
17025 * @method setStartPosition
17026 * @param pos current position (from previous lookup)
17029 setStartPosition: function(pos) {
17030 var p = pos || Dom.getXY( this.getEl() );
17031 this.deltaSetXY = null;
17033 this.startPageX = p[0];
17034 this.startPageY = p[1];
17038 * Add this instance to a group of related drag/drop objects. All
17039 * instances belong to at least one group, and can belong to as many
17040 * groups as needed.
17041 * @method addToGroup
17042 * @param sGroup {string} the name of the group
17044 addToGroup: function(sGroup) {
17045 this.groups[sGroup] = true;
17046 this.DDM.regDragDrop(this, sGroup);
17050 * Remove's this instance from the supplied interaction group
17051 * @method removeFromGroup
17052 * @param {string} sGroup The group to drop
17054 removeFromGroup: function(sGroup) {
17055 if (this.groups[sGroup]) {
17056 delete this.groups[sGroup];
17059 this.DDM.removeDDFromGroup(this, sGroup);
17063 * Allows you to specify that an element other than the linked element
17064 * will be moved with the cursor during a drag
17065 * @method setDragElId
17066 * @param id {string} the id of the element that will be used to initiate the drag
17068 setDragElId: function(id) {
17069 this.dragElId = id;
17073 * Allows you to specify a child of the linked element that should be
17074 * used to initiate the drag operation. An example of this would be if
17075 * you have a content div with text and links. Clicking anywhere in the
17076 * content area would normally start the drag operation. Use this method
17077 * to specify that an element inside of the content div is the element
17078 * that starts the drag operation.
17079 * @method setHandleElId
17080 * @param id {string} the id of the element that will be used to
17081 * initiate the drag.
17083 setHandleElId: function(id) {
17084 if (typeof id !== "string") {
17087 this.handleElId = id;
17088 this.DDM.regHandle(this.id, id);
17092 * Allows you to set an element outside of the linked element as a drag
17094 * @method setOuterHandleElId
17095 * @param id the id of the element that will be used to initiate the drag
17097 setOuterHandleElId: function(id) {
17098 if (typeof id !== "string") {
17101 Event.on(id, "mousedown",
17102 this.handleMouseDown, this);
17103 this.setHandleElId(id);
17105 this.hasOuterHandles = true;
17109 * Remove all drag and drop hooks for this element
17112 unreg: function() {
17113 Event.un(this.id, "mousedown",
17114 this.handleMouseDown);
17115 Event.un(this.id, "touchstart",
17116 this.handleMouseDown);
17117 this._domRef = null;
17118 this.DDM._remove(this);
17121 destroy : function(){
17126 * Returns true if this instance is locked, or the drag drop mgr is locked
17127 * (meaning that all drag/drop is disabled on the page.)
17129 * @return {boolean} true if this obj or all drag/drop is locked, else
17132 isLocked: function() {
17133 return (this.DDM.isLocked() || this.locked);
17137 * Fired when this object is clicked
17138 * @method handleMouseDown
17140 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17143 handleMouseDown: function(e, oDD){
17145 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17146 //Roo.log('not touch/ button !=0');
17149 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17150 return; // double touch..
17154 if (this.isLocked()) {
17155 //Roo.log('locked');
17159 this.DDM.refreshCache(this.groups);
17160 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17161 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17162 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17163 //Roo.log('no outer handes or not over target');
17166 // Roo.log('check validator');
17167 if (this.clickValidator(e)) {
17168 // Roo.log('validate success');
17169 // set the initial element position
17170 this.setStartPosition();
17173 this.b4MouseDown(e);
17174 this.onMouseDown(e);
17176 this.DDM.handleMouseDown(e, this);
17178 this.DDM.stopEvent(e);
17186 clickValidator: function(e) {
17187 var target = e.getTarget();
17188 return ( this.isValidHandleChild(target) &&
17189 (this.id == this.handleElId ||
17190 this.DDM.handleWasClicked(target, this.id)) );
17194 * Allows you to specify a tag name that should not start a drag operation
17195 * when clicked. This is designed to facilitate embedding links within a
17196 * drag handle that do something other than start the drag.
17197 * @method addInvalidHandleType
17198 * @param {string} tagName the type of element to exclude
17200 addInvalidHandleType: function(tagName) {
17201 var type = tagName.toUpperCase();
17202 this.invalidHandleTypes[type] = type;
17206 * Lets you to specify an element id for a child of a drag handle
17207 * that should not initiate a drag
17208 * @method addInvalidHandleId
17209 * @param {string} id the element id of the element you wish to ignore
17211 addInvalidHandleId: function(id) {
17212 if (typeof id !== "string") {
17215 this.invalidHandleIds[id] = id;
17219 * Lets you specify a css class of elements that will not initiate a drag
17220 * @method addInvalidHandleClass
17221 * @param {string} cssClass the class of the elements you wish to ignore
17223 addInvalidHandleClass: function(cssClass) {
17224 this.invalidHandleClasses.push(cssClass);
17228 * Unsets an excluded tag name set by addInvalidHandleType
17229 * @method removeInvalidHandleType
17230 * @param {string} tagName the type of element to unexclude
17232 removeInvalidHandleType: function(tagName) {
17233 var type = tagName.toUpperCase();
17234 // this.invalidHandleTypes[type] = null;
17235 delete this.invalidHandleTypes[type];
17239 * Unsets an invalid handle id
17240 * @method removeInvalidHandleId
17241 * @param {string} id the id of the element to re-enable
17243 removeInvalidHandleId: function(id) {
17244 if (typeof id !== "string") {
17247 delete this.invalidHandleIds[id];
17251 * Unsets an invalid css class
17252 * @method removeInvalidHandleClass
17253 * @param {string} cssClass the class of the element(s) you wish to
17256 removeInvalidHandleClass: function(cssClass) {
17257 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17258 if (this.invalidHandleClasses[i] == cssClass) {
17259 delete this.invalidHandleClasses[i];
17265 * Checks the tag exclusion list to see if this click should be ignored
17266 * @method isValidHandleChild
17267 * @param {HTMLElement} node the HTMLElement to evaluate
17268 * @return {boolean} true if this is a valid tag type, false if not
17270 isValidHandleChild: function(node) {
17273 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17276 nodeName = node.nodeName.toUpperCase();
17278 nodeName = node.nodeName;
17280 valid = valid && !this.invalidHandleTypes[nodeName];
17281 valid = valid && !this.invalidHandleIds[node.id];
17283 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17284 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17293 * Create the array of horizontal tick marks if an interval was specified
17294 * in setXConstraint().
17295 * @method setXTicks
17298 setXTicks: function(iStartX, iTickSize) {
17300 this.xTickSize = iTickSize;
17304 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17306 this.xTicks[this.xTicks.length] = i;
17311 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17313 this.xTicks[this.xTicks.length] = i;
17318 this.xTicks.sort(this.DDM.numericSort) ;
17322 * Create the array of vertical tick marks if an interval was specified in
17323 * setYConstraint().
17324 * @method setYTicks
17327 setYTicks: function(iStartY, iTickSize) {
17329 this.yTickSize = iTickSize;
17333 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17335 this.yTicks[this.yTicks.length] = i;
17340 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17342 this.yTicks[this.yTicks.length] = i;
17347 this.yTicks.sort(this.DDM.numericSort) ;
17351 * By default, the element can be dragged any place on the screen. Use
17352 * this method to limit the horizontal travel of the element. Pass in
17353 * 0,0 for the parameters if you want to lock the drag to the y axis.
17354 * @method setXConstraint
17355 * @param {int} iLeft the number of pixels the element can move to the left
17356 * @param {int} iRight the number of pixels the element can move to the
17358 * @param {int} iTickSize optional parameter for specifying that the
17360 * should move iTickSize pixels at a time.
17362 setXConstraint: function(iLeft, iRight, iTickSize) {
17363 this.leftConstraint = iLeft;
17364 this.rightConstraint = iRight;
17366 this.minX = this.initPageX - iLeft;
17367 this.maxX = this.initPageX + iRight;
17368 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17370 this.constrainX = true;
17374 * Clears any constraints applied to this instance. Also clears ticks
17375 * since they can't exist independent of a constraint at this time.
17376 * @method clearConstraints
17378 clearConstraints: function() {
17379 this.constrainX = false;
17380 this.constrainY = false;
17385 * Clears any tick interval defined for this instance
17386 * @method clearTicks
17388 clearTicks: function() {
17389 this.xTicks = null;
17390 this.yTicks = null;
17391 this.xTickSize = 0;
17392 this.yTickSize = 0;
17396 * By default, the element can be dragged any place on the screen. Set
17397 * this to limit the vertical travel of the element. Pass in 0,0 for the
17398 * parameters if you want to lock the drag to the x axis.
17399 * @method setYConstraint
17400 * @param {int} iUp the number of pixels the element can move up
17401 * @param {int} iDown the number of pixels the element can move down
17402 * @param {int} iTickSize optional parameter for specifying that the
17403 * element should move iTickSize pixels at a time.
17405 setYConstraint: function(iUp, iDown, iTickSize) {
17406 this.topConstraint = iUp;
17407 this.bottomConstraint = iDown;
17409 this.minY = this.initPageY - iUp;
17410 this.maxY = this.initPageY + iDown;
17411 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17413 this.constrainY = true;
17418 * resetConstraints must be called if you manually reposition a dd element.
17419 * @method resetConstraints
17420 * @param {boolean} maintainOffset
17422 resetConstraints: function() {
17425 // Maintain offsets if necessary
17426 if (this.initPageX || this.initPageX === 0) {
17427 // figure out how much this thing has moved
17428 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17429 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17431 this.setInitPosition(dx, dy);
17433 // This is the first time we have detected the element's position
17435 this.setInitPosition();
17438 if (this.constrainX) {
17439 this.setXConstraint( this.leftConstraint,
17440 this.rightConstraint,
17444 if (this.constrainY) {
17445 this.setYConstraint( this.topConstraint,
17446 this.bottomConstraint,
17452 * Normally the drag element is moved pixel by pixel, but we can specify
17453 * that it move a number of pixels at a time. This method resolves the
17454 * location when we have it set up like this.
17456 * @param {int} val where we want to place the object
17457 * @param {int[]} tickArray sorted array of valid points
17458 * @return {int} the closest tick
17461 getTick: function(val, tickArray) {
17464 // If tick interval is not defined, it is effectively 1 pixel,
17465 // so we return the value passed to us.
17467 } else if (tickArray[0] >= val) {
17468 // The value is lower than the first tick, so we return the first
17470 return tickArray[0];
17472 for (var i=0, len=tickArray.length; i<len; ++i) {
17474 if (tickArray[next] && tickArray[next] >= val) {
17475 var diff1 = val - tickArray[i];
17476 var diff2 = tickArray[next] - val;
17477 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17481 // The value is larger than the last tick, so we return the last
17483 return tickArray[tickArray.length - 1];
17490 * @return {string} string representation of the dd obj
17492 toString: function() {
17493 return ("DragDrop " + this.id);
17501 * Ext JS Library 1.1.1
17502 * Copyright(c) 2006-2007, Ext JS, LLC.
17504 * Originally Released Under LGPL - original licence link has changed is not relivant.
17507 * <script type="text/javascript">
17512 * The drag and drop utility provides a framework for building drag and drop
17513 * applications. In addition to enabling drag and drop for specific elements,
17514 * the drag and drop elements are tracked by the manager class, and the
17515 * interactions between the various elements are tracked during the drag and
17516 * the implementing code is notified about these important moments.
17519 // Only load the library once. Rewriting the manager class would orphan
17520 // existing drag and drop instances.
17521 if (!Roo.dd.DragDropMgr) {
17524 * @class Roo.dd.DragDropMgr
17525 * DragDropMgr is a singleton that tracks the element interaction for
17526 * all DragDrop items in the window. Generally, you will not call
17527 * this class directly, but it does have helper methods that could
17528 * be useful in your DragDrop implementations.
17531 Roo.dd.DragDropMgr = function() {
17533 var Event = Roo.EventManager;
17538 * Two dimensional Array of registered DragDrop objects. The first
17539 * dimension is the DragDrop item group, the second the DragDrop
17542 * @type {string: string}
17549 * Array of element ids defined as drag handles. Used to determine
17550 * if the element that generated the mousedown event is actually the
17551 * handle and not the html element itself.
17552 * @property handleIds
17553 * @type {string: string}
17560 * the DragDrop object that is currently being dragged
17561 * @property dragCurrent
17569 * the DragDrop object(s) that are being hovered over
17570 * @property dragOvers
17578 * the X distance between the cursor and the object being dragged
17587 * the Y distance between the cursor and the object being dragged
17596 * Flag to determine if we should prevent the default behavior of the
17597 * events we define. By default this is true, but this can be set to
17598 * false if you need the default behavior (not recommended)
17599 * @property preventDefault
17603 preventDefault: true,
17606 * Flag to determine if we should stop the propagation of the events
17607 * we generate. This is true by default but you may want to set it to
17608 * false if the html element contains other features that require the
17610 * @property stopPropagation
17614 stopPropagation: true,
17617 * Internal flag that is set to true when drag and drop has been
17619 * @property initialized
17626 * All drag and drop can be disabled.
17634 * Called the first time an element is registered.
17640 this.initialized = true;
17644 * In point mode, drag and drop interaction is defined by the
17645 * location of the cursor during the drag/drop
17653 * In intersect mode, drag and drop interactio nis defined by the
17654 * overlap of two or more drag and drop objects.
17655 * @property INTERSECT
17662 * The current drag and drop mode. Default: POINT
17670 * Runs method on all drag and drop objects
17671 * @method _execOnAll
17675 _execOnAll: function(sMethod, args) {
17676 for (var i in this.ids) {
17677 for (var j in this.ids[i]) {
17678 var oDD = this.ids[i][j];
17679 if (! this.isTypeOfDD(oDD)) {
17682 oDD[sMethod].apply(oDD, args);
17688 * Drag and drop initialization. Sets up the global event handlers
17693 _onLoad: function() {
17697 if (!Roo.isTouch) {
17698 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17699 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17701 Event.on(document, "touchend", this.handleMouseUp, this, true);
17702 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17704 Event.on(window, "unload", this._onUnload, this, true);
17705 Event.on(window, "resize", this._onResize, this, true);
17706 // Event.on(window, "mouseout", this._test);
17711 * Reset constraints on all drag and drop objs
17712 * @method _onResize
17716 _onResize: function(e) {
17717 this._execOnAll("resetConstraints", []);
17721 * Lock all drag and drop functionality
17725 lock: function() { this.locked = true; },
17728 * Unlock all drag and drop functionality
17732 unlock: function() { this.locked = false; },
17735 * Is drag and drop locked?
17737 * @return {boolean} True if drag and drop is locked, false otherwise.
17740 isLocked: function() { return this.locked; },
17743 * Location cache that is set for all drag drop objects when a drag is
17744 * initiated, cleared when the drag is finished.
17745 * @property locationCache
17752 * Set useCache to false if you want to force object the lookup of each
17753 * drag and drop linked element constantly during a drag.
17754 * @property useCache
17761 * The number of pixels that the mouse needs to move after the
17762 * mousedown before the drag is initiated. Default=3;
17763 * @property clickPixelThresh
17767 clickPixelThresh: 3,
17770 * The number of milliseconds after the mousedown event to initiate the
17771 * drag if we don't get a mouseup event. Default=1000
17772 * @property clickTimeThresh
17776 clickTimeThresh: 350,
17779 * Flag that indicates that either the drag pixel threshold or the
17780 * mousdown time threshold has been met
17781 * @property dragThreshMet
17786 dragThreshMet: false,
17789 * Timeout used for the click time threshold
17790 * @property clickTimeout
17795 clickTimeout: null,
17798 * The X position of the mousedown event stored for later use when a
17799 * drag threshold is met.
17808 * The Y position of the mousedown event stored for later use when a
17809 * drag threshold is met.
17818 * Each DragDrop instance must be registered with the DragDropMgr.
17819 * This is executed in DragDrop.init()
17820 * @method regDragDrop
17821 * @param {DragDrop} oDD the DragDrop object to register
17822 * @param {String} sGroup the name of the group this element belongs to
17825 regDragDrop: function(oDD, sGroup) {
17826 if (!this.initialized) { this.init(); }
17828 if (!this.ids[sGroup]) {
17829 this.ids[sGroup] = {};
17831 this.ids[sGroup][oDD.id] = oDD;
17835 * Removes the supplied dd instance from the supplied group. Executed
17836 * by DragDrop.removeFromGroup, so don't call this function directly.
17837 * @method removeDDFromGroup
17841 removeDDFromGroup: function(oDD, sGroup) {
17842 if (!this.ids[sGroup]) {
17843 this.ids[sGroup] = {};
17846 var obj = this.ids[sGroup];
17847 if (obj && obj[oDD.id]) {
17848 delete obj[oDD.id];
17853 * Unregisters a drag and drop item. This is executed in
17854 * DragDrop.unreg, use that method instead of calling this directly.
17859 _remove: function(oDD) {
17860 for (var g in oDD.groups) {
17861 if (g && this.ids[g][oDD.id]) {
17862 delete this.ids[g][oDD.id];
17865 delete this.handleIds[oDD.id];
17869 * Each DragDrop handle element must be registered. This is done
17870 * automatically when executing DragDrop.setHandleElId()
17871 * @method regHandle
17872 * @param {String} sDDId the DragDrop id this element is a handle for
17873 * @param {String} sHandleId the id of the element that is the drag
17877 regHandle: function(sDDId, sHandleId) {
17878 if (!this.handleIds[sDDId]) {
17879 this.handleIds[sDDId] = {};
17881 this.handleIds[sDDId][sHandleId] = sHandleId;
17885 * Utility function to determine if a given element has been
17886 * registered as a drag drop item.
17887 * @method isDragDrop
17888 * @param {String} id the element id to check
17889 * @return {boolean} true if this element is a DragDrop item,
17893 isDragDrop: function(id) {
17894 return ( this.getDDById(id) ) ? true : false;
17898 * Returns the drag and drop instances that are in all groups the
17899 * passed in instance belongs to.
17900 * @method getRelated
17901 * @param {DragDrop} p_oDD the obj to get related data for
17902 * @param {boolean} bTargetsOnly if true, only return targetable objs
17903 * @return {DragDrop[]} the related instances
17906 getRelated: function(p_oDD, bTargetsOnly) {
17908 for (var i in p_oDD.groups) {
17909 for (j in this.ids[i]) {
17910 var dd = this.ids[i][j];
17911 if (! this.isTypeOfDD(dd)) {
17914 if (!bTargetsOnly || dd.isTarget) {
17915 oDDs[oDDs.length] = dd;
17924 * Returns true if the specified dd target is a legal target for
17925 * the specifice drag obj
17926 * @method isLegalTarget
17927 * @param {DragDrop} the drag obj
17928 * @param {DragDrop} the target
17929 * @return {boolean} true if the target is a legal target for the
17933 isLegalTarget: function (oDD, oTargetDD) {
17934 var targets = this.getRelated(oDD, true);
17935 for (var i=0, len=targets.length;i<len;++i) {
17936 if (targets[i].id == oTargetDD.id) {
17945 * My goal is to be able to transparently determine if an object is
17946 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17947 * returns "object", oDD.constructor.toString() always returns
17948 * "DragDrop" and not the name of the subclass. So for now it just
17949 * evaluates a well-known variable in DragDrop.
17950 * @method isTypeOfDD
17951 * @param {Object} the object to evaluate
17952 * @return {boolean} true if typeof oDD = DragDrop
17955 isTypeOfDD: function (oDD) {
17956 return (oDD && oDD.__ygDragDrop);
17960 * Utility function to determine if a given element has been
17961 * registered as a drag drop handle for the given Drag Drop object.
17963 * @param {String} id the element id to check
17964 * @return {boolean} true if this element is a DragDrop handle, false
17968 isHandle: function(sDDId, sHandleId) {
17969 return ( this.handleIds[sDDId] &&
17970 this.handleIds[sDDId][sHandleId] );
17974 * Returns the DragDrop instance for a given id
17975 * @method getDDById
17976 * @param {String} id the id of the DragDrop object
17977 * @return {DragDrop} the drag drop object, null if it is not found
17980 getDDById: function(id) {
17981 for (var i in this.ids) {
17982 if (this.ids[i][id]) {
17983 return this.ids[i][id];
17990 * Fired after a registered DragDrop object gets the mousedown event.
17991 * Sets up the events required to track the object being dragged
17992 * @method handleMouseDown
17993 * @param {Event} e the event
17994 * @param oDD the DragDrop object being dragged
17998 handleMouseDown: function(e, oDD) {
18000 Roo.QuickTips.disable();
18002 this.currentTarget = e.getTarget();
18004 this.dragCurrent = oDD;
18006 var el = oDD.getEl();
18008 // track start position
18009 this.startX = e.getPageX();
18010 this.startY = e.getPageY();
18012 this.deltaX = this.startX - el.offsetLeft;
18013 this.deltaY = this.startY - el.offsetTop;
18015 this.dragThreshMet = false;
18017 this.clickTimeout = setTimeout(
18019 var DDM = Roo.dd.DDM;
18020 DDM.startDrag(DDM.startX, DDM.startY);
18022 this.clickTimeThresh );
18026 * Fired when either the drag pixel threshol or the mousedown hold
18027 * time threshold has been met.
18028 * @method startDrag
18029 * @param x {int} the X position of the original mousedown
18030 * @param y {int} the Y position of the original mousedown
18033 startDrag: function(x, y) {
18034 clearTimeout(this.clickTimeout);
18035 if (this.dragCurrent) {
18036 this.dragCurrent.b4StartDrag(x, y);
18037 this.dragCurrent.startDrag(x, y);
18039 this.dragThreshMet = true;
18043 * Internal function to handle the mouseup event. Will be invoked
18044 * from the context of the document.
18045 * @method handleMouseUp
18046 * @param {Event} e the event
18050 handleMouseUp: function(e) {
18053 Roo.QuickTips.enable();
18055 if (! this.dragCurrent) {
18059 clearTimeout(this.clickTimeout);
18061 if (this.dragThreshMet) {
18062 this.fireEvents(e, true);
18072 * Utility to stop event propagation and event default, if these
18073 * features are turned on.
18074 * @method stopEvent
18075 * @param {Event} e the event as returned by this.getEvent()
18078 stopEvent: function(e){
18079 if(this.stopPropagation) {
18080 e.stopPropagation();
18083 if (this.preventDefault) {
18084 e.preventDefault();
18089 * Internal function to clean up event handlers after the drag
18090 * operation is complete
18092 * @param {Event} e the event
18096 stopDrag: function(e) {
18097 // Fire the drag end event for the item that was dragged
18098 if (this.dragCurrent) {
18099 if (this.dragThreshMet) {
18100 this.dragCurrent.b4EndDrag(e);
18101 this.dragCurrent.endDrag(e);
18104 this.dragCurrent.onMouseUp(e);
18107 this.dragCurrent = null;
18108 this.dragOvers = {};
18112 * Internal function to handle the mousemove event. Will be invoked
18113 * from the context of the html element.
18115 * @TODO figure out what we can do about mouse events lost when the
18116 * user drags objects beyond the window boundary. Currently we can
18117 * detect this in internet explorer by verifying that the mouse is
18118 * down during the mousemove event. Firefox doesn't give us the
18119 * button state on the mousemove event.
18120 * @method handleMouseMove
18121 * @param {Event} e the event
18125 handleMouseMove: function(e) {
18126 if (! this.dragCurrent) {
18130 // var button = e.which || e.button;
18132 // check for IE mouseup outside of page boundary
18133 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18135 return this.handleMouseUp(e);
18138 if (!this.dragThreshMet) {
18139 var diffX = Math.abs(this.startX - e.getPageX());
18140 var diffY = Math.abs(this.startY - e.getPageY());
18141 if (diffX > this.clickPixelThresh ||
18142 diffY > this.clickPixelThresh) {
18143 this.startDrag(this.startX, this.startY);
18147 if (this.dragThreshMet) {
18148 this.dragCurrent.b4Drag(e);
18149 this.dragCurrent.onDrag(e);
18150 if(!this.dragCurrent.moveOnly){
18151 this.fireEvents(e, false);
18161 * Iterates over all of the DragDrop elements to find ones we are
18162 * hovering over or dropping on
18163 * @method fireEvents
18164 * @param {Event} e the event
18165 * @param {boolean} isDrop is this a drop op or a mouseover op?
18169 fireEvents: function(e, isDrop) {
18170 var dc = this.dragCurrent;
18172 // If the user did the mouse up outside of the window, we could
18173 // get here even though we have ended the drag.
18174 if (!dc || dc.isLocked()) {
18178 var pt = e.getPoint();
18180 // cache the previous dragOver array
18186 var enterEvts = [];
18188 // Check to see if the object(s) we were hovering over is no longer
18189 // being hovered over so we can fire the onDragOut event
18190 for (var i in this.dragOvers) {
18192 var ddo = this.dragOvers[i];
18194 if (! this.isTypeOfDD(ddo)) {
18198 if (! this.isOverTarget(pt, ddo, this.mode)) {
18199 outEvts.push( ddo );
18202 oldOvers[i] = true;
18203 delete this.dragOvers[i];
18206 for (var sGroup in dc.groups) {
18208 if ("string" != typeof sGroup) {
18212 for (i in this.ids[sGroup]) {
18213 var oDD = this.ids[sGroup][i];
18214 if (! this.isTypeOfDD(oDD)) {
18218 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18219 if (this.isOverTarget(pt, oDD, this.mode)) {
18220 // look for drop interactions
18222 dropEvts.push( oDD );
18223 // look for drag enter and drag over interactions
18226 // initial drag over: dragEnter fires
18227 if (!oldOvers[oDD.id]) {
18228 enterEvts.push( oDD );
18229 // subsequent drag overs: dragOver fires
18231 overEvts.push( oDD );
18234 this.dragOvers[oDD.id] = oDD;
18242 if (outEvts.length) {
18243 dc.b4DragOut(e, outEvts);
18244 dc.onDragOut(e, outEvts);
18247 if (enterEvts.length) {
18248 dc.onDragEnter(e, enterEvts);
18251 if (overEvts.length) {
18252 dc.b4DragOver(e, overEvts);
18253 dc.onDragOver(e, overEvts);
18256 if (dropEvts.length) {
18257 dc.b4DragDrop(e, dropEvts);
18258 dc.onDragDrop(e, dropEvts);
18262 // fire dragout events
18264 for (i=0, len=outEvts.length; i<len; ++i) {
18265 dc.b4DragOut(e, outEvts[i].id);
18266 dc.onDragOut(e, outEvts[i].id);
18269 // fire enter events
18270 for (i=0,len=enterEvts.length; i<len; ++i) {
18271 // dc.b4DragEnter(e, oDD.id);
18272 dc.onDragEnter(e, enterEvts[i].id);
18275 // fire over events
18276 for (i=0,len=overEvts.length; i<len; ++i) {
18277 dc.b4DragOver(e, overEvts[i].id);
18278 dc.onDragOver(e, overEvts[i].id);
18281 // fire drop events
18282 for (i=0, len=dropEvts.length; i<len; ++i) {
18283 dc.b4DragDrop(e, dropEvts[i].id);
18284 dc.onDragDrop(e, dropEvts[i].id);
18289 // notify about a drop that did not find a target
18290 if (isDrop && !dropEvts.length) {
18291 dc.onInvalidDrop(e);
18297 * Helper function for getting the best match from the list of drag
18298 * and drop objects returned by the drag and drop events when we are
18299 * in INTERSECT mode. It returns either the first object that the
18300 * cursor is over, or the object that has the greatest overlap with
18301 * the dragged element.
18302 * @method getBestMatch
18303 * @param {DragDrop[]} dds The array of drag and drop objects
18305 * @return {DragDrop} The best single match
18308 getBestMatch: function(dds) {
18310 // Return null if the input is not what we expect
18311 //if (!dds || !dds.length || dds.length == 0) {
18313 // If there is only one item, it wins
18314 //} else if (dds.length == 1) {
18316 var len = dds.length;
18321 // Loop through the targeted items
18322 for (var i=0; i<len; ++i) {
18324 // If the cursor is over the object, it wins. If the
18325 // cursor is over multiple matches, the first one we come
18327 if (dd.cursorIsOver) {
18330 // Otherwise the object with the most overlap wins
18333 winner.overlap.getArea() < dd.overlap.getArea()) {
18344 * Refreshes the cache of the top-left and bottom-right points of the
18345 * drag and drop objects in the specified group(s). This is in the
18346 * format that is stored in the drag and drop instance, so typical
18349 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18353 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18355 * @TODO this really should be an indexed array. Alternatively this
18356 * method could accept both.
18357 * @method refreshCache
18358 * @param {Object} groups an associative array of groups to refresh
18361 refreshCache: function(groups) {
18362 for (var sGroup in groups) {
18363 if ("string" != typeof sGroup) {
18366 for (var i in this.ids[sGroup]) {
18367 var oDD = this.ids[sGroup][i];
18369 if (this.isTypeOfDD(oDD)) {
18370 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18371 var loc = this.getLocation(oDD);
18373 this.locationCache[oDD.id] = loc;
18375 delete this.locationCache[oDD.id];
18376 // this will unregister the drag and drop object if
18377 // the element is not in a usable state
18386 * This checks to make sure an element exists and is in the DOM. The
18387 * main purpose is to handle cases where innerHTML is used to remove
18388 * drag and drop objects from the DOM. IE provides an 'unspecified
18389 * error' when trying to access the offsetParent of such an element
18391 * @param {HTMLElement} el the element to check
18392 * @return {boolean} true if the element looks usable
18395 verifyEl: function(el) {
18400 parent = el.offsetParent;
18403 parent = el.offsetParent;
18414 * Returns a Region object containing the drag and drop element's position
18415 * and size, including the padding configured for it
18416 * @method getLocation
18417 * @param {DragDrop} oDD the drag and drop object to get the
18419 * @return {Roo.lib.Region} a Region object representing the total area
18420 * the element occupies, including any padding
18421 * the instance is configured for.
18424 getLocation: function(oDD) {
18425 if (! this.isTypeOfDD(oDD)) {
18429 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18432 pos= Roo.lib.Dom.getXY(el);
18440 x2 = x1 + el.offsetWidth;
18442 y2 = y1 + el.offsetHeight;
18444 t = y1 - oDD.padding[0];
18445 r = x2 + oDD.padding[1];
18446 b = y2 + oDD.padding[2];
18447 l = x1 - oDD.padding[3];
18449 return new Roo.lib.Region( t, r, b, l );
18453 * Checks the cursor location to see if it over the target
18454 * @method isOverTarget
18455 * @param {Roo.lib.Point} pt The point to evaluate
18456 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18457 * @return {boolean} true if the mouse is over the target
18461 isOverTarget: function(pt, oTarget, intersect) {
18462 // use cache if available
18463 var loc = this.locationCache[oTarget.id];
18464 if (!loc || !this.useCache) {
18465 loc = this.getLocation(oTarget);
18466 this.locationCache[oTarget.id] = loc;
18474 oTarget.cursorIsOver = loc.contains( pt );
18476 // DragDrop is using this as a sanity check for the initial mousedown
18477 // in this case we are done. In POINT mode, if the drag obj has no
18478 // contraints, we are also done. Otherwise we need to evaluate the
18479 // location of the target as related to the actual location of the
18480 // dragged element.
18481 var dc = this.dragCurrent;
18482 if (!dc || !dc.getTargetCoord ||
18483 (!intersect && !dc.constrainX && !dc.constrainY)) {
18484 return oTarget.cursorIsOver;
18487 oTarget.overlap = null;
18489 // Get the current location of the drag element, this is the
18490 // location of the mouse event less the delta that represents
18491 // where the original mousedown happened on the element. We
18492 // need to consider constraints and ticks as well.
18493 var pos = dc.getTargetCoord(pt.x, pt.y);
18495 var el = dc.getDragEl();
18496 var curRegion = new Roo.lib.Region( pos.y,
18497 pos.x + el.offsetWidth,
18498 pos.y + el.offsetHeight,
18501 var overlap = curRegion.intersect(loc);
18504 oTarget.overlap = overlap;
18505 return (intersect) ? true : oTarget.cursorIsOver;
18512 * unload event handler
18513 * @method _onUnload
18517 _onUnload: function(e, me) {
18518 Roo.dd.DragDropMgr.unregAll();
18522 * Cleans up the drag and drop events and objects.
18527 unregAll: function() {
18529 if (this.dragCurrent) {
18531 this.dragCurrent = null;
18534 this._execOnAll("unreg", []);
18536 for (i in this.elementCache) {
18537 delete this.elementCache[i];
18540 this.elementCache = {};
18545 * A cache of DOM elements
18546 * @property elementCache
18553 * Get the wrapper for the DOM element specified
18554 * @method getElWrapper
18555 * @param {String} id the id of the element to get
18556 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18558 * @deprecated This wrapper isn't that useful
18561 getElWrapper: function(id) {
18562 var oWrapper = this.elementCache[id];
18563 if (!oWrapper || !oWrapper.el) {
18564 oWrapper = this.elementCache[id] =
18565 new this.ElementWrapper(Roo.getDom(id));
18571 * Returns the actual DOM element
18572 * @method getElement
18573 * @param {String} id the id of the elment to get
18574 * @return {Object} The element
18575 * @deprecated use Roo.getDom instead
18578 getElement: function(id) {
18579 return Roo.getDom(id);
18583 * Returns the style property for the DOM element (i.e.,
18584 * document.getElById(id).style)
18586 * @param {String} id the id of the elment to get
18587 * @return {Object} The style property of the element
18588 * @deprecated use Roo.getDom instead
18591 getCss: function(id) {
18592 var el = Roo.getDom(id);
18593 return (el) ? el.style : null;
18597 * Inner class for cached elements
18598 * @class DragDropMgr.ElementWrapper
18603 ElementWrapper: function(el) {
18608 this.el = el || null;
18613 this.id = this.el && el.id;
18615 * A reference to the style property
18618 this.css = this.el && el.style;
18622 * Returns the X position of an html element
18624 * @param el the element for which to get the position
18625 * @return {int} the X coordinate
18627 * @deprecated use Roo.lib.Dom.getX instead
18630 getPosX: function(el) {
18631 return Roo.lib.Dom.getX(el);
18635 * Returns the Y position of an html element
18637 * @param el the element for which to get the position
18638 * @return {int} the Y coordinate
18639 * @deprecated use Roo.lib.Dom.getY instead
18642 getPosY: function(el) {
18643 return Roo.lib.Dom.getY(el);
18647 * Swap two nodes. In IE, we use the native method, for others we
18648 * emulate the IE behavior
18650 * @param n1 the first node to swap
18651 * @param n2 the other node to swap
18654 swapNode: function(n1, n2) {
18658 var p = n2.parentNode;
18659 var s = n2.nextSibling;
18662 p.insertBefore(n1, n2);
18663 } else if (n2 == n1.nextSibling) {
18664 p.insertBefore(n2, n1);
18666 n1.parentNode.replaceChild(n2, n1);
18667 p.insertBefore(n1, s);
18673 * Returns the current scroll position
18674 * @method getScroll
18678 getScroll: function () {
18679 var t, l, dde=document.documentElement, db=document.body;
18680 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18682 l = dde.scrollLeft;
18689 return { top: t, left: l };
18693 * Returns the specified element style property
18695 * @param {HTMLElement} el the element
18696 * @param {string} styleProp the style property
18697 * @return {string} The value of the style property
18698 * @deprecated use Roo.lib.Dom.getStyle
18701 getStyle: function(el, styleProp) {
18702 return Roo.fly(el).getStyle(styleProp);
18706 * Gets the scrollTop
18707 * @method getScrollTop
18708 * @return {int} the document's scrollTop
18711 getScrollTop: function () { return this.getScroll().top; },
18714 * Gets the scrollLeft
18715 * @method getScrollLeft
18716 * @return {int} the document's scrollTop
18719 getScrollLeft: function () { return this.getScroll().left; },
18722 * Sets the x/y position of an element to the location of the
18725 * @param {HTMLElement} moveEl The element to move
18726 * @param {HTMLElement} targetEl The position reference element
18729 moveToEl: function (moveEl, targetEl) {
18730 var aCoord = Roo.lib.Dom.getXY(targetEl);
18731 Roo.lib.Dom.setXY(moveEl, aCoord);
18735 * Numeric array sort function
18736 * @method numericSort
18739 numericSort: function(a, b) { return (a - b); },
18743 * @property _timeoutCount
18750 * Trying to make the load order less important. Without this we get
18751 * an error if this file is loaded before the Event Utility.
18752 * @method _addListeners
18756 _addListeners: function() {
18757 var DDM = Roo.dd.DDM;
18758 if ( Roo.lib.Event && document ) {
18761 if (DDM._timeoutCount > 2000) {
18763 setTimeout(DDM._addListeners, 10);
18764 if (document && document.body) {
18765 DDM._timeoutCount += 1;
18772 * Recursively searches the immediate parent and all child nodes for
18773 * the handle element in order to determine wheter or not it was
18775 * @method handleWasClicked
18776 * @param node the html element to inspect
18779 handleWasClicked: function(node, id) {
18780 if (this.isHandle(id, node.id)) {
18783 // check to see if this is a text node child of the one we want
18784 var p = node.parentNode;
18787 if (this.isHandle(id, p.id)) {
18802 // shorter alias, save a few bytes
18803 Roo.dd.DDM = Roo.dd.DragDropMgr;
18804 Roo.dd.DDM._addListeners();
18808 * Ext JS Library 1.1.1
18809 * Copyright(c) 2006-2007, Ext JS, LLC.
18811 * Originally Released Under LGPL - original licence link has changed is not relivant.
18814 * <script type="text/javascript">
18819 * A DragDrop implementation where the linked element follows the
18820 * mouse cursor during a drag.
18821 * @extends Roo.dd.DragDrop
18823 * @param {String} id the id of the linked element
18824 * @param {String} sGroup the group of related DragDrop items
18825 * @param {object} config an object containing configurable attributes
18826 * Valid properties for DD:
18829 Roo.dd.DD = function(id, sGroup, config) {
18831 this.init(id, sGroup, config);
18835 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18838 * When set to true, the utility automatically tries to scroll the browser
18839 * window wehn a drag and drop element is dragged near the viewport boundary.
18840 * Defaults to true.
18847 * Sets the pointer offset to the distance between the linked element's top
18848 * left corner and the location the element was clicked
18849 * @method autoOffset
18850 * @param {int} iPageX the X coordinate of the click
18851 * @param {int} iPageY the Y coordinate of the click
18853 autoOffset: function(iPageX, iPageY) {
18854 var x = iPageX - this.startPageX;
18855 var y = iPageY - this.startPageY;
18856 this.setDelta(x, y);
18860 * Sets the pointer offset. You can call this directly to force the
18861 * offset to be in a particular location (e.g., pass in 0,0 to set it
18862 * to the center of the object)
18864 * @param {int} iDeltaX the distance from the left
18865 * @param {int} iDeltaY the distance from the top
18867 setDelta: function(iDeltaX, iDeltaY) {
18868 this.deltaX = iDeltaX;
18869 this.deltaY = iDeltaY;
18873 * Sets the drag element to the location of the mousedown or click event,
18874 * maintaining the cursor location relative to the location on the element
18875 * that was clicked. Override this if you want to place the element in a
18876 * location other than where the cursor is.
18877 * @method setDragElPos
18878 * @param {int} iPageX the X coordinate of the mousedown or drag event
18879 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18881 setDragElPos: function(iPageX, iPageY) {
18882 // the first time we do this, we are going to check to make sure
18883 // the element has css positioning
18885 var el = this.getDragEl();
18886 this.alignElWithMouse(el, iPageX, iPageY);
18890 * Sets the element to the location of the mousedown or click event,
18891 * maintaining the cursor location relative to the location on the element
18892 * that was clicked. Override this if you want to place the element in a
18893 * location other than where the cursor is.
18894 * @method alignElWithMouse
18895 * @param {HTMLElement} el the element to move
18896 * @param {int} iPageX the X coordinate of the mousedown or drag event
18897 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18899 alignElWithMouse: function(el, iPageX, iPageY) {
18900 var oCoord = this.getTargetCoord(iPageX, iPageY);
18901 var fly = el.dom ? el : Roo.fly(el);
18902 if (!this.deltaSetXY) {
18903 var aCoord = [oCoord.x, oCoord.y];
18905 var newLeft = fly.getLeft(true);
18906 var newTop = fly.getTop(true);
18907 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18909 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18912 this.cachePosition(oCoord.x, oCoord.y);
18913 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18918 * Saves the most recent position so that we can reset the constraints and
18919 * tick marks on-demand. We need to know this so that we can calculate the
18920 * number of pixels the element is offset from its original position.
18921 * @method cachePosition
18922 * @param iPageX the current x position (optional, this just makes it so we
18923 * don't have to look it up again)
18924 * @param iPageY the current y position (optional, this just makes it so we
18925 * don't have to look it up again)
18927 cachePosition: function(iPageX, iPageY) {
18929 this.lastPageX = iPageX;
18930 this.lastPageY = iPageY;
18932 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18933 this.lastPageX = aCoord[0];
18934 this.lastPageY = aCoord[1];
18939 * Auto-scroll the window if the dragged object has been moved beyond the
18940 * visible window boundary.
18941 * @method autoScroll
18942 * @param {int} x the drag element's x position
18943 * @param {int} y the drag element's y position
18944 * @param {int} h the height of the drag element
18945 * @param {int} w the width of the drag element
18948 autoScroll: function(x, y, h, w) {
18951 // The client height
18952 var clientH = Roo.lib.Dom.getViewWidth();
18954 // The client width
18955 var clientW = Roo.lib.Dom.getViewHeight();
18957 // The amt scrolled down
18958 var st = this.DDM.getScrollTop();
18960 // The amt scrolled right
18961 var sl = this.DDM.getScrollLeft();
18963 // Location of the bottom of the element
18966 // Location of the right of the element
18969 // The distance from the cursor to the bottom of the visible area,
18970 // adjusted so that we don't scroll if the cursor is beyond the
18971 // element drag constraints
18972 var toBot = (clientH + st - y - this.deltaY);
18974 // The distance from the cursor to the right of the visible area
18975 var toRight = (clientW + sl - x - this.deltaX);
18978 // How close to the edge the cursor must be before we scroll
18979 // var thresh = (document.all) ? 100 : 40;
18982 // How many pixels to scroll per autoscroll op. This helps to reduce
18983 // clunky scrolling. IE is more sensitive about this ... it needs this
18984 // value to be higher.
18985 var scrAmt = (document.all) ? 80 : 30;
18987 // Scroll down if we are near the bottom of the visible page and the
18988 // obj extends below the crease
18989 if ( bot > clientH && toBot < thresh ) {
18990 window.scrollTo(sl, st + scrAmt);
18993 // Scroll up if the window is scrolled down and the top of the object
18994 // goes above the top border
18995 if ( y < st && st > 0 && y - st < thresh ) {
18996 window.scrollTo(sl, st - scrAmt);
18999 // Scroll right if the obj is beyond the right border and the cursor is
19000 // near the border.
19001 if ( right > clientW && toRight < thresh ) {
19002 window.scrollTo(sl + scrAmt, st);
19005 // Scroll left if the window has been scrolled to the right and the obj
19006 // extends past the left border
19007 if ( x < sl && sl > 0 && x - sl < thresh ) {
19008 window.scrollTo(sl - scrAmt, st);
19014 * Finds the location the element should be placed if we want to move
19015 * it to where the mouse location less the click offset would place us.
19016 * @method getTargetCoord
19017 * @param {int} iPageX the X coordinate of the click
19018 * @param {int} iPageY the Y coordinate of the click
19019 * @return an object that contains the coordinates (Object.x and Object.y)
19022 getTargetCoord: function(iPageX, iPageY) {
19025 var x = iPageX - this.deltaX;
19026 var y = iPageY - this.deltaY;
19028 if (this.constrainX) {
19029 if (x < this.minX) { x = this.minX; }
19030 if (x > this.maxX) { x = this.maxX; }
19033 if (this.constrainY) {
19034 if (y < this.minY) { y = this.minY; }
19035 if (y > this.maxY) { y = this.maxY; }
19038 x = this.getTick(x, this.xTicks);
19039 y = this.getTick(y, this.yTicks);
19046 * Sets up config options specific to this class. Overrides
19047 * Roo.dd.DragDrop, but all versions of this method through the
19048 * inheritance chain are called
19050 applyConfig: function() {
19051 Roo.dd.DD.superclass.applyConfig.call(this);
19052 this.scroll = (this.config.scroll !== false);
19056 * Event that fires prior to the onMouseDown event. Overrides
19059 b4MouseDown: function(e) {
19060 // this.resetConstraints();
19061 this.autoOffset(e.getPageX(),
19066 * Event that fires prior to the onDrag event. Overrides
19069 b4Drag: function(e) {
19070 this.setDragElPos(e.getPageX(),
19074 toString: function() {
19075 return ("DD " + this.id);
19078 //////////////////////////////////////////////////////////////////////////
19079 // Debugging ygDragDrop events that can be overridden
19080 //////////////////////////////////////////////////////////////////////////
19082 startDrag: function(x, y) {
19085 onDrag: function(e) {
19088 onDragEnter: function(e, id) {
19091 onDragOver: function(e, id) {
19094 onDragOut: function(e, id) {
19097 onDragDrop: function(e, id) {
19100 endDrag: function(e) {
19107 * Ext JS Library 1.1.1
19108 * Copyright(c) 2006-2007, Ext JS, LLC.
19110 * Originally Released Under LGPL - original licence link has changed is not relivant.
19113 * <script type="text/javascript">
19117 * @class Roo.dd.DDProxy
19118 * A DragDrop implementation that inserts an empty, bordered div into
19119 * the document that follows the cursor during drag operations. At the time of
19120 * the click, the frame div is resized to the dimensions of the linked html
19121 * element, and moved to the exact location of the linked element.
19123 * References to the "frame" element refer to the single proxy element that
19124 * was created to be dragged in place of all DDProxy elements on the
19127 * @extends Roo.dd.DD
19129 * @param {String} id the id of the linked html element
19130 * @param {String} sGroup the group of related DragDrop objects
19131 * @param {object} config an object containing configurable attributes
19132 * Valid properties for DDProxy in addition to those in DragDrop:
19133 * resizeFrame, centerFrame, dragElId
19135 Roo.dd.DDProxy = function(id, sGroup, config) {
19137 this.init(id, sGroup, config);
19143 * The default drag frame div id
19144 * @property Roo.dd.DDProxy.dragElId
19148 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19150 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19153 * By default we resize the drag frame to be the same size as the element
19154 * we want to drag (this is to get the frame effect). We can turn it off
19155 * if we want a different behavior.
19156 * @property resizeFrame
19162 * By default the frame is positioned exactly where the drag element is, so
19163 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19164 * you do not have constraints on the obj is to have the drag frame centered
19165 * around the cursor. Set centerFrame to true for this effect.
19166 * @property centerFrame
19169 centerFrame: false,
19172 * Creates the proxy element if it does not yet exist
19173 * @method createFrame
19175 createFrame: function() {
19177 var body = document.body;
19179 if (!body || !body.firstChild) {
19180 setTimeout( function() { self.createFrame(); }, 50 );
19184 var div = this.getDragEl();
19187 div = document.createElement("div");
19188 div.id = this.dragElId;
19191 s.position = "absolute";
19192 s.visibility = "hidden";
19194 s.border = "2px solid #aaa";
19197 // appendChild can blow up IE if invoked prior to the window load event
19198 // while rendering a table. It is possible there are other scenarios
19199 // that would cause this to happen as well.
19200 body.insertBefore(div, body.firstChild);
19205 * Initialization for the drag frame element. Must be called in the
19206 * constructor of all subclasses
19207 * @method initFrame
19209 initFrame: function() {
19210 this.createFrame();
19213 applyConfig: function() {
19214 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19216 this.resizeFrame = (this.config.resizeFrame !== false);
19217 this.centerFrame = (this.config.centerFrame);
19218 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19222 * Resizes the drag frame to the dimensions of the clicked object, positions
19223 * it over the object, and finally displays it
19224 * @method showFrame
19225 * @param {int} iPageX X click position
19226 * @param {int} iPageY Y click position
19229 showFrame: function(iPageX, iPageY) {
19230 var el = this.getEl();
19231 var dragEl = this.getDragEl();
19232 var s = dragEl.style;
19234 this._resizeProxy();
19236 if (this.centerFrame) {
19237 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19238 Math.round(parseInt(s.height, 10)/2) );
19241 this.setDragElPos(iPageX, iPageY);
19243 Roo.fly(dragEl).show();
19247 * The proxy is automatically resized to the dimensions of the linked
19248 * element when a drag is initiated, unless resizeFrame is set to false
19249 * @method _resizeProxy
19252 _resizeProxy: function() {
19253 if (this.resizeFrame) {
19254 var el = this.getEl();
19255 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19259 // overrides Roo.dd.DragDrop
19260 b4MouseDown: function(e) {
19261 var x = e.getPageX();
19262 var y = e.getPageY();
19263 this.autoOffset(x, y);
19264 this.setDragElPos(x, y);
19267 // overrides Roo.dd.DragDrop
19268 b4StartDrag: function(x, y) {
19269 // show the drag frame
19270 this.showFrame(x, y);
19273 // overrides Roo.dd.DragDrop
19274 b4EndDrag: function(e) {
19275 Roo.fly(this.getDragEl()).hide();
19278 // overrides Roo.dd.DragDrop
19279 // By default we try to move the element to the last location of the frame.
19280 // This is so that the default behavior mirrors that of Roo.dd.DD.
19281 endDrag: function(e) {
19283 var lel = this.getEl();
19284 var del = this.getDragEl();
19286 // Show the drag frame briefly so we can get its position
19287 del.style.visibility = "";
19290 // Hide the linked element before the move to get around a Safari
19292 lel.style.visibility = "hidden";
19293 Roo.dd.DDM.moveToEl(lel, del);
19294 del.style.visibility = "hidden";
19295 lel.style.visibility = "";
19300 beforeMove : function(){
19304 afterDrag : function(){
19308 toString: function() {
19309 return ("DDProxy " + this.id);
19315 * Ext JS Library 1.1.1
19316 * Copyright(c) 2006-2007, Ext JS, LLC.
19318 * Originally Released Under LGPL - original licence link has changed is not relivant.
19321 * <script type="text/javascript">
19325 * @class Roo.dd.DDTarget
19326 * A DragDrop implementation that does not move, but can be a drop
19327 * target. You would get the same result by simply omitting implementation
19328 * for the event callbacks, but this way we reduce the processing cost of the
19329 * event listener and the callbacks.
19330 * @extends Roo.dd.DragDrop
19332 * @param {String} id the id of the element that is a drop target
19333 * @param {String} sGroup the group of related DragDrop objects
19334 * @param {object} config an object containing configurable attributes
19335 * Valid properties for DDTarget in addition to those in
19339 Roo.dd.DDTarget = function(id, sGroup, config) {
19341 this.initTarget(id, sGroup, config);
19343 if (config.listeners || config.events) {
19344 Roo.dd.DragDrop.superclass.constructor.call(this, {
19345 listeners : config.listeners || {},
19346 events : config.events || {}
19351 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19352 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19353 toString: function() {
19354 return ("DDTarget " + this.id);
19359 * Ext JS Library 1.1.1
19360 * Copyright(c) 2006-2007, Ext JS, LLC.
19362 * Originally Released Under LGPL - original licence link has changed is not relivant.
19365 * <script type="text/javascript">
19370 * @class Roo.dd.ScrollManager
19371 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19372 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19375 Roo.dd.ScrollManager = function(){
19376 var ddm = Roo.dd.DragDropMgr;
19383 var onStop = function(e){
19388 var triggerRefresh = function(){
19389 if(ddm.dragCurrent){
19390 ddm.refreshCache(ddm.dragCurrent.groups);
19394 var doScroll = function(){
19395 if(ddm.dragCurrent){
19396 var dds = Roo.dd.ScrollManager;
19398 if(proc.el.scroll(proc.dir, dds.increment)){
19402 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19407 var clearProc = function(){
19409 clearInterval(proc.id);
19416 var startProc = function(el, dir){
19417 Roo.log('scroll startproc');
19421 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19424 var onFire = function(e, isDrop){
19426 if(isDrop || !ddm.dragCurrent){ return; }
19427 var dds = Roo.dd.ScrollManager;
19428 if(!dragEl || dragEl != ddm.dragCurrent){
19429 dragEl = ddm.dragCurrent;
19430 // refresh regions on drag start
19431 dds.refreshCache();
19434 var xy = Roo.lib.Event.getXY(e);
19435 var pt = new Roo.lib.Point(xy[0], xy[1]);
19436 for(var id in els){
19437 var el = els[id], r = el._region;
19438 if(r && r.contains(pt) && el.isScrollable()){
19439 if(r.bottom - pt.y <= dds.thresh){
19441 startProc(el, "down");
19444 }else if(r.right - pt.x <= dds.thresh){
19446 startProc(el, "left");
19449 }else if(pt.y - r.top <= dds.thresh){
19451 startProc(el, "up");
19454 }else if(pt.x - r.left <= dds.thresh){
19456 startProc(el, "right");
19465 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19466 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19470 * Registers new overflow element(s) to auto scroll
19471 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19473 register : function(el){
19474 if(el instanceof Array){
19475 for(var i = 0, len = el.length; i < len; i++) {
19476 this.register(el[i]);
19482 Roo.dd.ScrollManager.els = els;
19486 * Unregisters overflow element(s) so they are no longer scrolled
19487 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19489 unregister : function(el){
19490 if(el instanceof Array){
19491 for(var i = 0, len = el.length; i < len; i++) {
19492 this.unregister(el[i]);
19501 * The number of pixels from the edge of a container the pointer needs to be to
19502 * trigger scrolling (defaults to 25)
19508 * The number of pixels to scroll in each scroll increment (defaults to 50)
19514 * The frequency of scrolls in milliseconds (defaults to 500)
19520 * True to animate the scroll (defaults to true)
19526 * The animation duration in seconds -
19527 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19533 * Manually trigger a cache refresh.
19535 refreshCache : function(){
19536 for(var id in els){
19537 if(typeof els[id] == 'object'){ // for people extending the object prototype
19538 els[id]._region = els[id].getRegion();
19545 * Ext JS Library 1.1.1
19546 * Copyright(c) 2006-2007, Ext JS, LLC.
19548 * Originally Released Under LGPL - original licence link has changed is not relivant.
19551 * <script type="text/javascript">
19556 * @class Roo.dd.Registry
19557 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19558 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19561 Roo.dd.Registry = function(){
19564 var autoIdSeed = 0;
19566 var getId = function(el, autogen){
19567 if(typeof el == "string"){
19571 if(!id && autogen !== false){
19572 id = "roodd-" + (++autoIdSeed);
19580 * Register a drag drop element
19581 * @param {String|HTMLElement} element The id or DOM node to register
19582 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19583 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19584 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19585 * populated in the data object (if applicable):
19587 Value Description<br />
19588 --------- ------------------------------------------<br />
19589 handles Array of DOM nodes that trigger dragging<br />
19590 for the element being registered<br />
19591 isHandle True if the element passed in triggers<br />
19592 dragging itself, else false
19595 register : function(el, data){
19597 if(typeof el == "string"){
19598 el = document.getElementById(el);
19601 elements[getId(el)] = data;
19602 if(data.isHandle !== false){
19603 handles[data.ddel.id] = data;
19606 var hs = data.handles;
19607 for(var i = 0, len = hs.length; i < len; i++){
19608 handles[getId(hs[i])] = data;
19614 * Unregister a drag drop element
19615 * @param {String|HTMLElement} element The id or DOM node to unregister
19617 unregister : function(el){
19618 var id = getId(el, false);
19619 var data = elements[id];
19621 delete elements[id];
19623 var hs = data.handles;
19624 for(var i = 0, len = hs.length; i < len; i++){
19625 delete handles[getId(hs[i], false)];
19632 * Returns the handle registered for a DOM Node by id
19633 * @param {String|HTMLElement} id The DOM node or id to look up
19634 * @return {Object} handle The custom handle data
19636 getHandle : function(id){
19637 if(typeof id != "string"){ // must be element?
19640 return handles[id];
19644 * Returns the handle that is registered for the DOM node that is the target of the event
19645 * @param {Event} e The event
19646 * @return {Object} handle The custom handle data
19648 getHandleFromEvent : function(e){
19649 var t = Roo.lib.Event.getTarget(e);
19650 return t ? handles[t.id] : null;
19654 * Returns a custom data object that is registered for a DOM node by id
19655 * @param {String|HTMLElement} id The DOM node or id to look up
19656 * @return {Object} data The custom data
19658 getTarget : function(id){
19659 if(typeof id != "string"){ // must be element?
19662 return elements[id];
19666 * Returns a custom data object that is registered for the DOM node that is the target of the event
19667 * @param {Event} e The event
19668 * @return {Object} data The custom data
19670 getTargetFromEvent : function(e){
19671 var t = Roo.lib.Event.getTarget(e);
19672 return t ? elements[t.id] || handles[t.id] : null;
19677 * Ext JS Library 1.1.1
19678 * Copyright(c) 2006-2007, Ext JS, LLC.
19680 * Originally Released Under LGPL - original licence link has changed is not relivant.
19683 * <script type="text/javascript">
19688 * @class Roo.dd.StatusProxy
19689 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19690 * default drag proxy used by all Roo.dd components.
19692 * @param {Object} config
19694 Roo.dd.StatusProxy = function(config){
19695 Roo.apply(this, config);
19696 this.id = this.id || Roo.id();
19697 this.el = new Roo.Layer({
19699 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19700 {tag: "div", cls: "x-dd-drop-icon"},
19701 {tag: "div", cls: "x-dd-drag-ghost"}
19704 shadow: !config || config.shadow !== false
19706 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19707 this.dropStatus = this.dropNotAllowed;
19710 Roo.dd.StatusProxy.prototype = {
19712 * @cfg {String} dropAllowed
19713 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19715 dropAllowed : "x-dd-drop-ok",
19717 * @cfg {String} dropNotAllowed
19718 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19720 dropNotAllowed : "x-dd-drop-nodrop",
19723 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19724 * over the current target element.
19725 * @param {String} cssClass The css class for the new drop status indicator image
19727 setStatus : function(cssClass){
19728 cssClass = cssClass || this.dropNotAllowed;
19729 if(this.dropStatus != cssClass){
19730 this.el.replaceClass(this.dropStatus, cssClass);
19731 this.dropStatus = cssClass;
19736 * Resets the status indicator to the default dropNotAllowed value
19737 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19739 reset : function(clearGhost){
19740 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19741 this.dropStatus = this.dropNotAllowed;
19743 this.ghost.update("");
19748 * Updates the contents of the ghost element
19749 * @param {String} html The html that will replace the current innerHTML of the ghost element
19751 update : function(html){
19752 if(typeof html == "string"){
19753 this.ghost.update(html);
19755 this.ghost.update("");
19756 html.style.margin = "0";
19757 this.ghost.dom.appendChild(html);
19759 // ensure float = none set?? cant remember why though.
19760 var el = this.ghost.dom.firstChild;
19762 Roo.fly(el).setStyle('float', 'none');
19767 * Returns the underlying proxy {@link Roo.Layer}
19768 * @return {Roo.Layer} el
19770 getEl : function(){
19775 * Returns the ghost element
19776 * @return {Roo.Element} el
19778 getGhost : function(){
19784 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19786 hide : function(clear){
19794 * Stops the repair animation if it's currently running
19797 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19803 * Displays this proxy
19810 * Force the Layer to sync its shadow and shim positions to the element
19817 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19818 * invalid drop operation by the item being dragged.
19819 * @param {Array} xy The XY position of the element ([x, y])
19820 * @param {Function} callback The function to call after the repair is complete
19821 * @param {Object} scope The scope in which to execute the callback
19823 repair : function(xy, callback, scope){
19824 this.callback = callback;
19825 this.scope = scope;
19826 if(xy && this.animRepair !== false){
19827 this.el.addClass("x-dd-drag-repair");
19828 this.el.hideUnders(true);
19829 this.anim = this.el.shift({
19830 duration: this.repairDuration || .5,
19834 callback: this.afterRepair,
19838 this.afterRepair();
19843 afterRepair : function(){
19845 if(typeof this.callback == "function"){
19846 this.callback.call(this.scope || this);
19848 this.callback = null;
19853 * Ext JS Library 1.1.1
19854 * Copyright(c) 2006-2007, Ext JS, LLC.
19856 * Originally Released Under LGPL - original licence link has changed is not relivant.
19859 * <script type="text/javascript">
19863 * @class Roo.dd.DragSource
19864 * @extends Roo.dd.DDProxy
19865 * A simple class that provides the basic implementation needed to make any element draggable.
19867 * @param {String/HTMLElement/Element} el The container element
19868 * @param {Object} config
19870 Roo.dd.DragSource = function(el, config){
19871 this.el = Roo.get(el);
19872 this.dragData = {};
19874 Roo.apply(this, config);
19877 this.proxy = new Roo.dd.StatusProxy();
19880 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19881 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19883 this.dragging = false;
19886 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19888 * @cfg {String} dropAllowed
19889 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19891 dropAllowed : "x-dd-drop-ok",
19893 * @cfg {String} dropNotAllowed
19894 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19896 dropNotAllowed : "x-dd-drop-nodrop",
19899 * Returns the data object associated with this drag source
19900 * @return {Object} data An object containing arbitrary data
19902 getDragData : function(e){
19903 return this.dragData;
19907 onDragEnter : function(e, id){
19908 var target = Roo.dd.DragDropMgr.getDDById(id);
19909 this.cachedTarget = target;
19910 if(this.beforeDragEnter(target, e, id) !== false){
19911 if(target.isNotifyTarget){
19912 var status = target.notifyEnter(this, e, this.dragData);
19913 this.proxy.setStatus(status);
19915 this.proxy.setStatus(this.dropAllowed);
19918 if(this.afterDragEnter){
19920 * An empty function by default, but provided so that you can perform a custom action
19921 * when the dragged item enters the drop target by providing an implementation.
19922 * @param {Roo.dd.DragDrop} target The drop target
19923 * @param {Event} e The event object
19924 * @param {String} id The id of the dragged element
19925 * @method afterDragEnter
19927 this.afterDragEnter(target, e, id);
19933 * An empty function by default, but provided so that you can perform a custom action
19934 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19935 * @param {Roo.dd.DragDrop} target The drop target
19936 * @param {Event} e The event object
19937 * @param {String} id The id of the dragged element
19938 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19940 beforeDragEnter : function(target, e, id){
19945 alignElWithMouse: function() {
19946 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19951 onDragOver : function(e, id){
19952 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19953 if(this.beforeDragOver(target, e, id) !== false){
19954 if(target.isNotifyTarget){
19955 var status = target.notifyOver(this, e, this.dragData);
19956 this.proxy.setStatus(status);
19959 if(this.afterDragOver){
19961 * An empty function by default, but provided so that you can perform a custom action
19962 * while the dragged item is over the drop target by providing an implementation.
19963 * @param {Roo.dd.DragDrop} target The drop target
19964 * @param {Event} e The event object
19965 * @param {String} id The id of the dragged element
19966 * @method afterDragOver
19968 this.afterDragOver(target, e, id);
19974 * An empty function by default, but provided so that you can perform a custom action
19975 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19976 * @param {Roo.dd.DragDrop} target The drop target
19977 * @param {Event} e The event object
19978 * @param {String} id The id of the dragged element
19979 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19981 beforeDragOver : function(target, e, id){
19986 onDragOut : function(e, id){
19987 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19988 if(this.beforeDragOut(target, e, id) !== false){
19989 if(target.isNotifyTarget){
19990 target.notifyOut(this, e, this.dragData);
19992 this.proxy.reset();
19993 if(this.afterDragOut){
19995 * An empty function by default, but provided so that you can perform a custom action
19996 * after the dragged item is dragged out of the target without dropping.
19997 * @param {Roo.dd.DragDrop} target The drop target
19998 * @param {Event} e The event object
19999 * @param {String} id The id of the dragged element
20000 * @method afterDragOut
20002 this.afterDragOut(target, e, id);
20005 this.cachedTarget = null;
20009 * An empty function by default, but provided so that you can perform a custom action before the dragged
20010 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20011 * @param {Roo.dd.DragDrop} target The drop target
20012 * @param {Event} e The event object
20013 * @param {String} id The id of the dragged element
20014 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20016 beforeDragOut : function(target, e, id){
20021 onDragDrop : function(e, id){
20022 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20023 if(this.beforeDragDrop(target, e, id) !== false){
20024 if(target.isNotifyTarget){
20025 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20026 this.onValidDrop(target, e, id);
20028 this.onInvalidDrop(target, e, id);
20031 this.onValidDrop(target, e, id);
20034 if(this.afterDragDrop){
20036 * An empty function by default, but provided so that you can perform a custom action
20037 * after a valid drag drop has occurred by providing an implementation.
20038 * @param {Roo.dd.DragDrop} target The drop target
20039 * @param {Event} e The event object
20040 * @param {String} id The id of the dropped element
20041 * @method afterDragDrop
20043 this.afterDragDrop(target, e, id);
20046 delete this.cachedTarget;
20050 * An empty function by default, but provided so that you can perform a custom action before the dragged
20051 * item is dropped onto the target and optionally cancel the onDragDrop.
20052 * @param {Roo.dd.DragDrop} target The drop target
20053 * @param {Event} e The event object
20054 * @param {String} id The id of the dragged element
20055 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20057 beforeDragDrop : function(target, e, id){
20062 onValidDrop : function(target, e, id){
20064 if(this.afterValidDrop){
20066 * An empty function by default, but provided so that you can perform a custom action
20067 * after a valid drop has occurred by providing an implementation.
20068 * @param {Object} target The target DD
20069 * @param {Event} e The event object
20070 * @param {String} id The id of the dropped element
20071 * @method afterInvalidDrop
20073 this.afterValidDrop(target, e, id);
20078 getRepairXY : function(e, data){
20079 return this.el.getXY();
20083 onInvalidDrop : function(target, e, id){
20084 this.beforeInvalidDrop(target, e, id);
20085 if(this.cachedTarget){
20086 if(this.cachedTarget.isNotifyTarget){
20087 this.cachedTarget.notifyOut(this, e, this.dragData);
20089 this.cacheTarget = null;
20091 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20093 if(this.afterInvalidDrop){
20095 * An empty function by default, but provided so that you can perform a custom action
20096 * after an invalid drop has occurred by providing an implementation.
20097 * @param {Event} e The event object
20098 * @param {String} id The id of the dropped element
20099 * @method afterInvalidDrop
20101 this.afterInvalidDrop(e, id);
20106 afterRepair : function(){
20108 this.el.highlight(this.hlColor || "c3daf9");
20110 this.dragging = false;
20114 * An empty function by default, but provided so that you can perform a custom action after an invalid
20115 * drop has occurred.
20116 * @param {Roo.dd.DragDrop} target The drop target
20117 * @param {Event} e The event object
20118 * @param {String} id The id of the dragged element
20119 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20121 beforeInvalidDrop : function(target, e, id){
20126 handleMouseDown : function(e){
20127 if(this.dragging) {
20130 var data = this.getDragData(e);
20131 if(data && this.onBeforeDrag(data, e) !== false){
20132 this.dragData = data;
20134 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20139 * An empty function by default, but provided so that you can perform a custom action before the initial
20140 * drag event begins and optionally cancel it.
20141 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20142 * @param {Event} e The event object
20143 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20145 onBeforeDrag : function(data, e){
20150 * An empty function by default, but provided so that you can perform a custom action once the initial
20151 * drag event has begun. The drag cannot be canceled from this function.
20152 * @param {Number} x The x position of the click on the dragged object
20153 * @param {Number} y The y position of the click on the dragged object
20155 onStartDrag : Roo.emptyFn,
20157 // private - YUI override
20158 startDrag : function(x, y){
20159 this.proxy.reset();
20160 this.dragging = true;
20161 this.proxy.update("");
20162 this.onInitDrag(x, y);
20167 onInitDrag : function(x, y){
20168 var clone = this.el.dom.cloneNode(true);
20169 clone.id = Roo.id(); // prevent duplicate ids
20170 this.proxy.update(clone);
20171 this.onStartDrag(x, y);
20176 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20177 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20179 getProxy : function(){
20184 * Hides the drag source's {@link Roo.dd.StatusProxy}
20186 hideProxy : function(){
20188 this.proxy.reset(true);
20189 this.dragging = false;
20193 triggerCacheRefresh : function(){
20194 Roo.dd.DDM.refreshCache(this.groups);
20197 // private - override to prevent hiding
20198 b4EndDrag: function(e) {
20201 // private - override to prevent moving
20202 endDrag : function(e){
20203 this.onEndDrag(this.dragData, e);
20207 onEndDrag : function(data, e){
20210 // private - pin to cursor
20211 autoOffset : function(x, y) {
20212 this.setDelta(-12, -20);
20216 * Ext JS Library 1.1.1
20217 * Copyright(c) 2006-2007, Ext JS, LLC.
20219 * Originally Released Under LGPL - original licence link has changed is not relivant.
20222 * <script type="text/javascript">
20227 * @class Roo.dd.DropTarget
20228 * @extends Roo.dd.DDTarget
20229 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20230 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20232 * @param {String/HTMLElement/Element} el The container element
20233 * @param {Object} config
20235 Roo.dd.DropTarget = function(el, config){
20236 this.el = Roo.get(el);
20238 var listeners = false; ;
20239 if (config && config.listeners) {
20240 listeners= config.listeners;
20241 delete config.listeners;
20243 Roo.apply(this, config);
20245 if(this.containerScroll){
20246 Roo.dd.ScrollManager.register(this.el);
20250 * @scope Roo.dd.DropTarget
20255 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20256 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20257 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20259 * IMPORTANT : it should set this.overClass and this.dropAllowed
20261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20262 * @param {Event} e The event
20263 * @param {Object} data An object containing arbitrary data supplied by the drag source
20269 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20270 * This method will be called on every mouse movement while the drag source is over the drop target.
20271 * This default implementation simply returns the dropAllowed config value.
20273 * IMPORTANT : it should set this.dropAllowed
20275 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20276 * @param {Event} e The event
20277 * @param {Object} data An object containing arbitrary data supplied by the drag source
20283 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20284 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20285 * overClass (if any) from the drop element.
20287 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20288 * @param {Event} e The event
20289 * @param {Object} data An object containing arbitrary data supplied by the drag source
20295 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20296 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20297 * implementation that does something to process the drop event and returns true so that the drag source's
20298 * repair action does not run.
20300 * IMPORTANT : it should set this.success
20302 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20303 * @param {Event} e The event
20304 * @param {Object} data An object containing arbitrary data supplied by the drag source
20310 Roo.dd.DropTarget.superclass.constructor.call( this,
20312 this.ddGroup || this.group,
20315 listeners : listeners || {}
20323 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20325 * @cfg {String} overClass
20326 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20329 * @cfg {String} ddGroup
20330 * The drag drop group to handle drop events for
20334 * @cfg {String} dropAllowed
20335 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20337 dropAllowed : "x-dd-drop-ok",
20339 * @cfg {String} dropNotAllowed
20340 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20342 dropNotAllowed : "x-dd-drop-nodrop",
20344 * @cfg {boolean} success
20345 * set this after drop listener..
20349 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20350 * if the drop point is valid for over/enter..
20357 isNotifyTarget : true,
20362 notifyEnter : function(dd, e, data)
20365 this.fireEvent('enter', dd, e, data);
20366 if(this.overClass){
20367 this.el.addClass(this.overClass);
20369 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20370 this.valid ? this.dropAllowed : this.dropNotAllowed
20377 notifyOver : function(dd, e, data)
20380 this.fireEvent('over', dd, e, data);
20381 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20382 this.valid ? this.dropAllowed : this.dropNotAllowed
20389 notifyOut : function(dd, e, data)
20391 this.fireEvent('out', dd, e, data);
20392 if(this.overClass){
20393 this.el.removeClass(this.overClass);
20400 notifyDrop : function(dd, e, data)
20402 this.success = false;
20403 this.fireEvent('drop', dd, e, data);
20404 return this.success;
20408 * Ext JS Library 1.1.1
20409 * Copyright(c) 2006-2007, Ext JS, LLC.
20411 * Originally Released Under LGPL - original licence link has changed is not relivant.
20414 * <script type="text/javascript">
20419 * @class Roo.dd.DragZone
20420 * @extends Roo.dd.DragSource
20421 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20422 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20424 * @param {String/HTMLElement/Element} el The container element
20425 * @param {Object} config
20427 Roo.dd.DragZone = function(el, config){
20428 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20429 if(this.containerScroll){
20430 Roo.dd.ScrollManager.register(this.el);
20434 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20436 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20437 * for auto scrolling during drag operations.
20440 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20441 * method after a failed drop (defaults to "c3daf9" - light blue)
20445 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20446 * for a valid target to drag based on the mouse down. Override this method
20447 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20448 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20449 * @param {EventObject} e The mouse down event
20450 * @return {Object} The dragData
20452 getDragData : function(e){
20453 return Roo.dd.Registry.getHandleFromEvent(e);
20457 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20458 * this.dragData.ddel
20459 * @param {Number} x The x position of the click on the dragged object
20460 * @param {Number} y The y position of the click on the dragged object
20461 * @return {Boolean} true to continue the drag, false to cancel
20463 onInitDrag : function(x, y){
20464 this.proxy.update(this.dragData.ddel.cloneNode(true));
20465 this.onStartDrag(x, y);
20470 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20472 afterRepair : function(){
20474 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20476 this.dragging = false;
20480 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20481 * the XY of this.dragData.ddel
20482 * @param {EventObject} e The mouse up event
20483 * @return {Array} The xy location (e.g. [100, 200])
20485 getRepairXY : function(e){
20486 return Roo.Element.fly(this.dragData.ddel).getXY();
20490 * Ext JS Library 1.1.1
20491 * Copyright(c) 2006-2007, Ext JS, LLC.
20493 * Originally Released Under LGPL - original licence link has changed is not relivant.
20496 * <script type="text/javascript">
20499 * @class Roo.dd.DropZone
20500 * @extends Roo.dd.DropTarget
20501 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20502 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20504 * @param {String/HTMLElement/Element} el The container element
20505 * @param {Object} config
20507 Roo.dd.DropZone = function(el, config){
20508 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20511 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20513 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20514 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20515 * provide your own custom lookup.
20516 * @param {Event} e The event
20517 * @return {Object} data The custom data
20519 getTargetFromEvent : function(e){
20520 return Roo.dd.Registry.getTargetFromEvent(e);
20524 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20525 * that it has registered. This method has no default implementation and should be overridden to provide
20526 * node-specific processing if necessary.
20527 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20528 * {@link #getTargetFromEvent} for this node)
20529 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20530 * @param {Event} e The event
20531 * @param {Object} data An object containing arbitrary data supplied by the drag source
20533 onNodeEnter : function(n, dd, e, data){
20538 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20539 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20540 * overridden to provide the proper feedback.
20541 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20542 * {@link #getTargetFromEvent} for this node)
20543 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20544 * @param {Event} e The event
20545 * @param {Object} data An object containing arbitrary data supplied by the drag source
20546 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20547 * underlying {@link Roo.dd.StatusProxy} can be updated
20549 onNodeOver : function(n, dd, e, data){
20550 return this.dropAllowed;
20554 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20555 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20556 * node-specific processing if necessary.
20557 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20558 * {@link #getTargetFromEvent} for this node)
20559 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20560 * @param {Event} e The event
20561 * @param {Object} data An object containing arbitrary data supplied by the drag source
20563 onNodeOut : function(n, dd, e, data){
20568 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20569 * the drop node. The default implementation returns false, so it should be overridden to provide the
20570 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20571 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20572 * {@link #getTargetFromEvent} for this node)
20573 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20574 * @param {Event} e The event
20575 * @param {Object} data An object containing arbitrary data supplied by the drag source
20576 * @return {Boolean} True if the drop was valid, else false
20578 onNodeDrop : function(n, dd, e, data){
20583 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20584 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20585 * it should be overridden to provide the proper feedback if necessary.
20586 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20587 * @param {Event} e The event
20588 * @param {Object} data An object containing arbitrary data supplied by the drag source
20589 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20590 * underlying {@link Roo.dd.StatusProxy} can be updated
20592 onContainerOver : function(dd, e, data){
20593 return this.dropNotAllowed;
20597 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20598 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20599 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20600 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20601 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20602 * @param {Event} e The event
20603 * @param {Object} data An object containing arbitrary data supplied by the drag source
20604 * @return {Boolean} True if the drop was valid, else false
20606 onContainerDrop : function(dd, e, data){
20611 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20612 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20613 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20614 * you should override this method and provide a custom implementation.
20615 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20616 * @param {Event} e The event
20617 * @param {Object} data An object containing arbitrary data supplied by the drag source
20618 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20619 * underlying {@link Roo.dd.StatusProxy} can be updated
20621 notifyEnter : function(dd, e, data){
20622 return this.dropNotAllowed;
20626 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20627 * This method will be called on every mouse movement while the drag source is over the drop zone.
20628 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20629 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20630 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20631 * registered node, it will call {@link #onContainerOver}.
20632 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20633 * @param {Event} e The event
20634 * @param {Object} data An object containing arbitrary data supplied by the drag source
20635 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20636 * underlying {@link Roo.dd.StatusProxy} can be updated
20638 notifyOver : function(dd, e, data){
20639 var n = this.getTargetFromEvent(e);
20640 if(!n){ // not over valid drop target
20641 if(this.lastOverNode){
20642 this.onNodeOut(this.lastOverNode, dd, e, data);
20643 this.lastOverNode = null;
20645 return this.onContainerOver(dd, e, data);
20647 if(this.lastOverNode != n){
20648 if(this.lastOverNode){
20649 this.onNodeOut(this.lastOverNode, dd, e, data);
20651 this.onNodeEnter(n, dd, e, data);
20652 this.lastOverNode = n;
20654 return this.onNodeOver(n, dd, e, data);
20658 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20659 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20660 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20661 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20662 * @param {Event} e The event
20663 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20665 notifyOut : function(dd, e, data){
20666 if(this.lastOverNode){
20667 this.onNodeOut(this.lastOverNode, dd, e, data);
20668 this.lastOverNode = null;
20673 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20674 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20675 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20676 * otherwise it will call {@link #onContainerDrop}.
20677 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20678 * @param {Event} e The event
20679 * @param {Object} data An object containing arbitrary data supplied by the drag source
20680 * @return {Boolean} True if the drop was valid, else false
20682 notifyDrop : function(dd, e, data){
20683 if(this.lastOverNode){
20684 this.onNodeOut(this.lastOverNode, dd, e, data);
20685 this.lastOverNode = null;
20687 var n = this.getTargetFromEvent(e);
20689 this.onNodeDrop(n, dd, e, data) :
20690 this.onContainerDrop(dd, e, data);
20694 triggerCacheRefresh : function(){
20695 Roo.dd.DDM.refreshCache(this.groups);
20699 * Ext JS Library 1.1.1
20700 * Copyright(c) 2006-2007, Ext JS, LLC.
20702 * Originally Released Under LGPL - original licence link has changed is not relivant.
20705 * <script type="text/javascript">
20710 * @class Roo.data.SortTypes
20712 * Defines the default sorting (casting?) comparison functions used when sorting data.
20714 Roo.data.SortTypes = {
20716 * Default sort that does nothing
20717 * @param {Mixed} s The value being converted
20718 * @return {Mixed} The comparison value
20720 none : function(s){
20725 * The regular expression used to strip tags
20729 stripTagsRE : /<\/?[^>]+>/gi,
20732 * Strips all HTML tags to sort on text only
20733 * @param {Mixed} s The value being converted
20734 * @return {String} The comparison value
20736 asText : function(s){
20737 return String(s).replace(this.stripTagsRE, "");
20741 * Strips all HTML tags to sort on text only - Case insensitive
20742 * @param {Mixed} s The value being converted
20743 * @return {String} The comparison value
20745 asUCText : function(s){
20746 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20750 * Case insensitive string
20751 * @param {Mixed} s The value being converted
20752 * @return {String} The comparison value
20754 asUCString : function(s) {
20755 return String(s).toUpperCase();
20760 * @param {Mixed} s The value being converted
20761 * @return {Number} The comparison value
20763 asDate : function(s) {
20767 if(s instanceof Date){
20768 return s.getTime();
20770 return Date.parse(String(s));
20775 * @param {Mixed} s The value being converted
20776 * @return {Float} The comparison value
20778 asFloat : function(s) {
20779 var val = parseFloat(String(s).replace(/,/g, ""));
20780 if(isNaN(val)) val = 0;
20786 * @param {Mixed} s The value being converted
20787 * @return {Number} The comparison value
20789 asInt : function(s) {
20790 var val = parseInt(String(s).replace(/,/g, ""));
20791 if(isNaN(val)) val = 0;
20796 * Ext JS Library 1.1.1
20797 * Copyright(c) 2006-2007, Ext JS, LLC.
20799 * Originally Released Under LGPL - original licence link has changed is not relivant.
20802 * <script type="text/javascript">
20806 * @class Roo.data.Record
20807 * Instances of this class encapsulate both record <em>definition</em> information, and record
20808 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20809 * to access Records cached in an {@link Roo.data.Store} object.<br>
20811 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20812 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20815 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20817 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20818 * {@link #create}. The parameters are the same.
20819 * @param {Array} data An associative Array of data values keyed by the field name.
20820 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20821 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20822 * not specified an integer id is generated.
20824 Roo.data.Record = function(data, id){
20825 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20830 * Generate a constructor for a specific record layout.
20831 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20832 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20833 * Each field definition object may contain the following properties: <ul>
20834 * <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,
20835 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20836 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20837 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20838 * is being used, then this is a string containing the javascript expression to reference the data relative to
20839 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20840 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20841 * this may be omitted.</p></li>
20842 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20843 * <ul><li>auto (Default, implies no conversion)</li>
20848 * <li>date</li></ul></p></li>
20849 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20850 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20851 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20852 * by the Reader into an object that will be stored in the Record. It is passed the
20853 * following parameters:<ul>
20854 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20856 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20858 * <br>usage:<br><pre><code>
20859 var TopicRecord = Roo.data.Record.create(
20860 {name: 'title', mapping: 'topic_title'},
20861 {name: 'author', mapping: 'username'},
20862 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20863 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20864 {name: 'lastPoster', mapping: 'user2'},
20865 {name: 'excerpt', mapping: 'post_text'}
20868 var myNewRecord = new TopicRecord({
20869 title: 'Do my job please',
20872 lastPost: new Date(),
20873 lastPoster: 'Animal',
20874 excerpt: 'No way dude!'
20876 myStore.add(myNewRecord);
20881 Roo.data.Record.create = function(o){
20882 var f = function(){
20883 f.superclass.constructor.apply(this, arguments);
20885 Roo.extend(f, Roo.data.Record);
20886 var p = f.prototype;
20887 p.fields = new Roo.util.MixedCollection(false, function(field){
20890 for(var i = 0, len = o.length; i < len; i++){
20891 p.fields.add(new Roo.data.Field(o[i]));
20893 f.getField = function(name){
20894 return p.fields.get(name);
20899 Roo.data.Record.AUTO_ID = 1000;
20900 Roo.data.Record.EDIT = 'edit';
20901 Roo.data.Record.REJECT = 'reject';
20902 Roo.data.Record.COMMIT = 'commit';
20904 Roo.data.Record.prototype = {
20906 * Readonly flag - true if this record has been modified.
20915 join : function(store){
20916 this.store = store;
20920 * Set the named field to the specified value.
20921 * @param {String} name The name of the field to set.
20922 * @param {Object} value The value to set the field to.
20924 set : function(name, value){
20925 if(this.data[name] == value){
20929 if(!this.modified){
20930 this.modified = {};
20932 if(typeof this.modified[name] == 'undefined'){
20933 this.modified[name] = this.data[name];
20935 this.data[name] = value;
20936 if(!this.editing && this.store){
20937 this.store.afterEdit(this);
20942 * Get the value of the named field.
20943 * @param {String} name The name of the field to get the value of.
20944 * @return {Object} The value of the field.
20946 get : function(name){
20947 return this.data[name];
20951 beginEdit : function(){
20952 this.editing = true;
20953 this.modified = {};
20957 cancelEdit : function(){
20958 this.editing = false;
20959 delete this.modified;
20963 endEdit : function(){
20964 this.editing = false;
20965 if(this.dirty && this.store){
20966 this.store.afterEdit(this);
20971 * Usually called by the {@link Roo.data.Store} which owns the Record.
20972 * Rejects all changes made to the Record since either creation, or the last commit operation.
20973 * Modified fields are reverted to their original values.
20975 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20976 * of reject operations.
20978 reject : function(){
20979 var m = this.modified;
20981 if(typeof m[n] != "function"){
20982 this.data[n] = m[n];
20985 this.dirty = false;
20986 delete this.modified;
20987 this.editing = false;
20989 this.store.afterReject(this);
20994 * Usually called by the {@link Roo.data.Store} which owns the Record.
20995 * Commits all changes made to the Record since either creation, or the last commit operation.
20997 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20998 * of commit operations.
21000 commit : function(){
21001 this.dirty = false;
21002 delete this.modified;
21003 this.editing = false;
21005 this.store.afterCommit(this);
21010 hasError : function(){
21011 return this.error != null;
21015 clearError : function(){
21020 * Creates a copy of this record.
21021 * @param {String} id (optional) A new record id if you don't want to use this record's id
21024 copy : function(newId) {
21025 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21029 * Ext JS Library 1.1.1
21030 * Copyright(c) 2006-2007, Ext JS, LLC.
21032 * Originally Released Under LGPL - original licence link has changed is not relivant.
21035 * <script type="text/javascript">
21041 * @class Roo.data.Store
21042 * @extends Roo.util.Observable
21043 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21044 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21046 * 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
21047 * has no knowledge of the format of the data returned by the Proxy.<br>
21049 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21050 * instances from the data object. These records are cached and made available through accessor functions.
21052 * Creates a new Store.
21053 * @param {Object} config A config object containing the objects needed for the Store to access data,
21054 * and read the data into Records.
21056 Roo.data.Store = function(config){
21057 this.data = new Roo.util.MixedCollection(false);
21058 this.data.getKey = function(o){
21061 this.baseParams = {};
21063 this.paramNames = {
21068 "multisort" : "_multisort"
21071 if(config && config.data){
21072 this.inlineData = config.data;
21073 delete config.data;
21076 Roo.apply(this, config);
21078 if(this.reader){ // reader passed
21079 this.reader = Roo.factory(this.reader, Roo.data);
21080 this.reader.xmodule = this.xmodule || false;
21081 if(!this.recordType){
21082 this.recordType = this.reader.recordType;
21084 if(this.reader.onMetaChange){
21085 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21089 if(this.recordType){
21090 this.fields = this.recordType.prototype.fields;
21092 this.modified = [];
21096 * @event datachanged
21097 * Fires when the data cache has changed, and a widget which is using this Store
21098 * as a Record cache should refresh its view.
21099 * @param {Store} this
21101 datachanged : true,
21103 * @event metachange
21104 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21105 * @param {Store} this
21106 * @param {Object} meta The JSON metadata
21111 * Fires when Records have been added to the Store
21112 * @param {Store} this
21113 * @param {Roo.data.Record[]} records The array of Records added
21114 * @param {Number} index The index at which the record(s) were added
21119 * Fires when a Record has been removed from the Store
21120 * @param {Store} this
21121 * @param {Roo.data.Record} record The Record that was removed
21122 * @param {Number} index The index at which the record was removed
21127 * Fires when a Record has been updated
21128 * @param {Store} this
21129 * @param {Roo.data.Record} record The Record that was updated
21130 * @param {String} operation The update operation being performed. Value may be one of:
21132 Roo.data.Record.EDIT
21133 Roo.data.Record.REJECT
21134 Roo.data.Record.COMMIT
21140 * Fires when the data cache has been cleared.
21141 * @param {Store} this
21145 * @event beforeload
21146 * Fires before a request is made for a new data object. If the beforeload handler returns false
21147 * the load action will be canceled.
21148 * @param {Store} this
21149 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21153 * @event beforeloadadd
21154 * Fires after a new set of Records has been loaded.
21155 * @param {Store} this
21156 * @param {Roo.data.Record[]} records The Records that were loaded
21157 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21159 beforeloadadd : true,
21162 * Fires after a new set of Records has been loaded, before they are added to the store.
21163 * @param {Store} this
21164 * @param {Roo.data.Record[]} records The Records that were loaded
21165 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21166 * @params {Object} return from reader
21170 * @event loadexception
21171 * Fires if an exception occurs in the Proxy during loading.
21172 * Called with the signature of the Proxy's "loadexception" event.
21173 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21176 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21177 * @param {Object} load options
21178 * @param {Object} jsonData from your request (normally this contains the Exception)
21180 loadexception : true
21184 this.proxy = Roo.factory(this.proxy, Roo.data);
21185 this.proxy.xmodule = this.xmodule || false;
21186 this.relayEvents(this.proxy, ["loadexception"]);
21188 this.sortToggle = {};
21189 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21191 Roo.data.Store.superclass.constructor.call(this);
21193 if(this.inlineData){
21194 this.loadData(this.inlineData);
21195 delete this.inlineData;
21199 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21201 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21202 * without a remote query - used by combo/forms at present.
21206 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21209 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21212 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21213 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21216 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21217 * on any HTTP request
21220 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21223 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21227 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21228 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21230 remoteSort : false,
21233 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21234 * loaded or when a record is removed. (defaults to false).
21236 pruneModifiedRecords : false,
21239 lastOptions : null,
21242 * Add Records to the Store and fires the add event.
21243 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21245 add : function(records){
21246 records = [].concat(records);
21247 for(var i = 0, len = records.length; i < len; i++){
21248 records[i].join(this);
21250 var index = this.data.length;
21251 this.data.addAll(records);
21252 this.fireEvent("add", this, records, index);
21256 * Remove a Record from the Store and fires the remove event.
21257 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21259 remove : function(record){
21260 var index = this.data.indexOf(record);
21261 this.data.removeAt(index);
21262 if(this.pruneModifiedRecords){
21263 this.modified.remove(record);
21265 this.fireEvent("remove", this, record, index);
21269 * Remove all Records from the Store and fires the clear event.
21271 removeAll : function(){
21273 if(this.pruneModifiedRecords){
21274 this.modified = [];
21276 this.fireEvent("clear", this);
21280 * Inserts Records to the Store at the given index and fires the add event.
21281 * @param {Number} index The start index at which to insert the passed Records.
21282 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21284 insert : function(index, records){
21285 records = [].concat(records);
21286 for(var i = 0, len = records.length; i < len; i++){
21287 this.data.insert(index, records[i]);
21288 records[i].join(this);
21290 this.fireEvent("add", this, records, index);
21294 * Get the index within the cache of the passed Record.
21295 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21296 * @return {Number} The index of the passed Record. Returns -1 if not found.
21298 indexOf : function(record){
21299 return this.data.indexOf(record);
21303 * Get the index within the cache of the Record with the passed id.
21304 * @param {String} id The id of the Record to find.
21305 * @return {Number} The index of the Record. Returns -1 if not found.
21307 indexOfId : function(id){
21308 return this.data.indexOfKey(id);
21312 * Get the Record with the specified id.
21313 * @param {String} id The id of the Record to find.
21314 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21316 getById : function(id){
21317 return this.data.key(id);
21321 * Get the Record at the specified index.
21322 * @param {Number} index The index of the Record to find.
21323 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21325 getAt : function(index){
21326 return this.data.itemAt(index);
21330 * Returns a range of Records between specified indices.
21331 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21332 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21333 * @return {Roo.data.Record[]} An array of Records
21335 getRange : function(start, end){
21336 return this.data.getRange(start, end);
21340 storeOptions : function(o){
21341 o = Roo.apply({}, o);
21344 this.lastOptions = o;
21348 * Loads the Record cache from the configured Proxy using the configured Reader.
21350 * If using remote paging, then the first load call must specify the <em>start</em>
21351 * and <em>limit</em> properties in the options.params property to establish the initial
21352 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21354 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21355 * and this call will return before the new data has been loaded. Perform any post-processing
21356 * in a callback function, or in a "load" event handler.</strong>
21358 * @param {Object} options An object containing properties which control loading options:<ul>
21359 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21360 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21361 * passed the following arguments:<ul>
21362 * <li>r : Roo.data.Record[]</li>
21363 * <li>options: Options object from the load call</li>
21364 * <li>success: Boolean success indicator</li></ul></li>
21365 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21366 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21369 load : function(options){
21370 options = options || {};
21371 if(this.fireEvent("beforeload", this, options) !== false){
21372 this.storeOptions(options);
21373 var p = Roo.apply(options.params || {}, this.baseParams);
21374 // if meta was not loaded from remote source.. try requesting it.
21375 if (!this.reader.metaFromRemote) {
21376 p._requestMeta = 1;
21378 if(this.sortInfo && this.remoteSort){
21379 var pn = this.paramNames;
21380 p[pn["sort"]] = this.sortInfo.field;
21381 p[pn["dir"]] = this.sortInfo.direction;
21383 if (this.multiSort) {
21384 var pn = this.paramNames;
21385 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21388 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21393 * Reloads the Record cache from the configured Proxy using the configured Reader and
21394 * the options from the last load operation performed.
21395 * @param {Object} options (optional) An object containing properties which may override the options
21396 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21397 * the most recently used options are reused).
21399 reload : function(options){
21400 this.load(Roo.applyIf(options||{}, this.lastOptions));
21404 // Called as a callback by the Reader during a load operation.
21405 loadRecords : function(o, options, success){
21406 if(!o || success === false){
21407 if(success !== false){
21408 this.fireEvent("load", this, [], options, o);
21410 if(options.callback){
21411 options.callback.call(options.scope || this, [], options, false);
21415 // if data returned failure - throw an exception.
21416 if (o.success === false) {
21417 // show a message if no listener is registered.
21418 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21419 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21421 // loadmask wil be hooked into this..
21422 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21425 var r = o.records, t = o.totalRecords || r.length;
21427 this.fireEvent("beforeloadadd", this, r, options, o);
21429 if(!options || options.add !== true){
21430 if(this.pruneModifiedRecords){
21431 this.modified = [];
21433 for(var i = 0, len = r.length; i < len; i++){
21437 this.data = this.snapshot;
21438 delete this.snapshot;
21441 this.data.addAll(r);
21442 this.totalLength = t;
21444 this.fireEvent("datachanged", this);
21446 this.totalLength = Math.max(t, this.data.length+r.length);
21449 this.fireEvent("load", this, r, options, o);
21450 if(options.callback){
21451 options.callback.call(options.scope || this, r, options, true);
21457 * Loads data from a passed data block. A Reader which understands the format of the data
21458 * must have been configured in the constructor.
21459 * @param {Object} data The data block from which to read the Records. The format of the data expected
21460 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21461 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21463 loadData : function(o, append){
21464 var r = this.reader.readRecords(o);
21465 this.loadRecords(r, {add: append}, true);
21469 * Gets the number of cached records.
21471 * <em>If using paging, this may not be the total size of the dataset. If the data object
21472 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21473 * the data set size</em>
21475 getCount : function(){
21476 return this.data.length || 0;
21480 * Gets the total number of records in the dataset as returned by the server.
21482 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21483 * the dataset size</em>
21485 getTotalCount : function(){
21486 return this.totalLength || 0;
21490 * Returns the sort state of the Store as an object with two properties:
21492 field {String} The name of the field by which the Records are sorted
21493 direction {String} The sort order, "ASC" or "DESC"
21496 getSortState : function(){
21497 return this.sortInfo;
21501 applySort : function(){
21502 if(this.sortInfo && !this.remoteSort){
21503 var s = this.sortInfo, f = s.field;
21504 var st = this.fields.get(f).sortType;
21505 var fn = function(r1, r2){
21506 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21507 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21509 this.data.sort(s.direction, fn);
21510 if(this.snapshot && this.snapshot != this.data){
21511 this.snapshot.sort(s.direction, fn);
21517 * Sets the default sort column and order to be used by the next load operation.
21518 * @param {String} fieldName The name of the field to sort by.
21519 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21521 setDefaultSort : function(field, dir){
21522 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21526 * Sort the Records.
21527 * If remote sorting is used, the sort is performed on the server, and the cache is
21528 * reloaded. If local sorting is used, the cache is sorted internally.
21529 * @param {String} fieldName The name of the field to sort by.
21530 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21532 sort : function(fieldName, dir){
21533 var f = this.fields.get(fieldName);
21535 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21537 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21538 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21543 this.sortToggle[f.name] = dir;
21544 this.sortInfo = {field: f.name, direction: dir};
21545 if(!this.remoteSort){
21547 this.fireEvent("datachanged", this);
21549 this.load(this.lastOptions);
21554 * Calls the specified function for each of the Records in the cache.
21555 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21556 * Returning <em>false</em> aborts and exits the iteration.
21557 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21559 each : function(fn, scope){
21560 this.data.each(fn, scope);
21564 * Gets all records modified since the last commit. Modified records are persisted across load operations
21565 * (e.g., during paging).
21566 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21568 getModifiedRecords : function(){
21569 return this.modified;
21573 createFilterFn : function(property, value, anyMatch){
21574 if(!value.exec){ // not a regex
21575 value = String(value);
21576 if(value.length == 0){
21579 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21581 return function(r){
21582 return value.test(r.data[property]);
21587 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21588 * @param {String} property A field on your records
21589 * @param {Number} start The record index to start at (defaults to 0)
21590 * @param {Number} end The last record index to include (defaults to length - 1)
21591 * @return {Number} The sum
21593 sum : function(property, start, end){
21594 var rs = this.data.items, v = 0;
21595 start = start || 0;
21596 end = (end || end === 0) ? end : rs.length-1;
21598 for(var i = start; i <= end; i++){
21599 v += (rs[i].data[property] || 0);
21605 * Filter the records by a specified property.
21606 * @param {String} field A field on your records
21607 * @param {String/RegExp} value Either a string that the field
21608 * should start with or a RegExp to test against the field
21609 * @param {Boolean} anyMatch True to match any part not just the beginning
21611 filter : function(property, value, anyMatch){
21612 var fn = this.createFilterFn(property, value, anyMatch);
21613 return fn ? this.filterBy(fn) : this.clearFilter();
21617 * Filter by a function. The specified function will be called with each
21618 * record in this data source. If the function returns true the record is included,
21619 * otherwise it is filtered.
21620 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21621 * @param {Object} scope (optional) The scope of the function (defaults to this)
21623 filterBy : function(fn, scope){
21624 this.snapshot = this.snapshot || this.data;
21625 this.data = this.queryBy(fn, scope||this);
21626 this.fireEvent("datachanged", this);
21630 * Query the records by a specified property.
21631 * @param {String} field A field on your records
21632 * @param {String/RegExp} value Either a string that the field
21633 * should start with or a RegExp to test against the field
21634 * @param {Boolean} anyMatch True to match any part not just the beginning
21635 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21637 query : function(property, value, anyMatch){
21638 var fn = this.createFilterFn(property, value, anyMatch);
21639 return fn ? this.queryBy(fn) : this.data.clone();
21643 * Query by a function. The specified function will be called with each
21644 * record in this data source. If the function returns true the record is included
21646 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21647 * @param {Object} scope (optional) The scope of the function (defaults to this)
21648 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21650 queryBy : function(fn, scope){
21651 var data = this.snapshot || this.data;
21652 return data.filterBy(fn, scope||this);
21656 * Collects unique values for a particular dataIndex from this store.
21657 * @param {String} dataIndex The property to collect
21658 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21659 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21660 * @return {Array} An array of the unique values
21662 collect : function(dataIndex, allowNull, bypassFilter){
21663 var d = (bypassFilter === true && this.snapshot) ?
21664 this.snapshot.items : this.data.items;
21665 var v, sv, r = [], l = {};
21666 for(var i = 0, len = d.length; i < len; i++){
21667 v = d[i].data[dataIndex];
21669 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21678 * Revert to a view of the Record cache with no filtering applied.
21679 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21681 clearFilter : function(suppressEvent){
21682 if(this.snapshot && this.snapshot != this.data){
21683 this.data = this.snapshot;
21684 delete this.snapshot;
21685 if(suppressEvent !== true){
21686 this.fireEvent("datachanged", this);
21692 afterEdit : function(record){
21693 if(this.modified.indexOf(record) == -1){
21694 this.modified.push(record);
21696 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21700 afterReject : function(record){
21701 this.modified.remove(record);
21702 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21706 afterCommit : function(record){
21707 this.modified.remove(record);
21708 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21712 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21713 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21715 commitChanges : function(){
21716 var m = this.modified.slice(0);
21717 this.modified = [];
21718 for(var i = 0, len = m.length; i < len; i++){
21724 * Cancel outstanding changes on all changed records.
21726 rejectChanges : function(){
21727 var m = this.modified.slice(0);
21728 this.modified = [];
21729 for(var i = 0, len = m.length; i < len; i++){
21734 onMetaChange : function(meta, rtype, o){
21735 this.recordType = rtype;
21736 this.fields = rtype.prototype.fields;
21737 delete this.snapshot;
21738 this.sortInfo = meta.sortInfo || this.sortInfo;
21739 this.modified = [];
21740 this.fireEvent('metachange', this, this.reader.meta);
21744 * Ext JS Library 1.1.1
21745 * Copyright(c) 2006-2007, Ext JS, LLC.
21747 * Originally Released Under LGPL - original licence link has changed is not relivant.
21750 * <script type="text/javascript">
21754 * @class Roo.data.SimpleStore
21755 * @extends Roo.data.Store
21756 * Small helper class to make creating Stores from Array data easier.
21757 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21758 * @cfg {Array} fields An array of field definition objects, or field name strings.
21759 * @cfg {Array} data The multi-dimensional array of data
21761 * @param {Object} config
21763 Roo.data.SimpleStore = function(config){
21764 Roo.data.SimpleStore.superclass.constructor.call(this, {
21766 reader: new Roo.data.ArrayReader({
21769 Roo.data.Record.create(config.fields)
21771 proxy : new Roo.data.MemoryProxy(config.data)
21775 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21777 * Ext JS Library 1.1.1
21778 * Copyright(c) 2006-2007, Ext JS, LLC.
21780 * Originally Released Under LGPL - original licence link has changed is not relivant.
21783 * <script type="text/javascript">
21788 * @extends Roo.data.Store
21789 * @class Roo.data.JsonStore
21790 * Small helper class to make creating Stores for JSON data easier. <br/>
21792 var store = new Roo.data.JsonStore({
21793 url: 'get-images.php',
21795 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21798 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21799 * JsonReader and HttpProxy (unless inline data is provided).</b>
21800 * @cfg {Array} fields An array of field definition objects, or field name strings.
21802 * @param {Object} config
21804 Roo.data.JsonStore = function(c){
21805 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21806 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21807 reader: new Roo.data.JsonReader(c, c.fields)
21810 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21812 * Ext JS Library 1.1.1
21813 * Copyright(c) 2006-2007, Ext JS, LLC.
21815 * Originally Released Under LGPL - original licence link has changed is not relivant.
21818 * <script type="text/javascript">
21822 Roo.data.Field = function(config){
21823 if(typeof config == "string"){
21824 config = {name: config};
21826 Roo.apply(this, config);
21829 this.type = "auto";
21832 var st = Roo.data.SortTypes;
21833 // named sortTypes are supported, here we look them up
21834 if(typeof this.sortType == "string"){
21835 this.sortType = st[this.sortType];
21838 // set default sortType for strings and dates
21839 if(!this.sortType){
21842 this.sortType = st.asUCString;
21845 this.sortType = st.asDate;
21848 this.sortType = st.none;
21853 var stripRe = /[\$,%]/g;
21855 // prebuilt conversion function for this field, instead of
21856 // switching every time we're reading a value
21858 var cv, dateFormat = this.dateFormat;
21863 cv = function(v){ return v; };
21866 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21870 return v !== undefined && v !== null && v !== '' ?
21871 parseInt(String(v).replace(stripRe, ""), 10) : '';
21876 return v !== undefined && v !== null && v !== '' ?
21877 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21882 cv = function(v){ return v === true || v === "true" || v == 1; };
21889 if(v instanceof Date){
21893 if(dateFormat == "timestamp"){
21894 return new Date(v*1000);
21896 return Date.parseDate(v, dateFormat);
21898 var parsed = Date.parse(v);
21899 return parsed ? new Date(parsed) : null;
21908 Roo.data.Field.prototype = {
21916 * Ext JS Library 1.1.1
21917 * Copyright(c) 2006-2007, Ext JS, LLC.
21919 * Originally Released Under LGPL - original licence link has changed is not relivant.
21922 * <script type="text/javascript">
21925 // Base class for reading structured data from a data source. This class is intended to be
21926 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21929 * @class Roo.data.DataReader
21930 * Base class for reading structured data from a data source. This class is intended to be
21931 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21934 Roo.data.DataReader = function(meta, recordType){
21938 this.recordType = recordType instanceof Array ?
21939 Roo.data.Record.create(recordType) : recordType;
21942 Roo.data.DataReader.prototype = {
21944 * Create an empty record
21945 * @param {Object} data (optional) - overlay some values
21946 * @return {Roo.data.Record} record created.
21948 newRow : function(d) {
21950 this.recordType.prototype.fields.each(function(c) {
21952 case 'int' : da[c.name] = 0; break;
21953 case 'date' : da[c.name] = new Date(); break;
21954 case 'float' : da[c.name] = 0.0; break;
21955 case 'boolean' : da[c.name] = false; break;
21956 default : da[c.name] = ""; break;
21960 return new this.recordType(Roo.apply(da, d));
21965 * Ext JS Library 1.1.1
21966 * Copyright(c) 2006-2007, Ext JS, LLC.
21968 * Originally Released Under LGPL - original licence link has changed is not relivant.
21971 * <script type="text/javascript">
21975 * @class Roo.data.DataProxy
21976 * @extends Roo.data.Observable
21977 * This class is an abstract base class for implementations which provide retrieval of
21978 * unformatted data objects.<br>
21980 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21981 * (of the appropriate type which knows how to parse the data object) to provide a block of
21982 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21984 * Custom implementations must implement the load method as described in
21985 * {@link Roo.data.HttpProxy#load}.
21987 Roo.data.DataProxy = function(){
21990 * @event beforeload
21991 * Fires before a network request is made to retrieve a data object.
21992 * @param {Object} This DataProxy object.
21993 * @param {Object} params The params parameter to the load function.
21998 * Fires before the load method's callback is called.
21999 * @param {Object} This DataProxy object.
22000 * @param {Object} o The data object.
22001 * @param {Object} arg The callback argument object passed to the load function.
22005 * @event loadexception
22006 * Fires if an Exception occurs during data retrieval.
22007 * @param {Object} This DataProxy object.
22008 * @param {Object} o The data object.
22009 * @param {Object} arg The callback argument object passed to the load function.
22010 * @param {Object} e The Exception.
22012 loadexception : true
22014 Roo.data.DataProxy.superclass.constructor.call(this);
22017 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22020 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22024 * Ext JS Library 1.1.1
22025 * Copyright(c) 2006-2007, Ext JS, LLC.
22027 * Originally Released Under LGPL - original licence link has changed is not relivant.
22030 * <script type="text/javascript">
22033 * @class Roo.data.MemoryProxy
22034 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22035 * to the Reader when its load method is called.
22037 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22039 Roo.data.MemoryProxy = function(data){
22043 Roo.data.MemoryProxy.superclass.constructor.call(this);
22047 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22049 * Load data from the requested source (in this case an in-memory
22050 * data object passed to the constructor), read the data object into
22051 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22052 * process that block using the passed callback.
22053 * @param {Object} params This parameter is not used by the MemoryProxy class.
22054 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22055 * object into a block of Roo.data.Records.
22056 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22057 * The function must be passed <ul>
22058 * <li>The Record block object</li>
22059 * <li>The "arg" argument from the load function</li>
22060 * <li>A boolean success indicator</li>
22062 * @param {Object} scope The scope in which to call the callback
22063 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22065 load : function(params, reader, callback, scope, arg){
22066 params = params || {};
22069 result = reader.readRecords(this.data);
22071 this.fireEvent("loadexception", this, arg, null, e);
22072 callback.call(scope, null, arg, false);
22075 callback.call(scope, result, arg, true);
22079 update : function(params, records){
22084 * Ext JS Library 1.1.1
22085 * Copyright(c) 2006-2007, Ext JS, LLC.
22087 * Originally Released Under LGPL - original licence link has changed is not relivant.
22090 * <script type="text/javascript">
22093 * @class Roo.data.HttpProxy
22094 * @extends Roo.data.DataProxy
22095 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22096 * configured to reference a certain URL.<br><br>
22098 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22099 * from which the running page was served.<br><br>
22101 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22103 * Be aware that to enable the browser to parse an XML document, the server must set
22104 * the Content-Type header in the HTTP response to "text/xml".
22106 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22107 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22108 * will be used to make the request.
22110 Roo.data.HttpProxy = function(conn){
22111 Roo.data.HttpProxy.superclass.constructor.call(this);
22112 // is conn a conn config or a real conn?
22114 this.useAjax = !conn || !conn.events;
22118 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22119 // thse are take from connection...
22122 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22125 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22126 * extra parameters to each request made by this object. (defaults to undefined)
22129 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22130 * to each request made by this object. (defaults to undefined)
22133 * @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)
22136 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22139 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22145 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22149 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22150 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22151 * a finer-grained basis than the DataProxy events.
22153 getConnection : function(){
22154 return this.useAjax ? Roo.Ajax : this.conn;
22158 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22159 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22160 * process that block using the passed callback.
22161 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22162 * for the request to the remote server.
22163 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22164 * object into a block of Roo.data.Records.
22165 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22166 * The function must be passed <ul>
22167 * <li>The Record block object</li>
22168 * <li>The "arg" argument from the load function</li>
22169 * <li>A boolean success indicator</li>
22171 * @param {Object} scope The scope in which to call the callback
22172 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22174 load : function(params, reader, callback, scope, arg){
22175 if(this.fireEvent("beforeload", this, params) !== false){
22177 params : params || {},
22179 callback : callback,
22184 callback : this.loadResponse,
22188 Roo.applyIf(o, this.conn);
22189 if(this.activeRequest){
22190 Roo.Ajax.abort(this.activeRequest);
22192 this.activeRequest = Roo.Ajax.request(o);
22194 this.conn.request(o);
22197 callback.call(scope||this, null, arg, false);
22202 loadResponse : function(o, success, response){
22203 delete this.activeRequest;
22205 this.fireEvent("loadexception", this, o, response);
22206 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22211 result = o.reader.read(response);
22213 this.fireEvent("loadexception", this, o, response, e);
22214 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22218 this.fireEvent("load", this, o, o.request.arg);
22219 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22223 update : function(dataSet){
22228 updateResponse : function(dataSet){
22233 * Ext JS Library 1.1.1
22234 * Copyright(c) 2006-2007, Ext JS, LLC.
22236 * Originally Released Under LGPL - original licence link has changed is not relivant.
22239 * <script type="text/javascript">
22243 * @class Roo.data.ScriptTagProxy
22244 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22245 * other than the originating domain of the running page.<br><br>
22247 * <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
22248 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22250 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22251 * source code that is used as the source inside a <script> tag.<br><br>
22253 * In order for the browser to process the returned data, the server must wrap the data object
22254 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22255 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22256 * depending on whether the callback name was passed:
22259 boolean scriptTag = false;
22260 String cb = request.getParameter("callback");
22263 response.setContentType("text/javascript");
22265 response.setContentType("application/x-json");
22267 Writer out = response.getWriter();
22269 out.write(cb + "(");
22271 out.print(dataBlock.toJsonString());
22278 * @param {Object} config A configuration object.
22280 Roo.data.ScriptTagProxy = function(config){
22281 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22282 Roo.apply(this, config);
22283 this.head = document.getElementsByTagName("head")[0];
22286 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22288 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22290 * @cfg {String} url The URL from which to request the data object.
22293 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22297 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22298 * the server the name of the callback function set up by the load call to process the returned data object.
22299 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22300 * javascript output which calls this named function passing the data object as its only parameter.
22302 callbackParam : "callback",
22304 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22305 * name to the request.
22310 * Load data from the configured URL, read the data object into
22311 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22312 * process that block using the passed callback.
22313 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22314 * for the request to the remote server.
22315 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22316 * object into a block of Roo.data.Records.
22317 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22318 * The function must be passed <ul>
22319 * <li>The Record block object</li>
22320 * <li>The "arg" argument from the load function</li>
22321 * <li>A boolean success indicator</li>
22323 * @param {Object} scope The scope in which to call the callback
22324 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22326 load : function(params, reader, callback, scope, arg){
22327 if(this.fireEvent("beforeload", this, params) !== false){
22329 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22331 var url = this.url;
22332 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22334 url += "&_dc=" + (new Date().getTime());
22336 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22339 cb : "stcCallback"+transId,
22340 scriptId : "stcScript"+transId,
22344 callback : callback,
22350 window[trans.cb] = function(o){
22351 conn.handleResponse(o, trans);
22354 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22356 if(this.autoAbort !== false){
22360 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22362 var script = document.createElement("script");
22363 script.setAttribute("src", url);
22364 script.setAttribute("type", "text/javascript");
22365 script.setAttribute("id", trans.scriptId);
22366 this.head.appendChild(script);
22368 this.trans = trans;
22370 callback.call(scope||this, null, arg, false);
22375 isLoading : function(){
22376 return this.trans ? true : false;
22380 * Abort the current server request.
22382 abort : function(){
22383 if(this.isLoading()){
22384 this.destroyTrans(this.trans);
22389 destroyTrans : function(trans, isLoaded){
22390 this.head.removeChild(document.getElementById(trans.scriptId));
22391 clearTimeout(trans.timeoutId);
22393 window[trans.cb] = undefined;
22395 delete window[trans.cb];
22398 // if hasn't been loaded, wait for load to remove it to prevent script error
22399 window[trans.cb] = function(){
22400 window[trans.cb] = undefined;
22402 delete window[trans.cb];
22409 handleResponse : function(o, trans){
22410 this.trans = false;
22411 this.destroyTrans(trans, true);
22414 result = trans.reader.readRecords(o);
22416 this.fireEvent("loadexception", this, o, trans.arg, e);
22417 trans.callback.call(trans.scope||window, null, trans.arg, false);
22420 this.fireEvent("load", this, o, trans.arg);
22421 trans.callback.call(trans.scope||window, result, trans.arg, true);
22425 handleFailure : function(trans){
22426 this.trans = false;
22427 this.destroyTrans(trans, false);
22428 this.fireEvent("loadexception", this, null, trans.arg);
22429 trans.callback.call(trans.scope||window, null, trans.arg, false);
22433 * Ext JS Library 1.1.1
22434 * Copyright(c) 2006-2007, Ext JS, LLC.
22436 * Originally Released Under LGPL - original licence link has changed is not relivant.
22439 * <script type="text/javascript">
22443 * @class Roo.data.JsonReader
22444 * @extends Roo.data.DataReader
22445 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22446 * based on mappings in a provided Roo.data.Record constructor.
22448 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22449 * in the reply previously.
22454 var RecordDef = Roo.data.Record.create([
22455 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22456 {name: 'occupation'} // This field will use "occupation" as the mapping.
22458 var myReader = new Roo.data.JsonReader({
22459 totalProperty: "results", // The property which contains the total dataset size (optional)
22460 root: "rows", // The property which contains an Array of row objects
22461 id: "id" // The property within each row object that provides an ID for the record (optional)
22465 * This would consume a JSON file like this:
22467 { 'results': 2, 'rows': [
22468 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22469 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22472 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22473 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22474 * paged from the remote server.
22475 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22476 * @cfg {String} root name of the property which contains the Array of row objects.
22477 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22479 * Create a new JsonReader
22480 * @param {Object} meta Metadata configuration options
22481 * @param {Object} recordType Either an Array of field definition objects,
22482 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22484 Roo.data.JsonReader = function(meta, recordType){
22487 // set some defaults:
22488 Roo.applyIf(meta, {
22489 totalProperty: 'total',
22490 successProperty : 'success',
22495 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22497 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22500 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22501 * Used by Store query builder to append _requestMeta to params.
22504 metaFromRemote : false,
22506 * This method is only used by a DataProxy which has retrieved data from a remote server.
22507 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22508 * @return {Object} data A data block which is used by an Roo.data.Store object as
22509 * a cache of Roo.data.Records.
22511 read : function(response){
22512 var json = response.responseText;
22514 var o = /* eval:var:o */ eval("("+json+")");
22516 throw {message: "JsonReader.read: Json object not found"};
22522 this.metaFromRemote = true;
22523 this.meta = o.metaData;
22524 this.recordType = Roo.data.Record.create(o.metaData.fields);
22525 this.onMetaChange(this.meta, this.recordType, o);
22527 return this.readRecords(o);
22530 // private function a store will implement
22531 onMetaChange : function(meta, recordType, o){
22538 simpleAccess: function(obj, subsc) {
22545 getJsonAccessor: function(){
22547 return function(expr) {
22549 return(re.test(expr))
22550 ? new Function("obj", "return obj." + expr)
22555 return Roo.emptyFn;
22560 * Create a data block containing Roo.data.Records from an XML document.
22561 * @param {Object} o An object which contains an Array of row objects in the property specified
22562 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22563 * which contains the total size of the dataset.
22564 * @return {Object} data A data block which is used by an Roo.data.Store object as
22565 * a cache of Roo.data.Records.
22567 readRecords : function(o){
22569 * After any data loads, the raw JSON data is available for further custom processing.
22573 var s = this.meta, Record = this.recordType,
22574 f = Record.prototype.fields, fi = f.items, fl = f.length;
22576 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22578 if(s.totalProperty) {
22579 this.getTotal = this.getJsonAccessor(s.totalProperty);
22581 if(s.successProperty) {
22582 this.getSuccess = this.getJsonAccessor(s.successProperty);
22584 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22586 var g = this.getJsonAccessor(s.id);
22587 this.getId = function(rec) {
22589 return (r === undefined || r === "") ? null : r;
22592 this.getId = function(){return null;};
22595 for(var jj = 0; jj < fl; jj++){
22597 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22598 this.ef[jj] = this.getJsonAccessor(map);
22602 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22603 if(s.totalProperty){
22604 var vt = parseInt(this.getTotal(o), 10);
22609 if(s.successProperty){
22610 var vs = this.getSuccess(o);
22611 if(vs === false || vs === 'false'){
22616 for(var i = 0; i < c; i++){
22619 var id = this.getId(n);
22620 for(var j = 0; j < fl; j++){
22622 var v = this.ef[j](n);
22624 Roo.log('missing convert for ' + f.name);
22628 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22630 var record = new Record(values, id);
22632 records[i] = record;
22638 totalRecords : totalRecords
22643 * Ext JS Library 1.1.1
22644 * Copyright(c) 2006-2007, Ext JS, LLC.
22646 * Originally Released Under LGPL - original licence link has changed is not relivant.
22649 * <script type="text/javascript">
22653 * @class Roo.data.XmlReader
22654 * @extends Roo.data.DataReader
22655 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22656 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22658 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22659 * header in the HTTP response must be set to "text/xml".</em>
22663 var RecordDef = Roo.data.Record.create([
22664 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22665 {name: 'occupation'} // This field will use "occupation" as the mapping.
22667 var myReader = new Roo.data.XmlReader({
22668 totalRecords: "results", // The element which contains the total dataset size (optional)
22669 record: "row", // The repeated element which contains row information
22670 id: "id" // The element within the row that provides an ID for the record (optional)
22674 * This would consume an XML file like this:
22678 <results>2</results>
22681 <name>Bill</name>
22682 <occupation>Gardener</occupation>
22686 <name>Ben</name>
22687 <occupation>Horticulturalist</occupation>
22691 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22692 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22693 * paged from the remote server.
22694 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22695 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22696 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22697 * a record identifier value.
22699 * Create a new XmlReader
22700 * @param {Object} meta Metadata configuration options
22701 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22702 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22703 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22705 Roo.data.XmlReader = function(meta, recordType){
22707 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22709 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22711 * This method is only used by a DataProxy which has retrieved data from a remote server.
22712 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22713 * to contain a method called 'responseXML' that returns an XML document object.
22714 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22715 * a cache of Roo.data.Records.
22717 read : function(response){
22718 var doc = response.responseXML;
22720 throw {message: "XmlReader.read: XML Document not available"};
22722 return this.readRecords(doc);
22726 * Create a data block containing Roo.data.Records from an XML document.
22727 * @param {Object} doc A parsed XML document.
22728 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22729 * a cache of Roo.data.Records.
22731 readRecords : function(doc){
22733 * After any data loads/reads, the raw XML Document is available for further custom processing.
22734 * @type XMLDocument
22736 this.xmlData = doc;
22737 var root = doc.documentElement || doc;
22738 var q = Roo.DomQuery;
22739 var recordType = this.recordType, fields = recordType.prototype.fields;
22740 var sid = this.meta.id;
22741 var totalRecords = 0, success = true;
22742 if(this.meta.totalRecords){
22743 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22746 if(this.meta.success){
22747 var sv = q.selectValue(this.meta.success, root, true);
22748 success = sv !== false && sv !== 'false';
22751 var ns = q.select(this.meta.record, root);
22752 for(var i = 0, len = ns.length; i < len; i++) {
22755 var id = sid ? q.selectValue(sid, n) : undefined;
22756 for(var j = 0, jlen = fields.length; j < jlen; j++){
22757 var f = fields.items[j];
22758 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22760 values[f.name] = v;
22762 var record = new recordType(values, id);
22764 records[records.length] = record;
22770 totalRecords : totalRecords || records.length
22775 * Ext JS Library 1.1.1
22776 * Copyright(c) 2006-2007, Ext JS, LLC.
22778 * Originally Released Under LGPL - original licence link has changed is not relivant.
22781 * <script type="text/javascript">
22785 * @class Roo.data.ArrayReader
22786 * @extends Roo.data.DataReader
22787 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22788 * Each element of that Array represents a row of data fields. The
22789 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22790 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22794 var RecordDef = Roo.data.Record.create([
22795 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22796 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22798 var myReader = new Roo.data.ArrayReader({
22799 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22803 * This would consume an Array like this:
22805 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22807 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22809 * Create a new JsonReader
22810 * @param {Object} meta Metadata configuration options.
22811 * @param {Object} recordType Either an Array of field definition objects
22812 * as specified to {@link Roo.data.Record#create},
22813 * or an {@link Roo.data.Record} object
22814 * created using {@link Roo.data.Record#create}.
22816 Roo.data.ArrayReader = function(meta, recordType){
22817 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22820 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22822 * Create a data block containing Roo.data.Records from an XML document.
22823 * @param {Object} o An Array of row objects which represents the dataset.
22824 * @return {Object} data A data block which is used by an Roo.data.Store object as
22825 * a cache of Roo.data.Records.
22827 readRecords : function(o){
22828 var sid = this.meta ? this.meta.id : null;
22829 var recordType = this.recordType, fields = recordType.prototype.fields;
22832 for(var i = 0; i < root.length; i++){
22835 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22836 for(var j = 0, jlen = fields.length; j < jlen; j++){
22837 var f = fields.items[j];
22838 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22839 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22841 values[f.name] = v;
22843 var record = new recordType(values, id);
22845 records[records.length] = record;
22849 totalRecords : records.length
22854 * Ext JS Library 1.1.1
22855 * Copyright(c) 2006-2007, Ext JS, LLC.
22857 * Originally Released Under LGPL - original licence link has changed is not relivant.
22860 * <script type="text/javascript">
22865 * @class Roo.data.Tree
22866 * @extends Roo.util.Observable
22867 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22868 * in the tree have most standard DOM functionality.
22870 * @param {Node} root (optional) The root node
22872 Roo.data.Tree = function(root){
22873 this.nodeHash = {};
22875 * The root node for this tree
22880 this.setRootNode(root);
22885 * Fires when a new child node is appended to a node in this tree.
22886 * @param {Tree} tree The owner tree
22887 * @param {Node} parent The parent node
22888 * @param {Node} node The newly appended node
22889 * @param {Number} index The index of the newly appended node
22894 * Fires when a child node is removed from a node in this tree.
22895 * @param {Tree} tree The owner tree
22896 * @param {Node} parent The parent node
22897 * @param {Node} node The child node removed
22902 * Fires when a node is moved to a new location in the tree
22903 * @param {Tree} tree The owner tree
22904 * @param {Node} node The node moved
22905 * @param {Node} oldParent The old parent of this node
22906 * @param {Node} newParent The new parent of this node
22907 * @param {Number} index The index it was moved to
22912 * Fires when a new child node is inserted in a node in this tree.
22913 * @param {Tree} tree The owner tree
22914 * @param {Node} parent The parent node
22915 * @param {Node} node The child node inserted
22916 * @param {Node} refNode The child node the node was inserted before
22920 * @event beforeappend
22921 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22922 * @param {Tree} tree The owner tree
22923 * @param {Node} parent The parent node
22924 * @param {Node} node The child node to be appended
22926 "beforeappend" : true,
22928 * @event beforeremove
22929 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22930 * @param {Tree} tree The owner tree
22931 * @param {Node} parent The parent node
22932 * @param {Node} node The child node to be removed
22934 "beforeremove" : true,
22936 * @event beforemove
22937 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22938 * @param {Tree} tree The owner tree
22939 * @param {Node} node The node being moved
22940 * @param {Node} oldParent The parent of the node
22941 * @param {Node} newParent The new parent the node is moving to
22942 * @param {Number} index The index it is being moved to
22944 "beforemove" : true,
22946 * @event beforeinsert
22947 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22948 * @param {Tree} tree The owner tree
22949 * @param {Node} parent The parent node
22950 * @param {Node} node The child node to be inserted
22951 * @param {Node} refNode The child node the node is being inserted before
22953 "beforeinsert" : true
22956 Roo.data.Tree.superclass.constructor.call(this);
22959 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22960 pathSeparator: "/",
22962 proxyNodeEvent : function(){
22963 return this.fireEvent.apply(this, arguments);
22967 * Returns the root node for this tree.
22970 getRootNode : function(){
22975 * Sets the root node for this tree.
22976 * @param {Node} node
22979 setRootNode : function(node){
22981 node.ownerTree = this;
22982 node.isRoot = true;
22983 this.registerNode(node);
22988 * Gets a node in this tree by its id.
22989 * @param {String} id
22992 getNodeById : function(id){
22993 return this.nodeHash[id];
22996 registerNode : function(node){
22997 this.nodeHash[node.id] = node;
23000 unregisterNode : function(node){
23001 delete this.nodeHash[node.id];
23004 toString : function(){
23005 return "[Tree"+(this.id?" "+this.id:"")+"]";
23010 * @class Roo.data.Node
23011 * @extends Roo.util.Observable
23012 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23013 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23015 * @param {Object} attributes The attributes/config for the node
23017 Roo.data.Node = function(attributes){
23019 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23022 this.attributes = attributes || {};
23023 this.leaf = this.attributes.leaf;
23025 * The node id. @type String
23027 this.id = this.attributes.id;
23029 this.id = Roo.id(null, "ynode-");
23030 this.attributes.id = this.id;
23035 * All child nodes of this node. @type Array
23037 this.childNodes = [];
23038 if(!this.childNodes.indexOf){ // indexOf is a must
23039 this.childNodes.indexOf = function(o){
23040 for(var i = 0, len = this.length; i < len; i++){
23049 * The parent node for this node. @type Node
23051 this.parentNode = null;
23053 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23055 this.firstChild = null;
23057 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23059 this.lastChild = null;
23061 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23063 this.previousSibling = null;
23065 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23067 this.nextSibling = null;
23072 * Fires when a new child node is appended
23073 * @param {Tree} tree The owner tree
23074 * @param {Node} this This node
23075 * @param {Node} node The newly appended node
23076 * @param {Number} index The index of the newly appended node
23081 * Fires when a child node is removed
23082 * @param {Tree} tree The owner tree
23083 * @param {Node} this This node
23084 * @param {Node} node The removed node
23089 * Fires when this node is moved to a new location in the tree
23090 * @param {Tree} tree The owner tree
23091 * @param {Node} this This node
23092 * @param {Node} oldParent The old parent of this node
23093 * @param {Node} newParent The new parent of this node
23094 * @param {Number} index The index it was moved to
23099 * Fires when a new child node is inserted.
23100 * @param {Tree} tree The owner tree
23101 * @param {Node} this This node
23102 * @param {Node} node The child node inserted
23103 * @param {Node} refNode The child node the node was inserted before
23107 * @event beforeappend
23108 * Fires before a new child is appended, return false to cancel the append.
23109 * @param {Tree} tree The owner tree
23110 * @param {Node} this This node
23111 * @param {Node} node The child node to be appended
23113 "beforeappend" : true,
23115 * @event beforeremove
23116 * Fires before a child is removed, return false to cancel the remove.
23117 * @param {Tree} tree The owner tree
23118 * @param {Node} this This node
23119 * @param {Node} node The child node to be removed
23121 "beforeremove" : true,
23123 * @event beforemove
23124 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23125 * @param {Tree} tree The owner tree
23126 * @param {Node} this This node
23127 * @param {Node} oldParent The parent of this node
23128 * @param {Node} newParent The new parent this node is moving to
23129 * @param {Number} index The index it is being moved to
23131 "beforemove" : true,
23133 * @event beforeinsert
23134 * Fires before a new child is inserted, return false to cancel the insert.
23135 * @param {Tree} tree The owner tree
23136 * @param {Node} this This node
23137 * @param {Node} node The child node to be inserted
23138 * @param {Node} refNode The child node the node is being inserted before
23140 "beforeinsert" : true
23142 this.listeners = this.attributes.listeners;
23143 Roo.data.Node.superclass.constructor.call(this);
23146 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23147 fireEvent : function(evtName){
23148 // first do standard event for this node
23149 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23152 // then bubble it up to the tree if the event wasn't cancelled
23153 var ot = this.getOwnerTree();
23155 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23163 * Returns true if this node is a leaf
23164 * @return {Boolean}
23166 isLeaf : function(){
23167 return this.leaf === true;
23171 setFirstChild : function(node){
23172 this.firstChild = node;
23176 setLastChild : function(node){
23177 this.lastChild = node;
23182 * Returns true if this node is the last child of its parent
23183 * @return {Boolean}
23185 isLast : function(){
23186 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23190 * Returns true if this node is the first child of its parent
23191 * @return {Boolean}
23193 isFirst : function(){
23194 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23197 hasChildNodes : function(){
23198 return !this.isLeaf() && this.childNodes.length > 0;
23202 * Insert node(s) as the last child node of this node.
23203 * @param {Node/Array} node The node or Array of nodes to append
23204 * @return {Node} The appended node if single append, or null if an array was passed
23206 appendChild : function(node){
23208 if(node instanceof Array){
23210 }else if(arguments.length > 1){
23213 // if passed an array or multiple args do them one by one
23215 for(var i = 0, len = multi.length; i < len; i++) {
23216 this.appendChild(multi[i]);
23219 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23222 var index = this.childNodes.length;
23223 var oldParent = node.parentNode;
23224 // it's a move, make sure we move it cleanly
23226 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23229 oldParent.removeChild(node);
23231 index = this.childNodes.length;
23233 this.setFirstChild(node);
23235 this.childNodes.push(node);
23236 node.parentNode = this;
23237 var ps = this.childNodes[index-1];
23239 node.previousSibling = ps;
23240 ps.nextSibling = node;
23242 node.previousSibling = null;
23244 node.nextSibling = null;
23245 this.setLastChild(node);
23246 node.setOwnerTree(this.getOwnerTree());
23247 this.fireEvent("append", this.ownerTree, this, node, index);
23249 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23256 * Removes a child node from this node.
23257 * @param {Node} node The node to remove
23258 * @return {Node} The removed node
23260 removeChild : function(node){
23261 var index = this.childNodes.indexOf(node);
23265 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23269 // remove it from childNodes collection
23270 this.childNodes.splice(index, 1);
23273 if(node.previousSibling){
23274 node.previousSibling.nextSibling = node.nextSibling;
23276 if(node.nextSibling){
23277 node.nextSibling.previousSibling = node.previousSibling;
23280 // update child refs
23281 if(this.firstChild == node){
23282 this.setFirstChild(node.nextSibling);
23284 if(this.lastChild == node){
23285 this.setLastChild(node.previousSibling);
23288 node.setOwnerTree(null);
23289 // clear any references from the node
23290 node.parentNode = null;
23291 node.previousSibling = null;
23292 node.nextSibling = null;
23293 this.fireEvent("remove", this.ownerTree, this, node);
23298 * Inserts the first node before the second node in this nodes childNodes collection.
23299 * @param {Node} node The node to insert
23300 * @param {Node} refNode The node to insert before (if null the node is appended)
23301 * @return {Node} The inserted node
23303 insertBefore : function(node, refNode){
23304 if(!refNode){ // like standard Dom, refNode can be null for append
23305 return this.appendChild(node);
23308 if(node == refNode){
23312 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23315 var index = this.childNodes.indexOf(refNode);
23316 var oldParent = node.parentNode;
23317 var refIndex = index;
23319 // when moving internally, indexes will change after remove
23320 if(oldParent == this && this.childNodes.indexOf(node) < index){
23324 // it's a move, make sure we move it cleanly
23326 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23329 oldParent.removeChild(node);
23332 this.setFirstChild(node);
23334 this.childNodes.splice(refIndex, 0, node);
23335 node.parentNode = this;
23336 var ps = this.childNodes[refIndex-1];
23338 node.previousSibling = ps;
23339 ps.nextSibling = node;
23341 node.previousSibling = null;
23343 node.nextSibling = refNode;
23344 refNode.previousSibling = node;
23345 node.setOwnerTree(this.getOwnerTree());
23346 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23348 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23354 * Returns the child node at the specified index.
23355 * @param {Number} index
23358 item : function(index){
23359 return this.childNodes[index];
23363 * Replaces one child node in this node with another.
23364 * @param {Node} newChild The replacement node
23365 * @param {Node} oldChild The node to replace
23366 * @return {Node} The replaced node
23368 replaceChild : function(newChild, oldChild){
23369 this.insertBefore(newChild, oldChild);
23370 this.removeChild(oldChild);
23375 * Returns the index of a child node
23376 * @param {Node} node
23377 * @return {Number} The index of the node or -1 if it was not found
23379 indexOf : function(child){
23380 return this.childNodes.indexOf(child);
23384 * Returns the tree this node is in.
23387 getOwnerTree : function(){
23388 // if it doesn't have one, look for one
23389 if(!this.ownerTree){
23393 this.ownerTree = p.ownerTree;
23399 return this.ownerTree;
23403 * Returns depth of this node (the root node has a depth of 0)
23406 getDepth : function(){
23409 while(p.parentNode){
23417 setOwnerTree : function(tree){
23418 // if it's move, we need to update everyone
23419 if(tree != this.ownerTree){
23420 if(this.ownerTree){
23421 this.ownerTree.unregisterNode(this);
23423 this.ownerTree = tree;
23424 var cs = this.childNodes;
23425 for(var i = 0, len = cs.length; i < len; i++) {
23426 cs[i].setOwnerTree(tree);
23429 tree.registerNode(this);
23435 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23436 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23437 * @return {String} The path
23439 getPath : function(attr){
23440 attr = attr || "id";
23441 var p = this.parentNode;
23442 var b = [this.attributes[attr]];
23444 b.unshift(p.attributes[attr]);
23447 var sep = this.getOwnerTree().pathSeparator;
23448 return sep + b.join(sep);
23452 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23453 * function call will be the scope provided or the current node. The arguments to the function
23454 * will be the args provided or the current node. If the function returns false at any point,
23455 * the bubble is stopped.
23456 * @param {Function} fn The function to call
23457 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23458 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23460 bubble : function(fn, scope, args){
23463 if(fn.call(scope || p, args || p) === false){
23471 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23472 * function call will be the scope provided or the current node. The arguments to the function
23473 * will be the args provided or the current node. If the function returns false at any point,
23474 * the cascade is stopped on that branch.
23475 * @param {Function} fn The function to call
23476 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23477 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23479 cascade : function(fn, scope, args){
23480 if(fn.call(scope || this, args || this) !== false){
23481 var cs = this.childNodes;
23482 for(var i = 0, len = cs.length; i < len; i++) {
23483 cs[i].cascade(fn, scope, args);
23489 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23490 * function call will be the scope provided or the current node. The arguments to the function
23491 * will be the args provided or the current node. If the function returns false at any point,
23492 * the iteration stops.
23493 * @param {Function} fn The function to call
23494 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23495 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23497 eachChild : function(fn, scope, args){
23498 var cs = this.childNodes;
23499 for(var i = 0, len = cs.length; i < len; i++) {
23500 if(fn.call(scope || this, args || cs[i]) === false){
23507 * Finds the first child that has the attribute with the specified value.
23508 * @param {String} attribute The attribute name
23509 * @param {Mixed} value The value to search for
23510 * @return {Node} The found child or null if none was found
23512 findChild : function(attribute, value){
23513 var cs = this.childNodes;
23514 for(var i = 0, len = cs.length; i < len; i++) {
23515 if(cs[i].attributes[attribute] == value){
23523 * Finds the first child by a custom function. The child matches if the function passed
23525 * @param {Function} fn
23526 * @param {Object} scope (optional)
23527 * @return {Node} The found child or null if none was found
23529 findChildBy : function(fn, scope){
23530 var cs = this.childNodes;
23531 for(var i = 0, len = cs.length; i < len; i++) {
23532 if(fn.call(scope||cs[i], cs[i]) === true){
23540 * Sorts this nodes children using the supplied sort function
23541 * @param {Function} fn
23542 * @param {Object} scope (optional)
23544 sort : function(fn, scope){
23545 var cs = this.childNodes;
23546 var len = cs.length;
23548 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23550 for(var i = 0; i < len; i++){
23552 n.previousSibling = cs[i-1];
23553 n.nextSibling = cs[i+1];
23555 this.setFirstChild(n);
23558 this.setLastChild(n);
23565 * Returns true if this node is an ancestor (at any point) of the passed node.
23566 * @param {Node} node
23567 * @return {Boolean}
23569 contains : function(node){
23570 return node.isAncestor(this);
23574 * Returns true if the passed node is an ancestor (at any point) of this node.
23575 * @param {Node} node
23576 * @return {Boolean}
23578 isAncestor : function(node){
23579 var p = this.parentNode;
23589 toString : function(){
23590 return "[Node"+(this.id?" "+this.id:"")+"]";
23594 * Ext JS Library 1.1.1
23595 * Copyright(c) 2006-2007, Ext JS, LLC.
23597 * Originally Released Under LGPL - original licence link has changed is not relivant.
23600 * <script type="text/javascript">
23605 * @extends Roo.Element
23606 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23607 * automatic maintaining of shadow/shim positions.
23608 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23609 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23610 * you can pass a string with a CSS class name. False turns off the shadow.
23611 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23612 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23613 * @cfg {String} cls CSS class to add to the element
23614 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23615 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23617 * @param {Object} config An object with config options.
23618 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23621 Roo.Layer = function(config, existingEl){
23622 config = config || {};
23623 var dh = Roo.DomHelper;
23624 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23626 this.dom = Roo.getDom(existingEl);
23629 var o = config.dh || {tag: "div", cls: "x-layer"};
23630 this.dom = dh.append(pel, o);
23633 this.addClass(config.cls);
23635 this.constrain = config.constrain !== false;
23636 this.visibilityMode = Roo.Element.VISIBILITY;
23638 this.id = this.dom.id = config.id;
23640 this.id = Roo.id(this.dom);
23642 this.zindex = config.zindex || this.getZIndex();
23643 this.position("absolute", this.zindex);
23645 this.shadowOffset = config.shadowOffset || 4;
23646 this.shadow = new Roo.Shadow({
23647 offset : this.shadowOffset,
23648 mode : config.shadow
23651 this.shadowOffset = 0;
23653 this.useShim = config.shim !== false && Roo.useShims;
23654 this.useDisplay = config.useDisplay;
23658 var supr = Roo.Element.prototype;
23660 // shims are shared among layer to keep from having 100 iframes
23663 Roo.extend(Roo.Layer, Roo.Element, {
23665 getZIndex : function(){
23666 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23669 getShim : function(){
23676 var shim = shims.shift();
23678 shim = this.createShim();
23679 shim.enableDisplayMode('block');
23680 shim.dom.style.display = 'none';
23681 shim.dom.style.visibility = 'visible';
23683 var pn = this.dom.parentNode;
23684 if(shim.dom.parentNode != pn){
23685 pn.insertBefore(shim.dom, this.dom);
23687 shim.setStyle('z-index', this.getZIndex()-2);
23692 hideShim : function(){
23694 this.shim.setDisplayed(false);
23695 shims.push(this.shim);
23700 disableShadow : function(){
23702 this.shadowDisabled = true;
23703 this.shadow.hide();
23704 this.lastShadowOffset = this.shadowOffset;
23705 this.shadowOffset = 0;
23709 enableShadow : function(show){
23711 this.shadowDisabled = false;
23712 this.shadowOffset = this.lastShadowOffset;
23713 delete this.lastShadowOffset;
23721 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23722 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23723 sync : function(doShow){
23724 var sw = this.shadow;
23725 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23726 var sh = this.getShim();
23728 var w = this.getWidth(),
23729 h = this.getHeight();
23731 var l = this.getLeft(true),
23732 t = this.getTop(true);
23734 if(sw && !this.shadowDisabled){
23735 if(doShow && !sw.isVisible()){
23738 sw.realign(l, t, w, h);
23744 // fit the shim behind the shadow, so it is shimmed too
23745 var a = sw.adjusts, s = sh.dom.style;
23746 s.left = (Math.min(l, l+a.l))+"px";
23747 s.top = (Math.min(t, t+a.t))+"px";
23748 s.width = (w+a.w)+"px";
23749 s.height = (h+a.h)+"px";
23756 sh.setLeftTop(l, t);
23763 destroy : function(){
23766 this.shadow.hide();
23768 this.removeAllListeners();
23769 var pn = this.dom.parentNode;
23771 pn.removeChild(this.dom);
23773 Roo.Element.uncache(this.id);
23776 remove : function(){
23781 beginUpdate : function(){
23782 this.updating = true;
23786 endUpdate : function(){
23787 this.updating = false;
23792 hideUnders : function(negOffset){
23794 this.shadow.hide();
23800 constrainXY : function(){
23801 if(this.constrain){
23802 var vw = Roo.lib.Dom.getViewWidth(),
23803 vh = Roo.lib.Dom.getViewHeight();
23804 var s = Roo.get(document).getScroll();
23806 var xy = this.getXY();
23807 var x = xy[0], y = xy[1];
23808 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23809 // only move it if it needs it
23811 // first validate right/bottom
23812 if((x + w) > vw+s.left){
23813 x = vw - w - this.shadowOffset;
23816 if((y + h) > vh+s.top){
23817 y = vh - h - this.shadowOffset;
23820 // then make sure top/left isn't negative
23831 var ay = this.avoidY;
23832 if(y <= ay && (y+h) >= ay){
23838 supr.setXY.call(this, xy);
23844 isVisible : function(){
23845 return this.visible;
23849 showAction : function(){
23850 this.visible = true; // track visibility to prevent getStyle calls
23851 if(this.useDisplay === true){
23852 this.setDisplayed("");
23853 }else if(this.lastXY){
23854 supr.setXY.call(this, this.lastXY);
23855 }else if(this.lastLT){
23856 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23861 hideAction : function(){
23862 this.visible = false;
23863 if(this.useDisplay === true){
23864 this.setDisplayed(false);
23866 this.setLeftTop(-10000,-10000);
23870 // overridden Element method
23871 setVisible : function(v, a, d, c, e){
23876 var cb = function(){
23881 }.createDelegate(this);
23882 supr.setVisible.call(this, true, true, d, cb, e);
23885 this.hideUnders(true);
23894 }.createDelegate(this);
23896 supr.setVisible.call(this, v, a, d, cb, e);
23905 storeXY : function(xy){
23906 delete this.lastLT;
23910 storeLeftTop : function(left, top){
23911 delete this.lastXY;
23912 this.lastLT = [left, top];
23916 beforeFx : function(){
23917 this.beforeAction();
23918 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23922 afterFx : function(){
23923 Roo.Layer.superclass.afterFx.apply(this, arguments);
23924 this.sync(this.isVisible());
23928 beforeAction : function(){
23929 if(!this.updating && this.shadow){
23930 this.shadow.hide();
23934 // overridden Element method
23935 setLeft : function(left){
23936 this.storeLeftTop(left, this.getTop(true));
23937 supr.setLeft.apply(this, arguments);
23941 setTop : function(top){
23942 this.storeLeftTop(this.getLeft(true), top);
23943 supr.setTop.apply(this, arguments);
23947 setLeftTop : function(left, top){
23948 this.storeLeftTop(left, top);
23949 supr.setLeftTop.apply(this, arguments);
23953 setXY : function(xy, a, d, c, e){
23955 this.beforeAction();
23957 var cb = this.createCB(c);
23958 supr.setXY.call(this, xy, a, d, cb, e);
23965 createCB : function(c){
23976 // overridden Element method
23977 setX : function(x, a, d, c, e){
23978 this.setXY([x, this.getY()], a, d, c, e);
23981 // overridden Element method
23982 setY : function(y, a, d, c, e){
23983 this.setXY([this.getX(), y], a, d, c, e);
23986 // overridden Element method
23987 setSize : function(w, h, a, d, c, e){
23988 this.beforeAction();
23989 var cb = this.createCB(c);
23990 supr.setSize.call(this, w, h, a, d, cb, e);
23996 // overridden Element method
23997 setWidth : function(w, a, d, c, e){
23998 this.beforeAction();
23999 var cb = this.createCB(c);
24000 supr.setWidth.call(this, w, a, d, cb, e);
24006 // overridden Element method
24007 setHeight : function(h, a, d, c, e){
24008 this.beforeAction();
24009 var cb = this.createCB(c);
24010 supr.setHeight.call(this, h, a, d, cb, e);
24016 // overridden Element method
24017 setBounds : function(x, y, w, h, a, d, c, e){
24018 this.beforeAction();
24019 var cb = this.createCB(c);
24021 this.storeXY([x, y]);
24022 supr.setXY.call(this, [x, y]);
24023 supr.setSize.call(this, w, h, a, d, cb, e);
24026 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24032 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24033 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24034 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24035 * @param {Number} zindex The new z-index to set
24036 * @return {this} The Layer
24038 setZIndex : function(zindex){
24039 this.zindex = zindex;
24040 this.setStyle("z-index", zindex + 2);
24042 this.shadow.setZIndex(zindex + 1);
24045 this.shim.setStyle("z-index", zindex);
24051 * Ext JS Library 1.1.1
24052 * Copyright(c) 2006-2007, Ext JS, LLC.
24054 * Originally Released Under LGPL - original licence link has changed is not relivant.
24057 * <script type="text/javascript">
24062 * @class Roo.Shadow
24063 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24064 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24065 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24067 * Create a new Shadow
24068 * @param {Object} config The config object
24070 Roo.Shadow = function(config){
24071 Roo.apply(this, config);
24072 if(typeof this.mode != "string"){
24073 this.mode = this.defaultMode;
24075 var o = this.offset, a = {h: 0};
24076 var rad = Math.floor(this.offset/2);
24077 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24083 a.l -= this.offset + rad;
24084 a.t -= this.offset + rad;
24095 a.l -= (this.offset - rad);
24096 a.t -= this.offset + rad;
24098 a.w -= (this.offset - rad)*2;
24109 a.l -= (this.offset - rad);
24110 a.t -= (this.offset - rad);
24112 a.w -= (this.offset + rad + 1);
24113 a.h -= (this.offset + rad);
24122 Roo.Shadow.prototype = {
24124 * @cfg {String} mode
24125 * The shadow display mode. Supports the following options:<br />
24126 * sides: Shadow displays on both sides and bottom only<br />
24127 * frame: Shadow displays equally on all four sides<br />
24128 * drop: Traditional bottom-right drop shadow (default)
24131 * @cfg {String} offset
24132 * The number of pixels to offset the shadow from the element (defaults to 4)
24137 defaultMode: "drop",
24140 * Displays the shadow under the target element
24141 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24143 show : function(target){
24144 target = Roo.get(target);
24146 this.el = Roo.Shadow.Pool.pull();
24147 if(this.el.dom.nextSibling != target.dom){
24148 this.el.insertBefore(target);
24151 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24153 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24156 target.getLeft(true),
24157 target.getTop(true),
24161 this.el.dom.style.display = "block";
24165 * Returns true if the shadow is visible, else false
24167 isVisible : function(){
24168 return this.el ? true : false;
24172 * Direct alignment when values are already available. Show must be called at least once before
24173 * calling this method to ensure it is initialized.
24174 * @param {Number} left The target element left position
24175 * @param {Number} top The target element top position
24176 * @param {Number} width The target element width
24177 * @param {Number} height The target element height
24179 realign : function(l, t, w, h){
24183 var a = this.adjusts, d = this.el.dom, s = d.style;
24185 s.left = (l+a.l)+"px";
24186 s.top = (t+a.t)+"px";
24187 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24189 if(s.width != sws || s.height != shs){
24193 var cn = d.childNodes;
24194 var sww = Math.max(0, (sw-12))+"px";
24195 cn[0].childNodes[1].style.width = sww;
24196 cn[1].childNodes[1].style.width = sww;
24197 cn[2].childNodes[1].style.width = sww;
24198 cn[1].style.height = Math.max(0, (sh-12))+"px";
24204 * Hides this shadow
24208 this.el.dom.style.display = "none";
24209 Roo.Shadow.Pool.push(this.el);
24215 * Adjust the z-index of this shadow
24216 * @param {Number} zindex The new z-index
24218 setZIndex : function(z){
24221 this.el.setStyle("z-index", z);
24226 // Private utility class that manages the internal Shadow cache
24227 Roo.Shadow.Pool = function(){
24229 var markup = Roo.isIE ?
24230 '<div class="x-ie-shadow"></div>' :
24231 '<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>';
24234 var sh = p.shift();
24236 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24237 sh.autoBoxAdjust = false;
24242 push : function(sh){
24248 * Ext JS Library 1.1.1
24249 * Copyright(c) 2006-2007, Ext JS, LLC.
24251 * Originally Released Under LGPL - original licence link has changed is not relivant.
24254 * <script type="text/javascript">
24259 * @class Roo.SplitBar
24260 * @extends Roo.util.Observable
24261 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24265 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24266 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24267 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24268 split.minSize = 100;
24269 split.maxSize = 600;
24270 split.animate = true;
24271 split.on('moved', splitterMoved);
24274 * Create a new SplitBar
24275 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24276 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24277 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24278 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24279 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24280 position of the SplitBar).
24282 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24285 this.el = Roo.get(dragElement, true);
24286 this.el.dom.unselectable = "on";
24288 this.resizingEl = Roo.get(resizingElement, true);
24292 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24293 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24296 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24299 * The minimum size of the resizing element. (Defaults to 0)
24305 * The maximum size of the resizing element. (Defaults to 2000)
24308 this.maxSize = 2000;
24311 * Whether to animate the transition to the new size
24314 this.animate = false;
24317 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24320 this.useShim = false;
24325 if(!existingProxy){
24327 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24329 this.proxy = Roo.get(existingProxy).dom;
24332 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24335 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24338 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24341 this.dragSpecs = {};
24344 * @private The adapter to use to positon and resize elements
24346 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24347 this.adapter.init(this);
24349 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24351 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24352 this.el.addClass("x-splitbar-h");
24355 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24356 this.el.addClass("x-splitbar-v");
24362 * Fires when the splitter is moved (alias for {@link #event-moved})
24363 * @param {Roo.SplitBar} this
24364 * @param {Number} newSize the new width or height
24369 * Fires when the splitter is moved
24370 * @param {Roo.SplitBar} this
24371 * @param {Number} newSize the new width or height
24375 * @event beforeresize
24376 * Fires before the splitter is dragged
24377 * @param {Roo.SplitBar} this
24379 "beforeresize" : true,
24381 "beforeapply" : true
24384 Roo.util.Observable.call(this);
24387 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24388 onStartProxyDrag : function(x, y){
24389 this.fireEvent("beforeresize", this);
24391 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24393 o.enableDisplayMode("block");
24394 // all splitbars share the same overlay
24395 Roo.SplitBar.prototype.overlay = o;
24397 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24398 this.overlay.show();
24399 Roo.get(this.proxy).setDisplayed("block");
24400 var size = this.adapter.getElementSize(this);
24401 this.activeMinSize = this.getMinimumSize();;
24402 this.activeMaxSize = this.getMaximumSize();;
24403 var c1 = size - this.activeMinSize;
24404 var c2 = Math.max(this.activeMaxSize - size, 0);
24405 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24406 this.dd.resetConstraints();
24407 this.dd.setXConstraint(
24408 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24409 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24411 this.dd.setYConstraint(0, 0);
24413 this.dd.resetConstraints();
24414 this.dd.setXConstraint(0, 0);
24415 this.dd.setYConstraint(
24416 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24417 this.placement == Roo.SplitBar.TOP ? c2 : c1
24420 this.dragSpecs.startSize = size;
24421 this.dragSpecs.startPoint = [x, y];
24422 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24426 * @private Called after the drag operation by the DDProxy
24428 onEndProxyDrag : function(e){
24429 Roo.get(this.proxy).setDisplayed(false);
24430 var endPoint = Roo.lib.Event.getXY(e);
24432 this.overlay.hide();
24435 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24436 newSize = this.dragSpecs.startSize +
24437 (this.placement == Roo.SplitBar.LEFT ?
24438 endPoint[0] - this.dragSpecs.startPoint[0] :
24439 this.dragSpecs.startPoint[0] - endPoint[0]
24442 newSize = this.dragSpecs.startSize +
24443 (this.placement == Roo.SplitBar.TOP ?
24444 endPoint[1] - this.dragSpecs.startPoint[1] :
24445 this.dragSpecs.startPoint[1] - endPoint[1]
24448 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24449 if(newSize != this.dragSpecs.startSize){
24450 if(this.fireEvent('beforeapply', this, newSize) !== false){
24451 this.adapter.setElementSize(this, newSize);
24452 this.fireEvent("moved", this, newSize);
24453 this.fireEvent("resize", this, newSize);
24459 * Get the adapter this SplitBar uses
24460 * @return The adapter object
24462 getAdapter : function(){
24463 return this.adapter;
24467 * Set the adapter this SplitBar uses
24468 * @param {Object} adapter A SplitBar adapter object
24470 setAdapter : function(adapter){
24471 this.adapter = adapter;
24472 this.adapter.init(this);
24476 * Gets the minimum size for the resizing element
24477 * @return {Number} The minimum size
24479 getMinimumSize : function(){
24480 return this.minSize;
24484 * Sets the minimum size for the resizing element
24485 * @param {Number} minSize The minimum size
24487 setMinimumSize : function(minSize){
24488 this.minSize = minSize;
24492 * Gets the maximum size for the resizing element
24493 * @return {Number} The maximum size
24495 getMaximumSize : function(){
24496 return this.maxSize;
24500 * Sets the maximum size for the resizing element
24501 * @param {Number} maxSize The maximum size
24503 setMaximumSize : function(maxSize){
24504 this.maxSize = maxSize;
24508 * Sets the initialize size for the resizing element
24509 * @param {Number} size The initial size
24511 setCurrentSize : function(size){
24512 var oldAnimate = this.animate;
24513 this.animate = false;
24514 this.adapter.setElementSize(this, size);
24515 this.animate = oldAnimate;
24519 * Destroy this splitbar.
24520 * @param {Boolean} removeEl True to remove the element
24522 destroy : function(removeEl){
24524 this.shim.remove();
24527 this.proxy.parentNode.removeChild(this.proxy);
24535 * @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.
24537 Roo.SplitBar.createProxy = function(dir){
24538 var proxy = new Roo.Element(document.createElement("div"));
24539 proxy.unselectable();
24540 var cls = 'x-splitbar-proxy';
24541 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24542 document.body.appendChild(proxy.dom);
24547 * @class Roo.SplitBar.BasicLayoutAdapter
24548 * Default Adapter. It assumes the splitter and resizing element are not positioned
24549 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24551 Roo.SplitBar.BasicLayoutAdapter = function(){
24554 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24555 // do nothing for now
24556 init : function(s){
24560 * Called before drag operations to get the current size of the resizing element.
24561 * @param {Roo.SplitBar} s The SplitBar using this adapter
24563 getElementSize : function(s){
24564 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24565 return s.resizingEl.getWidth();
24567 return s.resizingEl.getHeight();
24572 * Called after drag operations to set the size of the resizing element.
24573 * @param {Roo.SplitBar} s The SplitBar using this adapter
24574 * @param {Number} newSize The new size to set
24575 * @param {Function} onComplete A function to be invoked when resizing is complete
24577 setElementSize : function(s, newSize, onComplete){
24578 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24580 s.resizingEl.setWidth(newSize);
24582 onComplete(s, newSize);
24585 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24590 s.resizingEl.setHeight(newSize);
24592 onComplete(s, newSize);
24595 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24602 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24603 * @extends Roo.SplitBar.BasicLayoutAdapter
24604 * Adapter that moves the splitter element to align with the resized sizing element.
24605 * Used with an absolute positioned SplitBar.
24606 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24607 * document.body, make sure you assign an id to the body element.
24609 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24610 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24611 this.container = Roo.get(container);
24614 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24615 init : function(s){
24616 this.basic.init(s);
24619 getElementSize : function(s){
24620 return this.basic.getElementSize(s);
24623 setElementSize : function(s, newSize, onComplete){
24624 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24627 moveSplitter : function(s){
24628 var yes = Roo.SplitBar;
24629 switch(s.placement){
24631 s.el.setX(s.resizingEl.getRight());
24634 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24637 s.el.setY(s.resizingEl.getBottom());
24640 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24647 * Orientation constant - Create a vertical SplitBar
24651 Roo.SplitBar.VERTICAL = 1;
24654 * Orientation constant - Create a horizontal SplitBar
24658 Roo.SplitBar.HORIZONTAL = 2;
24661 * Placement constant - The resizing element is to the left of the splitter element
24665 Roo.SplitBar.LEFT = 1;
24668 * Placement constant - The resizing element is to the right of the splitter element
24672 Roo.SplitBar.RIGHT = 2;
24675 * Placement constant - The resizing element is positioned above the splitter element
24679 Roo.SplitBar.TOP = 3;
24682 * Placement constant - The resizing element is positioned under splitter element
24686 Roo.SplitBar.BOTTOM = 4;
24689 * Ext JS Library 1.1.1
24690 * Copyright(c) 2006-2007, Ext JS, LLC.
24692 * Originally Released Under LGPL - original licence link has changed is not relivant.
24695 * <script type="text/javascript">
24700 * @extends Roo.util.Observable
24701 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24702 * This class also supports single and multi selection modes. <br>
24703 * Create a data model bound view:
24705 var store = new Roo.data.Store(...);
24707 var view = new Roo.View({
24709 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24711 singleSelect: true,
24712 selectedClass: "ydataview-selected",
24716 // listen for node click?
24717 view.on("click", function(vw, index, node, e){
24718 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24722 dataModel.load("foobar.xml");
24724 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24726 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24727 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24729 * Note: old style constructor is still suported (container, template, config)
24732 * Create a new View
24733 * @param {Object} config The config object
24736 Roo.View = function(config, depreciated_tpl, depreciated_config){
24738 if (typeof(depreciated_tpl) == 'undefined') {
24739 // new way.. - universal constructor.
24740 Roo.apply(this, config);
24741 this.el = Roo.get(this.el);
24744 this.el = Roo.get(config);
24745 this.tpl = depreciated_tpl;
24746 Roo.apply(this, depreciated_config);
24748 this.wrapEl = this.el.wrap().wrap();
24749 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24752 if(typeof(this.tpl) == "string"){
24753 this.tpl = new Roo.Template(this.tpl);
24755 // support xtype ctors..
24756 this.tpl = new Roo.factory(this.tpl, Roo);
24760 this.tpl.compile();
24768 * @event beforeclick
24769 * Fires before a click is processed. Returns false to cancel the default action.
24770 * @param {Roo.View} this
24771 * @param {Number} index The index of the target node
24772 * @param {HTMLElement} node The target node
24773 * @param {Roo.EventObject} e The raw event object
24775 "beforeclick" : true,
24778 * Fires when a template node is clicked.
24779 * @param {Roo.View} this
24780 * @param {Number} index The index of the target node
24781 * @param {HTMLElement} node The target node
24782 * @param {Roo.EventObject} e The raw event object
24787 * Fires when a template node is double clicked.
24788 * @param {Roo.View} this
24789 * @param {Number} index The index of the target node
24790 * @param {HTMLElement} node The target node
24791 * @param {Roo.EventObject} e The raw event object
24795 * @event contextmenu
24796 * Fires when a template node is right clicked.
24797 * @param {Roo.View} this
24798 * @param {Number} index The index of the target node
24799 * @param {HTMLElement} node The target node
24800 * @param {Roo.EventObject} e The raw event object
24802 "contextmenu" : true,
24804 * @event selectionchange
24805 * Fires when the selected nodes change.
24806 * @param {Roo.View} this
24807 * @param {Array} selections Array of the selected nodes
24809 "selectionchange" : true,
24812 * @event beforeselect
24813 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24814 * @param {Roo.View} this
24815 * @param {HTMLElement} node The node to be selected
24816 * @param {Array} selections Array of currently selected nodes
24818 "beforeselect" : true,
24820 * @event preparedata
24821 * Fires on every row to render, to allow you to change the data.
24822 * @param {Roo.View} this
24823 * @param {Object} data to be rendered (change this)
24825 "preparedata" : true
24833 "click": this.onClick,
24834 "dblclick": this.onDblClick,
24835 "contextmenu": this.onContextMenu,
24839 this.selections = [];
24841 this.cmp = new Roo.CompositeElementLite([]);
24843 this.store = Roo.factory(this.store, Roo.data);
24844 this.setStore(this.store, true);
24847 if ( this.footer && this.footer.xtype) {
24849 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24851 this.footer.dataSource = this.store
24852 this.footer.container = fctr;
24853 this.footer = Roo.factory(this.footer, Roo);
24854 fctr.insertFirst(this.el);
24856 // this is a bit insane - as the paging toolbar seems to detach the el..
24857 // dom.parentNode.parentNode.parentNode
24858 // they get detached?
24862 Roo.View.superclass.constructor.call(this);
24867 Roo.extend(Roo.View, Roo.util.Observable, {
24870 * @cfg {Roo.data.Store} store Data store to load data from.
24875 * @cfg {String|Roo.Element} el The container element.
24880 * @cfg {String|Roo.Template} tpl The template used by this View
24884 * @cfg {String} dataName the named area of the template to use as the data area
24885 * Works with domtemplates roo-name="name"
24889 * @cfg {String} selectedClass The css class to add to selected nodes
24891 selectedClass : "x-view-selected",
24893 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24898 * @cfg {String} text to display on mask (default Loading)
24902 * @cfg {Boolean} multiSelect Allow multiple selection
24904 multiSelect : false,
24906 * @cfg {Boolean} singleSelect Allow single selection
24908 singleSelect: false,
24911 * @cfg {Boolean} toggleSelect - selecting
24913 toggleSelect : false,
24916 * Returns the element this view is bound to.
24917 * @return {Roo.Element}
24919 getEl : function(){
24920 return this.wrapEl;
24926 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24928 refresh : function(){
24931 // if we are using something like 'domtemplate', then
24932 // the what gets used is:
24933 // t.applySubtemplate(NAME, data, wrapping data..)
24934 // the outer template then get' applied with
24935 // the store 'extra data'
24936 // and the body get's added to the
24937 // roo-name="data" node?
24938 // <span class='roo-tpl-{name}'></span> ?????
24942 this.clearSelections();
24943 this.el.update("");
24945 var records = this.store.getRange();
24946 if(records.length < 1) {
24948 // is this valid?? = should it render a template??
24950 this.el.update(this.emptyText);
24954 if (this.dataName) {
24955 this.el.update(t.apply(this.store.meta)); //????
24956 el = this.el.child('.roo-tpl-' + this.dataName);
24959 for(var i = 0, len = records.length; i < len; i++){
24960 var data = this.prepareData(records[i].data, i, records[i]);
24961 this.fireEvent("preparedata", this, data, i, records[i]);
24962 html[html.length] = Roo.util.Format.trim(
24964 t.applySubtemplate(this.dataName, data, this.store.meta) :
24971 el.update(html.join(""));
24972 this.nodes = el.dom.childNodes;
24973 this.updateIndexes(0);
24977 * Function to override to reformat the data that is sent to
24978 * the template for each node.
24979 * DEPRICATED - use the preparedata event handler.
24980 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24981 * a JSON object for an UpdateManager bound view).
24983 prepareData : function(data, index, record)
24985 this.fireEvent("preparedata", this, data, index, record);
24989 onUpdate : function(ds, record){
24990 this.clearSelections();
24991 var index = this.store.indexOf(record);
24992 var n = this.nodes[index];
24993 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24994 n.parentNode.removeChild(n);
24995 this.updateIndexes(index, index);
25001 onAdd : function(ds, records, index)
25003 this.clearSelections();
25004 if(this.nodes.length == 0){
25008 var n = this.nodes[index];
25009 for(var i = 0, len = records.length; i < len; i++){
25010 var d = this.prepareData(records[i].data, i, records[i]);
25012 this.tpl.insertBefore(n, d);
25015 this.tpl.append(this.el, d);
25018 this.updateIndexes(index);
25021 onRemove : function(ds, record, index){
25022 this.clearSelections();
25023 var el = this.dataName ?
25024 this.el.child('.roo-tpl-' + this.dataName) :
25026 el.dom.removeChild(this.nodes[index]);
25027 this.updateIndexes(index);
25031 * Refresh an individual node.
25032 * @param {Number} index
25034 refreshNode : function(index){
25035 this.onUpdate(this.store, this.store.getAt(index));
25038 updateIndexes : function(startIndex, endIndex){
25039 var ns = this.nodes;
25040 startIndex = startIndex || 0;
25041 endIndex = endIndex || ns.length - 1;
25042 for(var i = startIndex; i <= endIndex; i++){
25043 ns[i].nodeIndex = i;
25048 * Changes the data store this view uses and refresh the view.
25049 * @param {Store} store
25051 setStore : function(store, initial){
25052 if(!initial && this.store){
25053 this.store.un("datachanged", this.refresh);
25054 this.store.un("add", this.onAdd);
25055 this.store.un("remove", this.onRemove);
25056 this.store.un("update", this.onUpdate);
25057 this.store.un("clear", this.refresh);
25058 this.store.un("beforeload", this.onBeforeLoad);
25059 this.store.un("load", this.onLoad);
25060 this.store.un("loadexception", this.onLoad);
25064 store.on("datachanged", this.refresh, this);
25065 store.on("add", this.onAdd, this);
25066 store.on("remove", this.onRemove, this);
25067 store.on("update", this.onUpdate, this);
25068 store.on("clear", this.refresh, this);
25069 store.on("beforeload", this.onBeforeLoad, this);
25070 store.on("load", this.onLoad, this);
25071 store.on("loadexception", this.onLoad, this);
25079 * onbeforeLoad - masks the loading area.
25082 onBeforeLoad : function()
25084 this.el.update("");
25085 this.el.mask(this.mask ? this.mask : "Loading" );
25087 onLoad : function ()
25094 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25095 * @param {HTMLElement} node
25096 * @return {HTMLElement} The template node
25098 findItemFromChild : function(node){
25099 var el = this.dataName ?
25100 this.el.child('.roo-tpl-' + this.dataName,true) :
25103 if(!node || node.parentNode == el){
25106 var p = node.parentNode;
25107 while(p && p != el){
25108 if(p.parentNode == el){
25117 onClick : function(e){
25118 var item = this.findItemFromChild(e.getTarget());
25120 var index = this.indexOf(item);
25121 if(this.onItemClick(item, index, e) !== false){
25122 this.fireEvent("click", this, index, item, e);
25125 this.clearSelections();
25130 onContextMenu : function(e){
25131 var item = this.findItemFromChild(e.getTarget());
25133 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25138 onDblClick : function(e){
25139 var item = this.findItemFromChild(e.getTarget());
25141 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25145 onItemClick : function(item, index, e)
25147 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25150 if (this.toggleSelect) {
25151 var m = this.isSelected(item) ? 'unselect' : 'select';
25154 _t[m](item, true, false);
25157 if(this.multiSelect || this.singleSelect){
25158 if(this.multiSelect && e.shiftKey && this.lastSelection){
25159 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25161 this.select(item, this.multiSelect && e.ctrlKey);
25162 this.lastSelection = item;
25164 e.preventDefault();
25170 * Get the number of selected nodes.
25173 getSelectionCount : function(){
25174 return this.selections.length;
25178 * Get the currently selected nodes.
25179 * @return {Array} An array of HTMLElements
25181 getSelectedNodes : function(){
25182 return this.selections;
25186 * Get the indexes of the selected nodes.
25189 getSelectedIndexes : function(){
25190 var indexes = [], s = this.selections;
25191 for(var i = 0, len = s.length; i < len; i++){
25192 indexes.push(s[i].nodeIndex);
25198 * Clear all selections
25199 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25201 clearSelections : function(suppressEvent){
25202 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25203 this.cmp.elements = this.selections;
25204 this.cmp.removeClass(this.selectedClass);
25205 this.selections = [];
25206 if(!suppressEvent){
25207 this.fireEvent("selectionchange", this, this.selections);
25213 * Returns true if the passed node is selected
25214 * @param {HTMLElement/Number} node The node or node index
25215 * @return {Boolean}
25217 isSelected : function(node){
25218 var s = this.selections;
25222 node = this.getNode(node);
25223 return s.indexOf(node) !== -1;
25228 * @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
25229 * @param {Boolean} keepExisting (optional) true to keep existing selections
25230 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25232 select : function(nodeInfo, keepExisting, suppressEvent){
25233 if(nodeInfo instanceof Array){
25235 this.clearSelections(true);
25237 for(var i = 0, len = nodeInfo.length; i < len; i++){
25238 this.select(nodeInfo[i], true, true);
25242 var node = this.getNode(nodeInfo);
25243 if(!node || this.isSelected(node)){
25244 return; // already selected.
25247 this.clearSelections(true);
25249 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25250 Roo.fly(node).addClass(this.selectedClass);
25251 this.selections.push(node);
25252 if(!suppressEvent){
25253 this.fireEvent("selectionchange", this, this.selections);
25261 * @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
25262 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25263 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25265 unselect : function(nodeInfo, keepExisting, suppressEvent)
25267 if(nodeInfo instanceof Array){
25268 Roo.each(this.selections, function(s) {
25269 this.unselect(s, nodeInfo);
25273 var node = this.getNode(nodeInfo);
25274 if(!node || !this.isSelected(node)){
25275 Roo.log("not selected");
25276 return; // not selected.
25280 Roo.each(this.selections, function(s) {
25282 Roo.fly(node).removeClass(this.selectedClass);
25289 this.selections= ns;
25290 this.fireEvent("selectionchange", this, this.selections);
25294 * Gets a template node.
25295 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25296 * @return {HTMLElement} The node or null if it wasn't found
25298 getNode : function(nodeInfo){
25299 if(typeof nodeInfo == "string"){
25300 return document.getElementById(nodeInfo);
25301 }else if(typeof nodeInfo == "number"){
25302 return this.nodes[nodeInfo];
25308 * Gets a range template nodes.
25309 * @param {Number} startIndex
25310 * @param {Number} endIndex
25311 * @return {Array} An array of nodes
25313 getNodes : function(start, end){
25314 var ns = this.nodes;
25315 start = start || 0;
25316 end = typeof end == "undefined" ? ns.length - 1 : end;
25319 for(var i = start; i <= end; i++){
25323 for(var i = start; i >= end; i--){
25331 * Finds the index of the passed node
25332 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25333 * @return {Number} The index of the node or -1
25335 indexOf : function(node){
25336 node = this.getNode(node);
25337 if(typeof node.nodeIndex == "number"){
25338 return node.nodeIndex;
25340 var ns = this.nodes;
25341 for(var i = 0, len = ns.length; i < len; i++){
25351 * Ext JS Library 1.1.1
25352 * Copyright(c) 2006-2007, Ext JS, LLC.
25354 * Originally Released Under LGPL - original licence link has changed is not relivant.
25357 * <script type="text/javascript">
25361 * @class Roo.JsonView
25362 * @extends Roo.View
25363 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25365 var view = new Roo.JsonView({
25366 container: "my-element",
25367 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25372 // listen for node click?
25373 view.on("click", function(vw, index, node, e){
25374 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25377 // direct load of JSON data
25378 view.load("foobar.php");
25380 // Example from my blog list
25381 var tpl = new Roo.Template(
25382 '<div class="entry">' +
25383 '<a class="entry-title" href="{link}">{title}</a>' +
25384 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25385 "</div><hr />"
25388 var moreView = new Roo.JsonView({
25389 container : "entry-list",
25393 moreView.on("beforerender", this.sortEntries, this);
25395 url: "/blog/get-posts.php",
25396 params: "allposts=true",
25397 text: "Loading Blog Entries..."
25401 * Note: old code is supported with arguments : (container, template, config)
25405 * Create a new JsonView
25407 * @param {Object} config The config object
25410 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25413 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25415 var um = this.el.getUpdateManager();
25416 um.setRenderer(this);
25417 um.on("update", this.onLoad, this);
25418 um.on("failure", this.onLoadException, this);
25421 * @event beforerender
25422 * Fires before rendering of the downloaded JSON data.
25423 * @param {Roo.JsonView} this
25424 * @param {Object} data The JSON data loaded
25428 * Fires when data is loaded.
25429 * @param {Roo.JsonView} this
25430 * @param {Object} data The JSON data loaded
25431 * @param {Object} response The raw Connect response object
25434 * @event loadexception
25435 * Fires when loading fails.
25436 * @param {Roo.JsonView} this
25437 * @param {Object} response The raw Connect response object
25440 'beforerender' : true,
25442 'loadexception' : true
25445 Roo.extend(Roo.JsonView, Roo.View, {
25447 * @type {String} The root property in the loaded JSON object that contains the data
25452 * Refreshes the view.
25454 refresh : function(){
25455 this.clearSelections();
25456 this.el.update("");
25458 var o = this.jsonData;
25459 if(o && o.length > 0){
25460 for(var i = 0, len = o.length; i < len; i++){
25461 var data = this.prepareData(o[i], i, o);
25462 html[html.length] = this.tpl.apply(data);
25465 html.push(this.emptyText);
25467 this.el.update(html.join(""));
25468 this.nodes = this.el.dom.childNodes;
25469 this.updateIndexes(0);
25473 * 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.
25474 * @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:
25477 url: "your-url.php",
25478 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25479 callback: yourFunction,
25480 scope: yourObject, //(optional scope)
25483 text: "Loading...",
25488 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25489 * 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.
25490 * @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}
25491 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25492 * @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.
25495 var um = this.el.getUpdateManager();
25496 um.update.apply(um, arguments);
25499 render : function(el, response){
25500 this.clearSelections();
25501 this.el.update("");
25504 o = Roo.util.JSON.decode(response.responseText);
25507 o = o[this.jsonRoot];
25512 * The current JSON data or null
25515 this.beforeRender();
25520 * Get the number of records in the current JSON dataset
25523 getCount : function(){
25524 return this.jsonData ? this.jsonData.length : 0;
25528 * Returns the JSON object for the specified node(s)
25529 * @param {HTMLElement/Array} node The node or an array of nodes
25530 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25531 * you get the JSON object for the node
25533 getNodeData : function(node){
25534 if(node instanceof Array){
25536 for(var i = 0, len = node.length; i < len; i++){
25537 data.push(this.getNodeData(node[i]));
25541 return this.jsonData[this.indexOf(node)] || null;
25544 beforeRender : function(){
25545 this.snapshot = this.jsonData;
25547 this.sort.apply(this, this.sortInfo);
25549 this.fireEvent("beforerender", this, this.jsonData);
25552 onLoad : function(el, o){
25553 this.fireEvent("load", this, this.jsonData, o);
25556 onLoadException : function(el, o){
25557 this.fireEvent("loadexception", this, o);
25561 * Filter the data by a specific property.
25562 * @param {String} property A property on your JSON objects
25563 * @param {String/RegExp} value Either string that the property values
25564 * should start with, or a RegExp to test against the property
25566 filter : function(property, value){
25569 var ss = this.snapshot;
25570 if(typeof value == "string"){
25571 var vlen = value.length;
25573 this.clearFilter();
25576 value = value.toLowerCase();
25577 for(var i = 0, len = ss.length; i < len; i++){
25579 if(o[property].substr(0, vlen).toLowerCase() == value){
25583 } else if(value.exec){ // regex?
25584 for(var i = 0, len = ss.length; i < len; i++){
25586 if(value.test(o[property])){
25593 this.jsonData = data;
25599 * Filter by a function. The passed function will be called with each
25600 * object in the current dataset. If the function returns true the value is kept,
25601 * otherwise it is filtered.
25602 * @param {Function} fn
25603 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25605 filterBy : function(fn, scope){
25608 var ss = this.snapshot;
25609 for(var i = 0, len = ss.length; i < len; i++){
25611 if(fn.call(scope || this, o)){
25615 this.jsonData = data;
25621 * Clears the current filter.
25623 clearFilter : function(){
25624 if(this.snapshot && this.jsonData != this.snapshot){
25625 this.jsonData = this.snapshot;
25632 * Sorts the data for this view and refreshes it.
25633 * @param {String} property A property on your JSON objects to sort on
25634 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25635 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25637 sort : function(property, dir, sortType){
25638 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25641 var dsc = dir && dir.toLowerCase() == "desc";
25642 var f = function(o1, o2){
25643 var v1 = sortType ? sortType(o1[p]) : o1[p];
25644 var v2 = sortType ? sortType(o2[p]) : o2[p];
25647 return dsc ? +1 : -1;
25648 } else if(v1 > v2){
25649 return dsc ? -1 : +1;
25654 this.jsonData.sort(f);
25656 if(this.jsonData != this.snapshot){
25657 this.snapshot.sort(f);
25663 * Ext JS Library 1.1.1
25664 * Copyright(c) 2006-2007, Ext JS, LLC.
25666 * Originally Released Under LGPL - original licence link has changed is not relivant.
25669 * <script type="text/javascript">
25674 * @class Roo.ColorPalette
25675 * @extends Roo.Component
25676 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25677 * Here's an example of typical usage:
25679 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25680 cp.render('my-div');
25682 cp.on('select', function(palette, selColor){
25683 // do something with selColor
25687 * Create a new ColorPalette
25688 * @param {Object} config The config object
25690 Roo.ColorPalette = function(config){
25691 Roo.ColorPalette.superclass.constructor.call(this, config);
25695 * Fires when a color is selected
25696 * @param {ColorPalette} this
25697 * @param {String} color The 6-digit color hex code (without the # symbol)
25703 this.on("select", this.handler, this.scope, true);
25706 Roo.extend(Roo.ColorPalette, Roo.Component, {
25708 * @cfg {String} itemCls
25709 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25711 itemCls : "x-color-palette",
25713 * @cfg {String} value
25714 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25715 * the hex codes are case-sensitive.
25718 clickEvent:'click',
25720 ctype: "Roo.ColorPalette",
25723 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25725 allowReselect : false,
25728 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25729 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25730 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25731 * of colors with the width setting until the box is symmetrical.</p>
25732 * <p>You can override individual colors if needed:</p>
25734 var cp = new Roo.ColorPalette();
25735 cp.colors[0] = "FF0000"; // change the first box to red
25738 Or you can provide a custom array of your own for complete control:
25740 var cp = new Roo.ColorPalette();
25741 cp.colors = ["000000", "993300", "333300"];
25746 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25747 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25748 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25749 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25750 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25754 onRender : function(container, position){
25755 var t = new Roo.MasterTemplate(
25756 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25758 var c = this.colors;
25759 for(var i = 0, len = c.length; i < len; i++){
25762 var el = document.createElement("div");
25763 el.className = this.itemCls;
25765 container.dom.insertBefore(el, position);
25766 this.el = Roo.get(el);
25767 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25768 if(this.clickEvent != 'click'){
25769 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25774 afterRender : function(){
25775 Roo.ColorPalette.superclass.afterRender.call(this);
25777 var s = this.value;
25784 handleClick : function(e, t){
25785 e.preventDefault();
25786 if(!this.disabled){
25787 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25788 this.select(c.toUpperCase());
25793 * Selects the specified color in the palette (fires the select event)
25794 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25796 select : function(color){
25797 color = color.replace("#", "");
25798 if(color != this.value || this.allowReselect){
25801 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25803 el.child("a.color-"+color).addClass("x-color-palette-sel");
25804 this.value = color;
25805 this.fireEvent("select", this, color);
25810 * Ext JS Library 1.1.1
25811 * Copyright(c) 2006-2007, Ext JS, LLC.
25813 * Originally Released Under LGPL - original licence link has changed is not relivant.
25816 * <script type="text/javascript">
25820 * @class Roo.DatePicker
25821 * @extends Roo.Component
25822 * Simple date picker class.
25824 * Create a new DatePicker
25825 * @param {Object} config The config object
25827 Roo.DatePicker = function(config){
25828 Roo.DatePicker.superclass.constructor.call(this, config);
25830 this.value = config && config.value ?
25831 config.value.clearTime() : new Date().clearTime();
25836 * Fires when a date is selected
25837 * @param {DatePicker} this
25838 * @param {Date} date The selected date
25842 * @event monthchange
25843 * Fires when the displayed month changes
25844 * @param {DatePicker} this
25845 * @param {Date} date The selected month
25847 'monthchange': true
25851 this.on("select", this.handler, this.scope || this);
25853 // build the disabledDatesRE
25854 if(!this.disabledDatesRE && this.disabledDates){
25855 var dd = this.disabledDates;
25857 for(var i = 0; i < dd.length; i++){
25859 if(i != dd.length-1) re += "|";
25861 this.disabledDatesRE = new RegExp(re + ")");
25865 Roo.extend(Roo.DatePicker, Roo.Component, {
25867 * @cfg {String} todayText
25868 * The text to display on the button that selects the current date (defaults to "Today")
25870 todayText : "Today",
25872 * @cfg {String} okText
25873 * The text to display on the ok button
25875 okText : " OK ", //   to give the user extra clicking room
25877 * @cfg {String} cancelText
25878 * The text to display on the cancel button
25880 cancelText : "Cancel",
25882 * @cfg {String} todayTip
25883 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25885 todayTip : "{0} (Spacebar)",
25887 * @cfg {Date} minDate
25888 * Minimum allowable date (JavaScript date object, defaults to null)
25892 * @cfg {Date} maxDate
25893 * Maximum allowable date (JavaScript date object, defaults to null)
25897 * @cfg {String} minText
25898 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25900 minText : "This date is before the minimum date",
25902 * @cfg {String} maxText
25903 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25905 maxText : "This date is after the maximum date",
25907 * @cfg {String} format
25908 * The default date format string which can be overriden for localization support. The format must be
25909 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25913 * @cfg {Array} disabledDays
25914 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25916 disabledDays : null,
25918 * @cfg {String} disabledDaysText
25919 * The tooltip to display when the date falls on a disabled day (defaults to "")
25921 disabledDaysText : "",
25923 * @cfg {RegExp} disabledDatesRE
25924 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25926 disabledDatesRE : null,
25928 * @cfg {String} disabledDatesText
25929 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25931 disabledDatesText : "",
25933 * @cfg {Boolean} constrainToViewport
25934 * True to constrain the date picker to the viewport (defaults to true)
25936 constrainToViewport : true,
25938 * @cfg {Array} monthNames
25939 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25941 monthNames : Date.monthNames,
25943 * @cfg {Array} dayNames
25944 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25946 dayNames : Date.dayNames,
25948 * @cfg {String} nextText
25949 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25951 nextText: 'Next Month (Control+Right)',
25953 * @cfg {String} prevText
25954 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25956 prevText: 'Previous Month (Control+Left)',
25958 * @cfg {String} monthYearText
25959 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25961 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25963 * @cfg {Number} startDay
25964 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25968 * @cfg {Bool} showClear
25969 * Show a clear button (usefull for date form elements that can be blank.)
25975 * Sets the value of the date field
25976 * @param {Date} value The date to set
25978 setValue : function(value){
25979 var old = this.value;
25981 if (typeof(value) == 'string') {
25983 value = Date.parseDate(value, this.format);
25986 value = new Date();
25989 this.value = value.clearTime(true);
25991 this.update(this.value);
25996 * Gets the current selected value of the date field
25997 * @return {Date} The selected date
25999 getValue : function(){
26004 focus : function(){
26006 this.update(this.activeDate);
26011 onRender : function(container, position){
26014 '<table cellspacing="0">',
26015 '<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>',
26016 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26017 var dn = this.dayNames;
26018 for(var i = 0; i < 7; i++){
26019 var d = this.startDay+i;
26023 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26025 m[m.length] = "</tr></thead><tbody><tr>";
26026 for(var i = 0; i < 42; i++) {
26027 if(i % 7 == 0 && i != 0){
26028 m[m.length] = "</tr><tr>";
26030 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26032 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26033 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26035 var el = document.createElement("div");
26036 el.className = "x-date-picker";
26037 el.innerHTML = m.join("");
26039 container.dom.insertBefore(el, position);
26041 this.el = Roo.get(el);
26042 this.eventEl = Roo.get(el.firstChild);
26044 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26045 handler: this.showPrevMonth,
26047 preventDefault:true,
26051 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26052 handler: this.showNextMonth,
26054 preventDefault:true,
26058 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26060 this.monthPicker = this.el.down('div.x-date-mp');
26061 this.monthPicker.enableDisplayMode('block');
26063 var kn = new Roo.KeyNav(this.eventEl, {
26064 "left" : function(e){
26066 this.showPrevMonth() :
26067 this.update(this.activeDate.add("d", -1));
26070 "right" : function(e){
26072 this.showNextMonth() :
26073 this.update(this.activeDate.add("d", 1));
26076 "up" : function(e){
26078 this.showNextYear() :
26079 this.update(this.activeDate.add("d", -7));
26082 "down" : function(e){
26084 this.showPrevYear() :
26085 this.update(this.activeDate.add("d", 7));
26088 "pageUp" : function(e){
26089 this.showNextMonth();
26092 "pageDown" : function(e){
26093 this.showPrevMonth();
26096 "enter" : function(e){
26097 e.stopPropagation();
26104 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26106 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26108 this.el.unselectable();
26110 this.cells = this.el.select("table.x-date-inner tbody td");
26111 this.textNodes = this.el.query("table.x-date-inner tbody span");
26113 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26115 tooltip: this.monthYearText
26118 this.mbtn.on('click', this.showMonthPicker, this);
26119 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26122 var today = (new Date()).dateFormat(this.format);
26124 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26125 if (this.showClear) {
26126 baseTb.add( new Roo.Toolbar.Fill());
26129 text: String.format(this.todayText, today),
26130 tooltip: String.format(this.todayTip, today),
26131 handler: this.selectToday,
26135 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26138 if (this.showClear) {
26140 baseTb.add( new Roo.Toolbar.Fill());
26143 cls: 'x-btn-icon x-btn-clear',
26144 handler: function() {
26146 this.fireEvent("select", this, '');
26156 this.update(this.value);
26159 createMonthPicker : function(){
26160 if(!this.monthPicker.dom.firstChild){
26161 var buf = ['<table border="0" cellspacing="0">'];
26162 for(var i = 0; i < 6; i++){
26164 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26165 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26167 '<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>' :
26168 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26172 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26174 '</button><button type="button" class="x-date-mp-cancel">',
26176 '</button></td></tr>',
26179 this.monthPicker.update(buf.join(''));
26180 this.monthPicker.on('click', this.onMonthClick, this);
26181 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26183 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26184 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26186 this.mpMonths.each(function(m, a, i){
26189 m.dom.xmonth = 5 + Math.round(i * .5);
26191 m.dom.xmonth = Math.round((i-1) * .5);
26197 showMonthPicker : function(){
26198 this.createMonthPicker();
26199 var size = this.el.getSize();
26200 this.monthPicker.setSize(size);
26201 this.monthPicker.child('table').setSize(size);
26203 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26204 this.updateMPMonth(this.mpSelMonth);
26205 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26206 this.updateMPYear(this.mpSelYear);
26208 this.monthPicker.slideIn('t', {duration:.2});
26211 updateMPYear : function(y){
26213 var ys = this.mpYears.elements;
26214 for(var i = 1; i <= 10; i++){
26215 var td = ys[i-1], y2;
26217 y2 = y + Math.round(i * .5);
26218 td.firstChild.innerHTML = y2;
26221 y2 = y - (5-Math.round(i * .5));
26222 td.firstChild.innerHTML = y2;
26225 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26229 updateMPMonth : function(sm){
26230 this.mpMonths.each(function(m, a, i){
26231 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26235 selectMPMonth: function(m){
26239 onMonthClick : function(e, t){
26241 var el = new Roo.Element(t), pn;
26242 if(el.is('button.x-date-mp-cancel')){
26243 this.hideMonthPicker();
26245 else if(el.is('button.x-date-mp-ok')){
26246 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26247 this.hideMonthPicker();
26249 else if(pn = el.up('td.x-date-mp-month', 2)){
26250 this.mpMonths.removeClass('x-date-mp-sel');
26251 pn.addClass('x-date-mp-sel');
26252 this.mpSelMonth = pn.dom.xmonth;
26254 else if(pn = el.up('td.x-date-mp-year', 2)){
26255 this.mpYears.removeClass('x-date-mp-sel');
26256 pn.addClass('x-date-mp-sel');
26257 this.mpSelYear = pn.dom.xyear;
26259 else if(el.is('a.x-date-mp-prev')){
26260 this.updateMPYear(this.mpyear-10);
26262 else if(el.is('a.x-date-mp-next')){
26263 this.updateMPYear(this.mpyear+10);
26267 onMonthDblClick : function(e, t){
26269 var el = new Roo.Element(t), pn;
26270 if(pn = el.up('td.x-date-mp-month', 2)){
26271 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26272 this.hideMonthPicker();
26274 else if(pn = el.up('td.x-date-mp-year', 2)){
26275 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26276 this.hideMonthPicker();
26280 hideMonthPicker : function(disableAnim){
26281 if(this.monthPicker){
26282 if(disableAnim === true){
26283 this.monthPicker.hide();
26285 this.monthPicker.slideOut('t', {duration:.2});
26291 showPrevMonth : function(e){
26292 this.update(this.activeDate.add("mo", -1));
26296 showNextMonth : function(e){
26297 this.update(this.activeDate.add("mo", 1));
26301 showPrevYear : function(){
26302 this.update(this.activeDate.add("y", -1));
26306 showNextYear : function(){
26307 this.update(this.activeDate.add("y", 1));
26311 handleMouseWheel : function(e){
26312 var delta = e.getWheelDelta();
26314 this.showPrevMonth();
26316 } else if(delta < 0){
26317 this.showNextMonth();
26323 handleDateClick : function(e, t){
26325 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26326 this.setValue(new Date(t.dateValue));
26327 this.fireEvent("select", this, this.value);
26332 selectToday : function(){
26333 this.setValue(new Date().clearTime());
26334 this.fireEvent("select", this, this.value);
26338 update : function(date)
26340 var vd = this.activeDate;
26341 this.activeDate = date;
26343 var t = date.getTime();
26344 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26345 this.cells.removeClass("x-date-selected");
26346 this.cells.each(function(c){
26347 if(c.dom.firstChild.dateValue == t){
26348 c.addClass("x-date-selected");
26349 setTimeout(function(){
26350 try{c.dom.firstChild.focus();}catch(e){}
26359 var days = date.getDaysInMonth();
26360 var firstOfMonth = date.getFirstDateOfMonth();
26361 var startingPos = firstOfMonth.getDay()-this.startDay;
26363 if(startingPos <= this.startDay){
26367 var pm = date.add("mo", -1);
26368 var prevStart = pm.getDaysInMonth()-startingPos;
26370 var cells = this.cells.elements;
26371 var textEls = this.textNodes;
26372 days += startingPos;
26374 // convert everything to numbers so it's fast
26375 var day = 86400000;
26376 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26377 var today = new Date().clearTime().getTime();
26378 var sel = date.clearTime().getTime();
26379 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26380 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26381 var ddMatch = this.disabledDatesRE;
26382 var ddText = this.disabledDatesText;
26383 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26384 var ddaysText = this.disabledDaysText;
26385 var format = this.format;
26387 var setCellClass = function(cal, cell){
26389 var t = d.getTime();
26390 cell.firstChild.dateValue = t;
26392 cell.className += " x-date-today";
26393 cell.title = cal.todayText;
26396 cell.className += " x-date-selected";
26397 setTimeout(function(){
26398 try{cell.firstChild.focus();}catch(e){}
26403 cell.className = " x-date-disabled";
26404 cell.title = cal.minText;
26408 cell.className = " x-date-disabled";
26409 cell.title = cal.maxText;
26413 if(ddays.indexOf(d.getDay()) != -1){
26414 cell.title = ddaysText;
26415 cell.className = " x-date-disabled";
26418 if(ddMatch && format){
26419 var fvalue = d.dateFormat(format);
26420 if(ddMatch.test(fvalue)){
26421 cell.title = ddText.replace("%0", fvalue);
26422 cell.className = " x-date-disabled";
26428 for(; i < startingPos; i++) {
26429 textEls[i].innerHTML = (++prevStart);
26430 d.setDate(d.getDate()+1);
26431 cells[i].className = "x-date-prevday";
26432 setCellClass(this, cells[i]);
26434 for(; i < days; i++){
26435 intDay = i - startingPos + 1;
26436 textEls[i].innerHTML = (intDay);
26437 d.setDate(d.getDate()+1);
26438 cells[i].className = "x-date-active";
26439 setCellClass(this, cells[i]);
26442 for(; i < 42; i++) {
26443 textEls[i].innerHTML = (++extraDays);
26444 d.setDate(d.getDate()+1);
26445 cells[i].className = "x-date-nextday";
26446 setCellClass(this, cells[i]);
26449 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26450 this.fireEvent('monthchange', this, date);
26452 if(!this.internalRender){
26453 var main = this.el.dom.firstChild;
26454 var w = main.offsetWidth;
26455 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26456 Roo.fly(main).setWidth(w);
26457 this.internalRender = true;
26458 // opera does not respect the auto grow header center column
26459 // then, after it gets a width opera refuses to recalculate
26460 // without a second pass
26461 if(Roo.isOpera && !this.secondPass){
26462 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26463 this.secondPass = true;
26464 this.update.defer(10, this, [date]);
26472 * Ext JS Library 1.1.1
26473 * Copyright(c) 2006-2007, Ext JS, LLC.
26475 * Originally Released Under LGPL - original licence link has changed is not relivant.
26478 * <script type="text/javascript">
26481 * @class Roo.TabPanel
26482 * @extends Roo.util.Observable
26483 * A lightweight tab container.
26487 // basic tabs 1, built from existing content
26488 var tabs = new Roo.TabPanel("tabs1");
26489 tabs.addTab("script", "View Script");
26490 tabs.addTab("markup", "View Markup");
26491 tabs.activate("script");
26493 // more advanced tabs, built from javascript
26494 var jtabs = new Roo.TabPanel("jtabs");
26495 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26497 // set up the UpdateManager
26498 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26499 var updater = tab2.getUpdateManager();
26500 updater.setDefaultUrl("ajax1.htm");
26501 tab2.on('activate', updater.refresh, updater, true);
26503 // Use setUrl for Ajax loading
26504 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26505 tab3.setUrl("ajax2.htm", null, true);
26508 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26511 jtabs.activate("jtabs-1");
26514 * Create a new TabPanel.
26515 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26516 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26518 Roo.TabPanel = function(container, config){
26520 * The container element for this TabPanel.
26521 * @type Roo.Element
26523 this.el = Roo.get(container, true);
26525 if(typeof config == "boolean"){
26526 this.tabPosition = config ? "bottom" : "top";
26528 Roo.apply(this, config);
26531 if(this.tabPosition == "bottom"){
26532 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26533 this.el.addClass("x-tabs-bottom");
26535 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26536 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26537 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26539 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26541 if(this.tabPosition != "bottom"){
26542 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26543 * @type Roo.Element
26545 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26546 this.el.addClass("x-tabs-top");
26550 this.bodyEl.setStyle("position", "relative");
26552 this.active = null;
26553 this.activateDelegate = this.activate.createDelegate(this);
26558 * Fires when the active tab changes
26559 * @param {Roo.TabPanel} this
26560 * @param {Roo.TabPanelItem} activePanel The new active tab
26564 * @event beforetabchange
26565 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26566 * @param {Roo.TabPanel} this
26567 * @param {Object} e Set cancel to true on this object to cancel the tab change
26568 * @param {Roo.TabPanelItem} tab The tab being changed to
26570 "beforetabchange" : true
26573 Roo.EventManager.onWindowResize(this.onResize, this);
26574 this.cpad = this.el.getPadding("lr");
26575 this.hiddenCount = 0;
26578 // toolbar on the tabbar support...
26579 if (this.toolbar) {
26580 var tcfg = this.toolbar;
26581 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26582 this.toolbar = new Roo.Toolbar(tcfg);
26583 if (Roo.isSafari) {
26584 var tbl = tcfg.container.child('table', true);
26585 tbl.setAttribute('width', '100%');
26592 Roo.TabPanel.superclass.constructor.call(this);
26595 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26597 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26599 tabPosition : "top",
26601 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26603 currentTabWidth : 0,
26605 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26609 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26613 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26615 preferredTabWidth : 175,
26617 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26619 resizeTabs : false,
26621 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26623 monitorResize : true,
26625 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26630 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26631 * @param {String} id The id of the div to use <b>or create</b>
26632 * @param {String} text The text for the tab
26633 * @param {String} content (optional) Content to put in the TabPanelItem body
26634 * @param {Boolean} closable (optional) True to create a close icon on the tab
26635 * @return {Roo.TabPanelItem} The created TabPanelItem
26637 addTab : function(id, text, content, closable){
26638 var item = new Roo.TabPanelItem(this, id, text, closable);
26639 this.addTabItem(item);
26641 item.setContent(content);
26647 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26648 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26649 * @return {Roo.TabPanelItem}
26651 getTab : function(id){
26652 return this.items[id];
26656 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26657 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26659 hideTab : function(id){
26660 var t = this.items[id];
26663 this.hiddenCount++;
26664 this.autoSizeTabs();
26669 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26670 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26672 unhideTab : function(id){
26673 var t = this.items[id];
26675 t.setHidden(false);
26676 this.hiddenCount--;
26677 this.autoSizeTabs();
26682 * Adds an existing {@link Roo.TabPanelItem}.
26683 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26685 addTabItem : function(item){
26686 this.items[item.id] = item;
26687 this.items.push(item);
26688 if(this.resizeTabs){
26689 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26690 this.autoSizeTabs();
26697 * Removes a {@link Roo.TabPanelItem}.
26698 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26700 removeTab : function(id){
26701 var items = this.items;
26702 var tab = items[id];
26703 if(!tab) { return; }
26704 var index = items.indexOf(tab);
26705 if(this.active == tab && items.length > 1){
26706 var newTab = this.getNextAvailable(index);
26711 this.stripEl.dom.removeChild(tab.pnode.dom);
26712 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26713 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26715 items.splice(index, 1);
26716 delete this.items[tab.id];
26717 tab.fireEvent("close", tab);
26718 tab.purgeListeners();
26719 this.autoSizeTabs();
26722 getNextAvailable : function(start){
26723 var items = this.items;
26725 // look for a next tab that will slide over to
26726 // replace the one being removed
26727 while(index < items.length){
26728 var item = items[++index];
26729 if(item && !item.isHidden()){
26733 // if one isn't found select the previous tab (on the left)
26736 var item = items[--index];
26737 if(item && !item.isHidden()){
26745 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26746 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26748 disableTab : function(id){
26749 var tab = this.items[id];
26750 if(tab && this.active != tab){
26756 * Enables a {@link Roo.TabPanelItem} that is disabled.
26757 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26759 enableTab : function(id){
26760 var tab = this.items[id];
26765 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26766 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26767 * @return {Roo.TabPanelItem} The TabPanelItem.
26769 activate : function(id){
26770 var tab = this.items[id];
26774 if(tab == this.active || tab.disabled){
26778 this.fireEvent("beforetabchange", this, e, tab);
26779 if(e.cancel !== true && !tab.disabled){
26781 this.active.hide();
26783 this.active = this.items[id];
26784 this.active.show();
26785 this.fireEvent("tabchange", this, this.active);
26791 * Gets the active {@link Roo.TabPanelItem}.
26792 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26794 getActiveTab : function(){
26795 return this.active;
26799 * Updates the tab body element to fit the height of the container element
26800 * for overflow scrolling
26801 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26803 syncHeight : function(targetHeight){
26804 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26805 var bm = this.bodyEl.getMargins();
26806 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26807 this.bodyEl.setHeight(newHeight);
26811 onResize : function(){
26812 if(this.monitorResize){
26813 this.autoSizeTabs();
26818 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26820 beginUpdate : function(){
26821 this.updating = true;
26825 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26827 endUpdate : function(){
26828 this.updating = false;
26829 this.autoSizeTabs();
26833 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26835 autoSizeTabs : function(){
26836 var count = this.items.length;
26837 var vcount = count - this.hiddenCount;
26838 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26839 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26840 var availWidth = Math.floor(w / vcount);
26841 var b = this.stripBody;
26842 if(b.getWidth() > w){
26843 var tabs = this.items;
26844 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26845 if(availWidth < this.minTabWidth){
26846 /*if(!this.sleft){ // incomplete scrolling code
26847 this.createScrollButtons();
26850 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26853 if(this.currentTabWidth < this.preferredTabWidth){
26854 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26860 * Returns the number of tabs in this TabPanel.
26863 getCount : function(){
26864 return this.items.length;
26868 * Resizes all the tabs to the passed width
26869 * @param {Number} The new width
26871 setTabWidth : function(width){
26872 this.currentTabWidth = width;
26873 for(var i = 0, len = this.items.length; i < len; i++) {
26874 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26879 * Destroys this TabPanel
26880 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26882 destroy : function(removeEl){
26883 Roo.EventManager.removeResizeListener(this.onResize, this);
26884 for(var i = 0, len = this.items.length; i < len; i++){
26885 this.items[i].purgeListeners();
26887 if(removeEl === true){
26888 this.el.update("");
26895 * @class Roo.TabPanelItem
26896 * @extends Roo.util.Observable
26897 * Represents an individual item (tab plus body) in a TabPanel.
26898 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26899 * @param {String} id The id of this TabPanelItem
26900 * @param {String} text The text for the tab of this TabPanelItem
26901 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26903 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26905 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26906 * @type Roo.TabPanel
26908 this.tabPanel = tabPanel;
26910 * The id for this TabPanelItem
26915 this.disabled = false;
26919 this.loaded = false;
26920 this.closable = closable;
26923 * The body element for this TabPanelItem.
26924 * @type Roo.Element
26926 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26927 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26928 this.bodyEl.setStyle("display", "block");
26929 this.bodyEl.setStyle("zoom", "1");
26932 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26934 this.el = Roo.get(els.el, true);
26935 this.inner = Roo.get(els.inner, true);
26936 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26937 this.pnode = Roo.get(els.el.parentNode, true);
26938 this.el.on("mousedown", this.onTabMouseDown, this);
26939 this.el.on("click", this.onTabClick, this);
26942 var c = Roo.get(els.close, true);
26943 c.dom.title = this.closeText;
26944 c.addClassOnOver("close-over");
26945 c.on("click", this.closeClick, this);
26951 * Fires when this tab becomes the active tab.
26952 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26953 * @param {Roo.TabPanelItem} this
26957 * @event beforeclose
26958 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26959 * @param {Roo.TabPanelItem} this
26960 * @param {Object} e Set cancel to true on this object to cancel the close.
26962 "beforeclose": true,
26965 * Fires when this tab is closed.
26966 * @param {Roo.TabPanelItem} this
26970 * @event deactivate
26971 * Fires when this tab is no longer the active tab.
26972 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26973 * @param {Roo.TabPanelItem} this
26975 "deactivate" : true
26977 this.hidden = false;
26979 Roo.TabPanelItem.superclass.constructor.call(this);
26982 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26983 purgeListeners : function(){
26984 Roo.util.Observable.prototype.purgeListeners.call(this);
26985 this.el.removeAllListeners();
26988 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26991 this.pnode.addClass("on");
26994 this.tabPanel.stripWrap.repaint();
26996 this.fireEvent("activate", this.tabPanel, this);
27000 * Returns true if this tab is the active tab.
27001 * @return {Boolean}
27003 isActive : function(){
27004 return this.tabPanel.getActiveTab() == this;
27008 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27011 this.pnode.removeClass("on");
27013 this.fireEvent("deactivate", this.tabPanel, this);
27016 hideAction : function(){
27017 this.bodyEl.hide();
27018 this.bodyEl.setStyle("position", "absolute");
27019 this.bodyEl.setLeft("-20000px");
27020 this.bodyEl.setTop("-20000px");
27023 showAction : function(){
27024 this.bodyEl.setStyle("position", "relative");
27025 this.bodyEl.setTop("");
27026 this.bodyEl.setLeft("");
27027 this.bodyEl.show();
27031 * Set the tooltip for the tab.
27032 * @param {String} tooltip The tab's tooltip
27034 setTooltip : function(text){
27035 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27036 this.textEl.dom.qtip = text;
27037 this.textEl.dom.removeAttribute('title');
27039 this.textEl.dom.title = text;
27043 onTabClick : function(e){
27044 e.preventDefault();
27045 this.tabPanel.activate(this.id);
27048 onTabMouseDown : function(e){
27049 e.preventDefault();
27050 this.tabPanel.activate(this.id);
27053 getWidth : function(){
27054 return this.inner.getWidth();
27057 setWidth : function(width){
27058 var iwidth = width - this.pnode.getPadding("lr");
27059 this.inner.setWidth(iwidth);
27060 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27061 this.pnode.setWidth(width);
27065 * Show or hide the tab
27066 * @param {Boolean} hidden True to hide or false to show.
27068 setHidden : function(hidden){
27069 this.hidden = hidden;
27070 this.pnode.setStyle("display", hidden ? "none" : "");
27074 * Returns true if this tab is "hidden"
27075 * @return {Boolean}
27077 isHidden : function(){
27078 return this.hidden;
27082 * Returns the text for this tab
27085 getText : function(){
27089 autoSize : function(){
27090 //this.el.beginMeasure();
27091 this.textEl.setWidth(1);
27092 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27093 //this.el.endMeasure();
27097 * Sets the text for the tab (Note: this also sets the tooltip text)
27098 * @param {String} text The tab's text and tooltip
27100 setText : function(text){
27102 this.textEl.update(text);
27103 this.setTooltip(text);
27104 if(!this.tabPanel.resizeTabs){
27109 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27111 activate : function(){
27112 this.tabPanel.activate(this.id);
27116 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27118 disable : function(){
27119 if(this.tabPanel.active != this){
27120 this.disabled = true;
27121 this.pnode.addClass("disabled");
27126 * Enables this TabPanelItem if it was previously disabled.
27128 enable : function(){
27129 this.disabled = false;
27130 this.pnode.removeClass("disabled");
27134 * Sets the content for this TabPanelItem.
27135 * @param {String} content The content
27136 * @param {Boolean} loadScripts true to look for and load scripts
27138 setContent : function(content, loadScripts){
27139 this.bodyEl.update(content, loadScripts);
27143 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27144 * @return {Roo.UpdateManager} The UpdateManager
27146 getUpdateManager : function(){
27147 return this.bodyEl.getUpdateManager();
27151 * Set a URL to be used to load the content for this TabPanelItem.
27152 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27153 * @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)
27154 * @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)
27155 * @return {Roo.UpdateManager} The UpdateManager
27157 setUrl : function(url, params, loadOnce){
27158 if(this.refreshDelegate){
27159 this.un('activate', this.refreshDelegate);
27161 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27162 this.on("activate", this.refreshDelegate);
27163 return this.bodyEl.getUpdateManager();
27167 _handleRefresh : function(url, params, loadOnce){
27168 if(!loadOnce || !this.loaded){
27169 var updater = this.bodyEl.getUpdateManager();
27170 updater.update(url, params, this._setLoaded.createDelegate(this));
27175 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27176 * Will fail silently if the setUrl method has not been called.
27177 * This does not activate the panel, just updates its content.
27179 refresh : function(){
27180 if(this.refreshDelegate){
27181 this.loaded = false;
27182 this.refreshDelegate();
27187 _setLoaded : function(){
27188 this.loaded = true;
27192 closeClick : function(e){
27195 this.fireEvent("beforeclose", this, o);
27196 if(o.cancel !== true){
27197 this.tabPanel.removeTab(this.id);
27201 * The text displayed in the tooltip for the close icon.
27204 closeText : "Close this tab"
27208 Roo.TabPanel.prototype.createStrip = function(container){
27209 var strip = document.createElement("div");
27210 strip.className = "x-tabs-wrap";
27211 container.appendChild(strip);
27215 Roo.TabPanel.prototype.createStripList = function(strip){
27216 // div wrapper for retard IE
27217 // returns the "tr" element.
27218 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27219 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27220 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27221 return strip.firstChild.firstChild.firstChild.firstChild;
27224 Roo.TabPanel.prototype.createBody = function(container){
27225 var body = document.createElement("div");
27226 Roo.id(body, "tab-body");
27227 Roo.fly(body).addClass("x-tabs-body");
27228 container.appendChild(body);
27232 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27233 var body = Roo.getDom(id);
27235 body = document.createElement("div");
27238 Roo.fly(body).addClass("x-tabs-item-body");
27239 bodyEl.insertBefore(body, bodyEl.firstChild);
27243 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27244 var td = document.createElement("td");
27245 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27246 //stripEl.appendChild(td);
27248 td.className = "x-tabs-closable";
27249 if(!this.closeTpl){
27250 this.closeTpl = new Roo.Template(
27251 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27252 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27253 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27256 var el = this.closeTpl.overwrite(td, {"text": text});
27257 var close = el.getElementsByTagName("div")[0];
27258 var inner = el.getElementsByTagName("em")[0];
27259 return {"el": el, "close": close, "inner": inner};
27262 this.tabTpl = new Roo.Template(
27263 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27264 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27267 var el = this.tabTpl.overwrite(td, {"text": text});
27268 var inner = el.getElementsByTagName("em")[0];
27269 return {"el": el, "inner": inner};
27273 * Ext JS Library 1.1.1
27274 * Copyright(c) 2006-2007, Ext JS, LLC.
27276 * Originally Released Under LGPL - original licence link has changed is not relivant.
27279 * <script type="text/javascript">
27283 * @class Roo.Button
27284 * @extends Roo.util.Observable
27285 * Simple Button class
27286 * @cfg {String} text The button text
27287 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27288 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27289 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27290 * @cfg {Object} scope The scope of the handler
27291 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27292 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27293 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27294 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27295 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27296 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27297 applies if enableToggle = true)
27298 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27299 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27300 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27302 * Create a new button
27303 * @param {Object} config The config object
27305 Roo.Button = function(renderTo, config)
27309 renderTo = config.renderTo || false;
27312 Roo.apply(this, config);
27316 * Fires when this button is clicked
27317 * @param {Button} this
27318 * @param {EventObject} e The click event
27323 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27324 * @param {Button} this
27325 * @param {Boolean} pressed
27330 * Fires when the mouse hovers over the button
27331 * @param {Button} this
27332 * @param {Event} e The event object
27334 'mouseover' : true,
27337 * Fires when the mouse exits the button
27338 * @param {Button} this
27339 * @param {Event} e The event object
27344 * Fires when the button is rendered
27345 * @param {Button} this
27350 this.menu = Roo.menu.MenuMgr.get(this.menu);
27352 // register listeners first!! - so render can be captured..
27353 Roo.util.Observable.call(this);
27355 this.render(renderTo);
27361 Roo.extend(Roo.Button, Roo.util.Observable, {
27367 * Read-only. True if this button is hidden
27372 * Read-only. True if this button is disabled
27377 * Read-only. True if this button is pressed (only if enableToggle = true)
27383 * @cfg {Number} tabIndex
27384 * The DOM tabIndex for this button (defaults to undefined)
27386 tabIndex : undefined,
27389 * @cfg {Boolean} enableToggle
27390 * True to enable pressed/not pressed toggling (defaults to false)
27392 enableToggle: false,
27394 * @cfg {Mixed} menu
27395 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27399 * @cfg {String} menuAlign
27400 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27402 menuAlign : "tl-bl?",
27405 * @cfg {String} iconCls
27406 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27408 iconCls : undefined,
27410 * @cfg {String} type
27411 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27416 menuClassTarget: 'tr',
27419 * @cfg {String} clickEvent
27420 * The type of event to map to the button's event handler (defaults to 'click')
27422 clickEvent : 'click',
27425 * @cfg {Boolean} handleMouseEvents
27426 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27428 handleMouseEvents : true,
27431 * @cfg {String} tooltipType
27432 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27434 tooltipType : 'qtip',
27437 * @cfg {String} cls
27438 * A CSS class to apply to the button's main element.
27442 * @cfg {Roo.Template} template (Optional)
27443 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27444 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27445 * require code modifications if required elements (e.g. a button) aren't present.
27449 render : function(renderTo){
27451 if(this.hideParent){
27452 this.parentEl = Roo.get(renderTo);
27454 if(!this.dhconfig){
27455 if(!this.template){
27456 if(!Roo.Button.buttonTemplate){
27457 // hideous table template
27458 Roo.Button.buttonTemplate = new Roo.Template(
27459 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27460 '<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>',
27461 "</tr></tbody></table>");
27463 this.template = Roo.Button.buttonTemplate;
27465 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27466 var btnEl = btn.child("button:first");
27467 btnEl.on('focus', this.onFocus, this);
27468 btnEl.on('blur', this.onBlur, this);
27470 btn.addClass(this.cls);
27473 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27476 btnEl.addClass(this.iconCls);
27478 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27481 if(this.tabIndex !== undefined){
27482 btnEl.dom.tabIndex = this.tabIndex;
27485 if(typeof this.tooltip == 'object'){
27486 Roo.QuickTips.tips(Roo.apply({
27490 btnEl.dom[this.tooltipType] = this.tooltip;
27494 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27498 this.el.dom.id = this.el.id = this.id;
27501 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27502 this.menu.on("show", this.onMenuShow, this);
27503 this.menu.on("hide", this.onMenuHide, this);
27505 btn.addClass("x-btn");
27506 if(Roo.isIE && !Roo.isIE7){
27507 this.autoWidth.defer(1, this);
27511 if(this.handleMouseEvents){
27512 btn.on("mouseover", this.onMouseOver, this);
27513 btn.on("mouseout", this.onMouseOut, this);
27514 btn.on("mousedown", this.onMouseDown, this);
27516 btn.on(this.clickEvent, this.onClick, this);
27517 //btn.on("mouseup", this.onMouseUp, this);
27524 Roo.ButtonToggleMgr.register(this);
27526 this.el.addClass("x-btn-pressed");
27529 var repeater = new Roo.util.ClickRepeater(btn,
27530 typeof this.repeat == "object" ? this.repeat : {}
27532 repeater.on("click", this.onClick, this);
27535 this.fireEvent('render', this);
27539 * Returns the button's underlying element
27540 * @return {Roo.Element} The element
27542 getEl : function(){
27547 * Destroys this Button and removes any listeners.
27549 destroy : function(){
27550 Roo.ButtonToggleMgr.unregister(this);
27551 this.el.removeAllListeners();
27552 this.purgeListeners();
27557 autoWidth : function(){
27559 this.el.setWidth("auto");
27560 if(Roo.isIE7 && Roo.isStrict){
27561 var ib = this.el.child('button');
27562 if(ib && ib.getWidth() > 20){
27564 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27569 this.el.beginMeasure();
27571 if(this.el.getWidth() < this.minWidth){
27572 this.el.setWidth(this.minWidth);
27575 this.el.endMeasure();
27582 * Assigns this button's click handler
27583 * @param {Function} handler The function to call when the button is clicked
27584 * @param {Object} scope (optional) Scope for the function passed in
27586 setHandler : function(handler, scope){
27587 this.handler = handler;
27588 this.scope = scope;
27592 * Sets this button's text
27593 * @param {String} text The button text
27595 setText : function(text){
27598 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27604 * Gets the text for this button
27605 * @return {String} The button text
27607 getText : function(){
27615 this.hidden = false;
27617 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27625 this.hidden = true;
27627 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27632 * Convenience function for boolean show/hide
27633 * @param {Boolean} visible True to show, false to hide
27635 setVisible: function(visible){
27644 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27645 * @param {Boolean} state (optional) Force a particular state
27647 toggle : function(state){
27648 state = state === undefined ? !this.pressed : state;
27649 if(state != this.pressed){
27651 this.el.addClass("x-btn-pressed");
27652 this.pressed = true;
27653 this.fireEvent("toggle", this, true);
27655 this.el.removeClass("x-btn-pressed");
27656 this.pressed = false;
27657 this.fireEvent("toggle", this, false);
27659 if(this.toggleHandler){
27660 this.toggleHandler.call(this.scope || this, this, state);
27668 focus : function(){
27669 this.el.child('button:first').focus();
27673 * Disable this button
27675 disable : function(){
27677 this.el.addClass("x-btn-disabled");
27679 this.disabled = true;
27683 * Enable this button
27685 enable : function(){
27687 this.el.removeClass("x-btn-disabled");
27689 this.disabled = false;
27693 * Convenience function for boolean enable/disable
27694 * @param {Boolean} enabled True to enable, false to disable
27696 setDisabled : function(v){
27697 this[v !== true ? "enable" : "disable"]();
27701 onClick : function(e){
27703 e.preventDefault();
27708 if(!this.disabled){
27709 if(this.enableToggle){
27712 if(this.menu && !this.menu.isVisible()){
27713 this.menu.show(this.el, this.menuAlign);
27715 this.fireEvent("click", this, e);
27717 this.el.removeClass("x-btn-over");
27718 this.handler.call(this.scope || this, this, e);
27723 onMouseOver : function(e){
27724 if(!this.disabled){
27725 this.el.addClass("x-btn-over");
27726 this.fireEvent('mouseover', this, e);
27730 onMouseOut : function(e){
27731 if(!e.within(this.el, true)){
27732 this.el.removeClass("x-btn-over");
27733 this.fireEvent('mouseout', this, e);
27737 onFocus : function(e){
27738 if(!this.disabled){
27739 this.el.addClass("x-btn-focus");
27743 onBlur : function(e){
27744 this.el.removeClass("x-btn-focus");
27747 onMouseDown : function(e){
27748 if(!this.disabled && e.button == 0){
27749 this.el.addClass("x-btn-click");
27750 Roo.get(document).on('mouseup', this.onMouseUp, this);
27754 onMouseUp : function(e){
27756 this.el.removeClass("x-btn-click");
27757 Roo.get(document).un('mouseup', this.onMouseUp, this);
27761 onMenuShow : function(e){
27762 this.el.addClass("x-btn-menu-active");
27765 onMenuHide : function(e){
27766 this.el.removeClass("x-btn-menu-active");
27770 // Private utility class used by Button
27771 Roo.ButtonToggleMgr = function(){
27774 function toggleGroup(btn, state){
27776 var g = groups[btn.toggleGroup];
27777 for(var i = 0, l = g.length; i < l; i++){
27779 g[i].toggle(false);
27786 register : function(btn){
27787 if(!btn.toggleGroup){
27790 var g = groups[btn.toggleGroup];
27792 g = groups[btn.toggleGroup] = [];
27795 btn.on("toggle", toggleGroup);
27798 unregister : function(btn){
27799 if(!btn.toggleGroup){
27802 var g = groups[btn.toggleGroup];
27805 btn.un("toggle", toggleGroup);
27811 * Ext JS Library 1.1.1
27812 * Copyright(c) 2006-2007, Ext JS, LLC.
27814 * Originally Released Under LGPL - original licence link has changed is not relivant.
27817 * <script type="text/javascript">
27821 * @class Roo.SplitButton
27822 * @extends Roo.Button
27823 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27824 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27825 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27826 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27827 * @cfg {String} arrowTooltip The title attribute of the arrow
27829 * Create a new menu button
27830 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27831 * @param {Object} config The config object
27833 Roo.SplitButton = function(renderTo, config){
27834 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27836 * @event arrowclick
27837 * Fires when this button's arrow is clicked
27838 * @param {SplitButton} this
27839 * @param {EventObject} e The click event
27841 this.addEvents({"arrowclick":true});
27844 Roo.extend(Roo.SplitButton, Roo.Button, {
27845 render : function(renderTo){
27846 // this is one sweet looking template!
27847 var tpl = new Roo.Template(
27848 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27849 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27850 '<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>',
27851 "</tbody></table></td><td>",
27852 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27853 '<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>',
27854 "</tbody></table></td></tr></table>"
27856 var btn = tpl.append(renderTo, [this.text, this.type], true);
27857 var btnEl = btn.child("button");
27859 btn.addClass(this.cls);
27862 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27865 btnEl.addClass(this.iconCls);
27867 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27871 if(this.handleMouseEvents){
27872 btn.on("mouseover", this.onMouseOver, this);
27873 btn.on("mouseout", this.onMouseOut, this);
27874 btn.on("mousedown", this.onMouseDown, this);
27875 btn.on("mouseup", this.onMouseUp, this);
27877 btn.on(this.clickEvent, this.onClick, this);
27879 if(typeof this.tooltip == 'object'){
27880 Roo.QuickTips.tips(Roo.apply({
27884 btnEl.dom[this.tooltipType] = this.tooltip;
27887 if(this.arrowTooltip){
27888 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27897 this.el.addClass("x-btn-pressed");
27899 if(Roo.isIE && !Roo.isIE7){
27900 this.autoWidth.defer(1, this);
27905 this.menu.on("show", this.onMenuShow, this);
27906 this.menu.on("hide", this.onMenuHide, this);
27908 this.fireEvent('render', this);
27912 autoWidth : function(){
27914 var tbl = this.el.child("table:first");
27915 var tbl2 = this.el.child("table:last");
27916 this.el.setWidth("auto");
27917 tbl.setWidth("auto");
27918 if(Roo.isIE7 && Roo.isStrict){
27919 var ib = this.el.child('button:first');
27920 if(ib && ib.getWidth() > 20){
27922 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27927 this.el.beginMeasure();
27929 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27930 tbl.setWidth(this.minWidth-tbl2.getWidth());
27933 this.el.endMeasure();
27936 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27940 * Sets this button's click handler
27941 * @param {Function} handler The function to call when the button is clicked
27942 * @param {Object} scope (optional) Scope for the function passed above
27944 setHandler : function(handler, scope){
27945 this.handler = handler;
27946 this.scope = scope;
27950 * Sets this button's arrow click handler
27951 * @param {Function} handler The function to call when the arrow is clicked
27952 * @param {Object} scope (optional) Scope for the function passed above
27954 setArrowHandler : function(handler, scope){
27955 this.arrowHandler = handler;
27956 this.scope = scope;
27962 focus : function(){
27964 this.el.child("button:first").focus();
27969 onClick : function(e){
27970 e.preventDefault();
27971 if(!this.disabled){
27972 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27973 if(this.menu && !this.menu.isVisible()){
27974 this.menu.show(this.el, this.menuAlign);
27976 this.fireEvent("arrowclick", this, e);
27977 if(this.arrowHandler){
27978 this.arrowHandler.call(this.scope || this, this, e);
27981 this.fireEvent("click", this, e);
27983 this.handler.call(this.scope || this, this, e);
27989 onMouseDown : function(e){
27990 if(!this.disabled){
27991 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27995 onMouseUp : function(e){
27996 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28001 // backwards compat
28002 Roo.MenuButton = Roo.SplitButton;/*
28004 * Ext JS Library 1.1.1
28005 * Copyright(c) 2006-2007, Ext JS, LLC.
28007 * Originally Released Under LGPL - original licence link has changed is not relivant.
28010 * <script type="text/javascript">
28014 * @class Roo.Toolbar
28015 * Basic Toolbar class.
28017 * Creates a new Toolbar
28018 * @param {Object} container The config object
28020 Roo.Toolbar = function(container, buttons, config)
28022 /// old consturctor format still supported..
28023 if(container instanceof Array){ // omit the container for later rendering
28024 buttons = container;
28028 if (typeof(container) == 'object' && container.xtype) {
28029 config = container;
28030 container = config.container;
28031 buttons = config.buttons || []; // not really - use items!!
28034 if (config && config.items) {
28035 xitems = config.items;
28036 delete config.items;
28038 Roo.apply(this, config);
28039 this.buttons = buttons;
28042 this.render(container);
28044 this.xitems = xitems;
28045 Roo.each(xitems, function(b) {
28051 Roo.Toolbar.prototype = {
28053 * @cfg {Array} items
28054 * array of button configs or elements to add (will be converted to a MixedCollection)
28058 * @cfg {String/HTMLElement/Element} container
28059 * The id or element that will contain the toolbar
28062 render : function(ct){
28063 this.el = Roo.get(ct);
28065 this.el.addClass(this.cls);
28067 // using a table allows for vertical alignment
28068 // 100% width is needed by Safari...
28069 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28070 this.tr = this.el.child("tr", true);
28072 this.items = new Roo.util.MixedCollection(false, function(o){
28073 return o.id || ("item" + (++autoId));
28076 this.add.apply(this, this.buttons);
28077 delete this.buttons;
28082 * Adds element(s) to the toolbar -- this function takes a variable number of
28083 * arguments of mixed type and adds them to the toolbar.
28084 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28086 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28087 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28088 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28089 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28090 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28091 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28092 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28093 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28094 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28096 * @param {Mixed} arg2
28097 * @param {Mixed} etc.
28100 var a = arguments, l = a.length;
28101 for(var i = 0; i < l; i++){
28106 _add : function(el) {
28109 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28112 if (el.applyTo){ // some kind of form field
28113 return this.addField(el);
28115 if (el.render){ // some kind of Toolbar.Item
28116 return this.addItem(el);
28118 if (typeof el == "string"){ // string
28119 if(el == "separator" || el == "-"){
28120 return this.addSeparator();
28123 return this.addSpacer();
28126 return this.addFill();
28128 return this.addText(el);
28131 if(el.tagName){ // element
28132 return this.addElement(el);
28134 if(typeof el == "object"){ // must be button config?
28135 return this.addButton(el);
28137 // and now what?!?!
28143 * Add an Xtype element
28144 * @param {Object} xtype Xtype Object
28145 * @return {Object} created Object
28147 addxtype : function(e){
28148 return this.add(e);
28152 * Returns the Element for this toolbar.
28153 * @return {Roo.Element}
28155 getEl : function(){
28161 * @return {Roo.Toolbar.Item} The separator item
28163 addSeparator : function(){
28164 return this.addItem(new Roo.Toolbar.Separator());
28168 * Adds a spacer element
28169 * @return {Roo.Toolbar.Spacer} The spacer item
28171 addSpacer : function(){
28172 return this.addItem(new Roo.Toolbar.Spacer());
28176 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28177 * @return {Roo.Toolbar.Fill} The fill item
28179 addFill : function(){
28180 return this.addItem(new Roo.Toolbar.Fill());
28184 * Adds any standard HTML element to the toolbar
28185 * @param {String/HTMLElement/Element} el The element or id of the element to add
28186 * @return {Roo.Toolbar.Item} The element's item
28188 addElement : function(el){
28189 return this.addItem(new Roo.Toolbar.Item(el));
28192 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28193 * @type Roo.util.MixedCollection
28198 * Adds any Toolbar.Item or subclass
28199 * @param {Roo.Toolbar.Item} item
28200 * @return {Roo.Toolbar.Item} The item
28202 addItem : function(item){
28203 var td = this.nextBlock();
28205 this.items.add(item);
28210 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28211 * @param {Object/Array} config A button config or array of configs
28212 * @return {Roo.Toolbar.Button/Array}
28214 addButton : function(config){
28215 if(config instanceof Array){
28217 for(var i = 0, len = config.length; i < len; i++) {
28218 buttons.push(this.addButton(config[i]));
28223 if(!(config instanceof Roo.Toolbar.Button)){
28225 new Roo.Toolbar.SplitButton(config) :
28226 new Roo.Toolbar.Button(config);
28228 var td = this.nextBlock();
28235 * Adds text to the toolbar
28236 * @param {String} text The text to add
28237 * @return {Roo.Toolbar.Item} The element's item
28239 addText : function(text){
28240 return this.addItem(new Roo.Toolbar.TextItem(text));
28244 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28245 * @param {Number} index The index where the item is to be inserted
28246 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28247 * @return {Roo.Toolbar.Button/Item}
28249 insertButton : function(index, item){
28250 if(item instanceof Array){
28252 for(var i = 0, len = item.length; i < len; i++) {
28253 buttons.push(this.insertButton(index + i, item[i]));
28257 if (!(item instanceof Roo.Toolbar.Button)){
28258 item = new Roo.Toolbar.Button(item);
28260 var td = document.createElement("td");
28261 this.tr.insertBefore(td, this.tr.childNodes[index]);
28263 this.items.insert(index, item);
28268 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28269 * @param {Object} config
28270 * @return {Roo.Toolbar.Item} The element's item
28272 addDom : function(config, returnEl){
28273 var td = this.nextBlock();
28274 Roo.DomHelper.overwrite(td, config);
28275 var ti = new Roo.Toolbar.Item(td.firstChild);
28277 this.items.add(ti);
28282 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28283 * @type Roo.util.MixedCollection
28288 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28289 * Note: the field should not have been rendered yet. For a field that has already been
28290 * rendered, use {@link #addElement}.
28291 * @param {Roo.form.Field} field
28292 * @return {Roo.ToolbarItem}
28296 addField : function(field) {
28297 if (!this.fields) {
28299 this.fields = new Roo.util.MixedCollection(false, function(o){
28300 return o.id || ("item" + (++autoId));
28305 var td = this.nextBlock();
28307 var ti = new Roo.Toolbar.Item(td.firstChild);
28309 this.items.add(ti);
28310 this.fields.add(field);
28321 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28322 this.el.child('div').hide();
28330 this.el.child('div').show();
28334 nextBlock : function(){
28335 var td = document.createElement("td");
28336 this.tr.appendChild(td);
28341 destroy : function(){
28342 if(this.items){ // rendered?
28343 Roo.destroy.apply(Roo, this.items.items);
28345 if(this.fields){ // rendered?
28346 Roo.destroy.apply(Roo, this.fields.items);
28348 Roo.Element.uncache(this.el, this.tr);
28353 * @class Roo.Toolbar.Item
28354 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28356 * Creates a new Item
28357 * @param {HTMLElement} el
28359 Roo.Toolbar.Item = function(el){
28360 this.el = Roo.getDom(el);
28361 this.id = Roo.id(this.el);
28362 this.hidden = false;
28365 Roo.Toolbar.Item.prototype = {
28368 * Get this item's HTML Element
28369 * @return {HTMLElement}
28371 getEl : function(){
28376 render : function(td){
28378 td.appendChild(this.el);
28382 * Removes and destroys this item.
28384 destroy : function(){
28385 this.td.parentNode.removeChild(this.td);
28392 this.hidden = false;
28393 this.td.style.display = "";
28400 this.hidden = true;
28401 this.td.style.display = "none";
28405 * Convenience function for boolean show/hide.
28406 * @param {Boolean} visible true to show/false to hide
28408 setVisible: function(visible){
28417 * Try to focus this item.
28419 focus : function(){
28420 Roo.fly(this.el).focus();
28424 * Disables this item.
28426 disable : function(){
28427 Roo.fly(this.td).addClass("x-item-disabled");
28428 this.disabled = true;
28429 this.el.disabled = true;
28433 * Enables this item.
28435 enable : function(){
28436 Roo.fly(this.td).removeClass("x-item-disabled");
28437 this.disabled = false;
28438 this.el.disabled = false;
28444 * @class Roo.Toolbar.Separator
28445 * @extends Roo.Toolbar.Item
28446 * A simple toolbar separator class
28448 * Creates a new Separator
28450 Roo.Toolbar.Separator = function(){
28451 var s = document.createElement("span");
28452 s.className = "ytb-sep";
28453 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28455 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28456 enable:Roo.emptyFn,
28457 disable:Roo.emptyFn,
28462 * @class Roo.Toolbar.Spacer
28463 * @extends Roo.Toolbar.Item
28464 * A simple element that adds extra horizontal space to a toolbar.
28466 * Creates a new Spacer
28468 Roo.Toolbar.Spacer = function(){
28469 var s = document.createElement("div");
28470 s.className = "ytb-spacer";
28471 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28473 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28474 enable:Roo.emptyFn,
28475 disable:Roo.emptyFn,
28480 * @class Roo.Toolbar.Fill
28481 * @extends Roo.Toolbar.Spacer
28482 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28484 * Creates a new Spacer
28486 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28488 render : function(td){
28489 td.style.width = '100%';
28490 Roo.Toolbar.Fill.superclass.render.call(this, td);
28495 * @class Roo.Toolbar.TextItem
28496 * @extends Roo.Toolbar.Item
28497 * A simple class that renders text directly into a toolbar.
28499 * Creates a new TextItem
28500 * @param {String} text
28502 Roo.Toolbar.TextItem = function(text){
28503 if (typeof(text) == 'object') {
28506 var s = document.createElement("span");
28507 s.className = "ytb-text";
28508 s.innerHTML = text;
28509 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28511 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28512 enable:Roo.emptyFn,
28513 disable:Roo.emptyFn,
28518 * @class Roo.Toolbar.Button
28519 * @extends Roo.Button
28520 * A button that renders into a toolbar.
28522 * Creates a new Button
28523 * @param {Object} config A standard {@link Roo.Button} config object
28525 Roo.Toolbar.Button = function(config){
28526 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28528 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28529 render : function(td){
28531 Roo.Toolbar.Button.superclass.render.call(this, td);
28535 * Removes and destroys this button
28537 destroy : function(){
28538 Roo.Toolbar.Button.superclass.destroy.call(this);
28539 this.td.parentNode.removeChild(this.td);
28543 * Shows this button
28546 this.hidden = false;
28547 this.td.style.display = "";
28551 * Hides this button
28554 this.hidden = true;
28555 this.td.style.display = "none";
28559 * Disables this item
28561 disable : function(){
28562 Roo.fly(this.td).addClass("x-item-disabled");
28563 this.disabled = true;
28567 * Enables this item
28569 enable : function(){
28570 Roo.fly(this.td).removeClass("x-item-disabled");
28571 this.disabled = false;
28574 // backwards compat
28575 Roo.ToolbarButton = Roo.Toolbar.Button;
28578 * @class Roo.Toolbar.SplitButton
28579 * @extends Roo.SplitButton
28580 * A menu button that renders into a toolbar.
28582 * Creates a new SplitButton
28583 * @param {Object} config A standard {@link Roo.SplitButton} config object
28585 Roo.Toolbar.SplitButton = function(config){
28586 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28588 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28589 render : function(td){
28591 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28595 * Removes and destroys this button
28597 destroy : function(){
28598 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28599 this.td.parentNode.removeChild(this.td);
28603 * Shows this button
28606 this.hidden = false;
28607 this.td.style.display = "";
28611 * Hides this button
28614 this.hidden = true;
28615 this.td.style.display = "none";
28619 // backwards compat
28620 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28622 * Ext JS Library 1.1.1
28623 * Copyright(c) 2006-2007, Ext JS, LLC.
28625 * Originally Released Under LGPL - original licence link has changed is not relivant.
28628 * <script type="text/javascript">
28632 * @class Roo.PagingToolbar
28633 * @extends Roo.Toolbar
28634 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28636 * Create a new PagingToolbar
28637 * @param {Object} config The config object
28639 Roo.PagingToolbar = function(el, ds, config)
28641 // old args format still supported... - xtype is prefered..
28642 if (typeof(el) == 'object' && el.xtype) {
28643 // created from xtype...
28645 ds = el.dataSource;
28646 el = config.container;
28649 if (config.items) {
28650 items = config.items;
28654 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28657 this.renderButtons(this.el);
28660 // supprot items array.
28662 Roo.each(items, function(e) {
28663 this.add(Roo.factory(e));
28668 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28670 * @cfg {Roo.data.Store} dataSource
28671 * The underlying data store providing the paged data
28674 * @cfg {String/HTMLElement/Element} container
28675 * container The id or element that will contain the toolbar
28678 * @cfg {Boolean} displayInfo
28679 * True to display the displayMsg (defaults to false)
28682 * @cfg {Number} pageSize
28683 * The number of records to display per page (defaults to 20)
28687 * @cfg {String} displayMsg
28688 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28690 displayMsg : 'Displaying {0} - {1} of {2}',
28692 * @cfg {String} emptyMsg
28693 * The message to display when no records are found (defaults to "No data to display")
28695 emptyMsg : 'No data to display',
28697 * Customizable piece of the default paging text (defaults to "Page")
28700 beforePageText : "Page",
28702 * Customizable piece of the default paging text (defaults to "of %0")
28705 afterPageText : "of {0}",
28707 * Customizable piece of the default paging text (defaults to "First Page")
28710 firstText : "First Page",
28712 * Customizable piece of the default paging text (defaults to "Previous Page")
28715 prevText : "Previous Page",
28717 * Customizable piece of the default paging text (defaults to "Next Page")
28720 nextText : "Next Page",
28722 * Customizable piece of the default paging text (defaults to "Last Page")
28725 lastText : "Last Page",
28727 * Customizable piece of the default paging text (defaults to "Refresh")
28730 refreshText : "Refresh",
28733 renderButtons : function(el){
28734 Roo.PagingToolbar.superclass.render.call(this, el);
28735 this.first = this.addButton({
28736 tooltip: this.firstText,
28737 cls: "x-btn-icon x-grid-page-first",
28739 handler: this.onClick.createDelegate(this, ["first"])
28741 this.prev = this.addButton({
28742 tooltip: this.prevText,
28743 cls: "x-btn-icon x-grid-page-prev",
28745 handler: this.onClick.createDelegate(this, ["prev"])
28747 //this.addSeparator();
28748 this.add(this.beforePageText);
28749 this.field = Roo.get(this.addDom({
28754 cls: "x-grid-page-number"
28756 this.field.on("keydown", this.onPagingKeydown, this);
28757 this.field.on("focus", function(){this.dom.select();});
28758 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28759 this.field.setHeight(18);
28760 //this.addSeparator();
28761 this.next = this.addButton({
28762 tooltip: this.nextText,
28763 cls: "x-btn-icon x-grid-page-next",
28765 handler: this.onClick.createDelegate(this, ["next"])
28767 this.last = this.addButton({
28768 tooltip: this.lastText,
28769 cls: "x-btn-icon x-grid-page-last",
28771 handler: this.onClick.createDelegate(this, ["last"])
28773 //this.addSeparator();
28774 this.loading = this.addButton({
28775 tooltip: this.refreshText,
28776 cls: "x-btn-icon x-grid-loading",
28777 handler: this.onClick.createDelegate(this, ["refresh"])
28780 if(this.displayInfo){
28781 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28786 updateInfo : function(){
28787 if(this.displayEl){
28788 var count = this.ds.getCount();
28789 var msg = count == 0 ?
28793 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28795 this.displayEl.update(msg);
28800 onLoad : function(ds, r, o){
28801 this.cursor = o.params ? o.params.start : 0;
28802 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28804 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28805 this.field.dom.value = ap;
28806 this.first.setDisabled(ap == 1);
28807 this.prev.setDisabled(ap == 1);
28808 this.next.setDisabled(ap == ps);
28809 this.last.setDisabled(ap == ps);
28810 this.loading.enable();
28815 getPageData : function(){
28816 var total = this.ds.getTotalCount();
28819 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28820 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28825 onLoadError : function(){
28826 this.loading.enable();
28830 onPagingKeydown : function(e){
28831 var k = e.getKey();
28832 var d = this.getPageData();
28834 var v = this.field.dom.value, pageNum;
28835 if(!v || isNaN(pageNum = parseInt(v, 10))){
28836 this.field.dom.value = d.activePage;
28839 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28840 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28843 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))
28845 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28846 this.field.dom.value = pageNum;
28847 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28850 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28852 var v = this.field.dom.value, pageNum;
28853 var increment = (e.shiftKey) ? 10 : 1;
28854 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28856 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28857 this.field.dom.value = d.activePage;
28860 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28862 this.field.dom.value = parseInt(v, 10) + increment;
28863 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28864 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28871 beforeLoad : function(){
28873 this.loading.disable();
28878 onClick : function(which){
28882 ds.load({params:{start: 0, limit: this.pageSize}});
28885 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28888 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28891 var total = ds.getTotalCount();
28892 var extra = total % this.pageSize;
28893 var lastStart = extra ? (total - extra) : total-this.pageSize;
28894 ds.load({params:{start: lastStart, limit: this.pageSize}});
28897 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28903 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28904 * @param {Roo.data.Store} store The data store to unbind
28906 unbind : function(ds){
28907 ds.un("beforeload", this.beforeLoad, this);
28908 ds.un("load", this.onLoad, this);
28909 ds.un("loadexception", this.onLoadError, this);
28910 ds.un("remove", this.updateInfo, this);
28911 ds.un("add", this.updateInfo, this);
28912 this.ds = undefined;
28916 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28917 * @param {Roo.data.Store} store The data store to bind
28919 bind : function(ds){
28920 ds.on("beforeload", this.beforeLoad, this);
28921 ds.on("load", this.onLoad, this);
28922 ds.on("loadexception", this.onLoadError, this);
28923 ds.on("remove", this.updateInfo, this);
28924 ds.on("add", this.updateInfo, this);
28929 * Ext JS Library 1.1.1
28930 * Copyright(c) 2006-2007, Ext JS, LLC.
28932 * Originally Released Under LGPL - original licence link has changed is not relivant.
28935 * <script type="text/javascript">
28939 * @class Roo.Resizable
28940 * @extends Roo.util.Observable
28941 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28942 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28943 * 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
28944 * the element will be wrapped for you automatically.</p>
28945 * <p>Here is the list of valid resize handles:</p>
28948 ------ -------------------
28957 'hd' horizontal drag
28960 * <p>Here's an example showing the creation of a typical Resizable:</p>
28962 var resizer = new Roo.Resizable("element-id", {
28970 resizer.on("resize", myHandler);
28972 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28973 * resizer.east.setDisplayed(false);</p>
28974 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28975 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28976 * resize operation's new size (defaults to [0, 0])
28977 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28978 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28979 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28980 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28981 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28982 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28983 * @cfg {Number} width The width of the element in pixels (defaults to null)
28984 * @cfg {Number} height The height of the element in pixels (defaults to null)
28985 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28986 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28987 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28988 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28989 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28990 * in favor of the handles config option (defaults to false)
28991 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28992 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28993 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28994 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28995 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28996 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28997 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28998 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28999 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29000 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29001 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29003 * Create a new resizable component
29004 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29005 * @param {Object} config configuration options
29007 Roo.Resizable = function(el, config)
29009 this.el = Roo.get(el);
29011 if(config && config.wrap){
29012 config.resizeChild = this.el;
29013 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29014 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29015 this.el.setStyle("overflow", "hidden");
29016 this.el.setPositioning(config.resizeChild.getPositioning());
29017 config.resizeChild.clearPositioning();
29018 if(!config.width || !config.height){
29019 var csize = config.resizeChild.getSize();
29020 this.el.setSize(csize.width, csize.height);
29022 if(config.pinned && !config.adjustments){
29023 config.adjustments = "auto";
29027 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29028 this.proxy.unselectable();
29029 this.proxy.enableDisplayMode('block');
29031 Roo.apply(this, config);
29034 this.disableTrackOver = true;
29035 this.el.addClass("x-resizable-pinned");
29037 // if the element isn't positioned, make it relative
29038 var position = this.el.getStyle("position");
29039 if(position != "absolute" && position != "fixed"){
29040 this.el.setStyle("position", "relative");
29042 if(!this.handles){ // no handles passed, must be legacy style
29043 this.handles = 's,e,se';
29044 if(this.multiDirectional){
29045 this.handles += ',n,w';
29048 if(this.handles == "all"){
29049 this.handles = "n s e w ne nw se sw";
29051 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29052 var ps = Roo.Resizable.positions;
29053 for(var i = 0, len = hs.length; i < len; i++){
29054 if(hs[i] && ps[hs[i]]){
29055 var pos = ps[hs[i]];
29056 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29060 this.corner = this.southeast;
29062 // updateBox = the box can move..
29063 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29064 this.updateBox = true;
29067 this.activeHandle = null;
29069 if(this.resizeChild){
29070 if(typeof this.resizeChild == "boolean"){
29071 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29073 this.resizeChild = Roo.get(this.resizeChild, true);
29077 if(this.adjustments == "auto"){
29078 var rc = this.resizeChild;
29079 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29080 if(rc && (hw || hn)){
29081 rc.position("relative");
29082 rc.setLeft(hw ? hw.el.getWidth() : 0);
29083 rc.setTop(hn ? hn.el.getHeight() : 0);
29085 this.adjustments = [
29086 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29087 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29091 if(this.draggable){
29092 this.dd = this.dynamic ?
29093 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29094 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29100 * @event beforeresize
29101 * Fired before resize is allowed. Set enabled to false to cancel resize.
29102 * @param {Roo.Resizable} this
29103 * @param {Roo.EventObject} e The mousedown event
29105 "beforeresize" : true,
29108 * Fired a resizing.
29109 * @param {Roo.Resizable} this
29110 * @param {Number} x The new x position
29111 * @param {Number} y The new y position
29112 * @param {Number} w The new w width
29113 * @param {Number} h The new h hight
29114 * @param {Roo.EventObject} e The mouseup event
29119 * Fired after a resize.
29120 * @param {Roo.Resizable} this
29121 * @param {Number} width The new width
29122 * @param {Number} height The new height
29123 * @param {Roo.EventObject} e The mouseup event
29128 if(this.width !== null && this.height !== null){
29129 this.resizeTo(this.width, this.height);
29131 this.updateChildSize();
29134 this.el.dom.style.zoom = 1;
29136 Roo.Resizable.superclass.constructor.call(this);
29139 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29140 resizeChild : false,
29141 adjustments : [0, 0],
29151 multiDirectional : false,
29152 disableTrackOver : false,
29153 easing : 'easeOutStrong',
29154 widthIncrement : 0,
29155 heightIncrement : 0,
29159 preserveRatio : false,
29160 transparent: false,
29166 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29168 constrainTo: undefined,
29170 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29172 resizeRegion: undefined,
29176 * Perform a manual resize
29177 * @param {Number} width
29178 * @param {Number} height
29180 resizeTo : function(width, height){
29181 this.el.setSize(width, height);
29182 this.updateChildSize();
29183 this.fireEvent("resize", this, width, height, null);
29187 startSizing : function(e, handle){
29188 this.fireEvent("beforeresize", this, e);
29189 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29192 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29193 this.overlay.unselectable();
29194 this.overlay.enableDisplayMode("block");
29195 this.overlay.on("mousemove", this.onMouseMove, this);
29196 this.overlay.on("mouseup", this.onMouseUp, this);
29198 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29200 this.resizing = true;
29201 this.startBox = this.el.getBox();
29202 this.startPoint = e.getXY();
29203 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29204 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29206 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29207 this.overlay.show();
29209 if(this.constrainTo) {
29210 var ct = Roo.get(this.constrainTo);
29211 this.resizeRegion = ct.getRegion().adjust(
29212 ct.getFrameWidth('t'),
29213 ct.getFrameWidth('l'),
29214 -ct.getFrameWidth('b'),
29215 -ct.getFrameWidth('r')
29219 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29221 this.proxy.setBox(this.startBox);
29223 this.proxy.setStyle('visibility', 'visible');
29229 onMouseDown : function(handle, e){
29232 this.activeHandle = handle;
29233 this.startSizing(e, handle);
29238 onMouseUp : function(e){
29239 var size = this.resizeElement();
29240 this.resizing = false;
29242 this.overlay.hide();
29244 this.fireEvent("resize", this, size.width, size.height, e);
29248 updateChildSize : function(){
29250 if(this.resizeChild){
29252 var child = this.resizeChild;
29253 var adj = this.adjustments;
29254 if(el.dom.offsetWidth){
29255 var b = el.getSize(true);
29256 child.setSize(b.width+adj[0], b.height+adj[1]);
29258 // Second call here for IE
29259 // The first call enables instant resizing and
29260 // the second call corrects scroll bars if they
29263 setTimeout(function(){
29264 if(el.dom.offsetWidth){
29265 var b = el.getSize(true);
29266 child.setSize(b.width+adj[0], b.height+adj[1]);
29274 snap : function(value, inc, min){
29275 if(!inc || !value) return value;
29276 var newValue = value;
29277 var m = value % inc;
29280 newValue = value + (inc-m);
29282 newValue = value - m;
29285 return Math.max(min, newValue);
29289 resizeElement : function(){
29290 var box = this.proxy.getBox();
29291 if(this.updateBox){
29292 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29294 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29296 this.updateChildSize();
29304 constrain : function(v, diff, m, mx){
29307 }else if(v - diff > mx){
29314 onMouseMove : function(e){
29317 try{// try catch so if something goes wrong the user doesn't get hung
29319 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29323 //var curXY = this.startPoint;
29324 var curSize = this.curSize || this.startBox;
29325 var x = this.startBox.x, y = this.startBox.y;
29326 var ox = x, oy = y;
29327 var w = curSize.width, h = curSize.height;
29328 var ow = w, oh = h;
29329 var mw = this.minWidth, mh = this.minHeight;
29330 var mxw = this.maxWidth, mxh = this.maxHeight;
29331 var wi = this.widthIncrement;
29332 var hi = this.heightIncrement;
29334 var eventXY = e.getXY();
29335 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29336 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29338 var pos = this.activeHandle.position;
29343 w = Math.min(Math.max(mw, w), mxw);
29348 h = Math.min(Math.max(mh, h), mxh);
29353 w = Math.min(Math.max(mw, w), mxw);
29354 h = Math.min(Math.max(mh, h), mxh);
29357 diffY = this.constrain(h, diffY, mh, mxh);
29364 var adiffX = Math.abs(diffX);
29365 var sub = (adiffX % wi); // how much
29366 if (sub > (wi/2)) { // far enough to snap
29367 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29369 // remove difference..
29370 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29374 x = Math.max(this.minX, x);
29377 diffX = this.constrain(w, diffX, mw, mxw);
29383 w = Math.min(Math.max(mw, w), mxw);
29384 diffY = this.constrain(h, diffY, mh, mxh);
29389 diffX = this.constrain(w, diffX, mw, mxw);
29390 diffY = this.constrain(h, diffY, mh, mxh);
29397 diffX = this.constrain(w, diffX, mw, mxw);
29399 h = Math.min(Math.max(mh, h), mxh);
29405 var sw = this.snap(w, wi, mw);
29406 var sh = this.snap(h, hi, mh);
29407 if(sw != w || sh != h){
29430 if(this.preserveRatio){
29435 h = Math.min(Math.max(mh, h), mxh);
29440 w = Math.min(Math.max(mw, w), mxw);
29445 w = Math.min(Math.max(mw, w), mxw);
29451 w = Math.min(Math.max(mw, w), mxw);
29457 h = Math.min(Math.max(mh, h), mxh);
29465 h = Math.min(Math.max(mh, h), mxh);
29475 h = Math.min(Math.max(mh, h), mxh);
29483 if (pos == 'hdrag') {
29486 this.proxy.setBounds(x, y, w, h);
29488 this.resizeElement();
29492 this.fireEvent("resizing", this, x, y, w, h, e);
29496 handleOver : function(){
29498 this.el.addClass("x-resizable-over");
29503 handleOut : function(){
29504 if(!this.resizing){
29505 this.el.removeClass("x-resizable-over");
29510 * Returns the element this component is bound to.
29511 * @return {Roo.Element}
29513 getEl : function(){
29518 * Returns the resizeChild element (or null).
29519 * @return {Roo.Element}
29521 getResizeChild : function(){
29522 return this.resizeChild;
29524 groupHandler : function()
29529 * Destroys this resizable. If the element was wrapped and
29530 * removeEl is not true then the element remains.
29531 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29533 destroy : function(removeEl){
29534 this.proxy.remove();
29536 this.overlay.removeAllListeners();
29537 this.overlay.remove();
29539 var ps = Roo.Resizable.positions;
29541 if(typeof ps[k] != "function" && this[ps[k]]){
29542 var h = this[ps[k]];
29543 h.el.removeAllListeners();
29548 this.el.update("");
29555 // hash to map config positions to true positions
29556 Roo.Resizable.positions = {
29557 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29562 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29564 // only initialize the template if resizable is used
29565 var tpl = Roo.DomHelper.createTemplate(
29566 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29569 Roo.Resizable.Handle.prototype.tpl = tpl;
29571 this.position = pos;
29573 // show north drag fro topdra
29574 var handlepos = pos == 'hdrag' ? 'north' : pos;
29576 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29577 if (pos == 'hdrag') {
29578 this.el.setStyle('cursor', 'pointer');
29580 this.el.unselectable();
29582 this.el.setOpacity(0);
29584 this.el.on("mousedown", this.onMouseDown, this);
29585 if(!disableTrackOver){
29586 this.el.on("mouseover", this.onMouseOver, this);
29587 this.el.on("mouseout", this.onMouseOut, this);
29592 Roo.Resizable.Handle.prototype = {
29593 afterResize : function(rz){
29598 onMouseDown : function(e){
29599 this.rz.onMouseDown(this, e);
29602 onMouseOver : function(e){
29603 this.rz.handleOver(this, e);
29606 onMouseOut : function(e){
29607 this.rz.handleOut(this, e);
29611 * Ext JS Library 1.1.1
29612 * Copyright(c) 2006-2007, Ext JS, LLC.
29614 * Originally Released Under LGPL - original licence link has changed is not relivant.
29617 * <script type="text/javascript">
29621 * @class Roo.Editor
29622 * @extends Roo.Component
29623 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29625 * Create a new Editor
29626 * @param {Roo.form.Field} field The Field object (or descendant)
29627 * @param {Object} config The config object
29629 Roo.Editor = function(field, config){
29630 Roo.Editor.superclass.constructor.call(this, config);
29631 this.field = field;
29634 * @event beforestartedit
29635 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29636 * false from the handler of this event.
29637 * @param {Editor} this
29638 * @param {Roo.Element} boundEl The underlying element bound to this editor
29639 * @param {Mixed} value The field value being set
29641 "beforestartedit" : true,
29644 * Fires when this editor is displayed
29645 * @param {Roo.Element} boundEl The underlying element bound to this editor
29646 * @param {Mixed} value The starting field value
29648 "startedit" : true,
29650 * @event beforecomplete
29651 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29652 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29653 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29654 * event will not fire since no edit actually occurred.
29655 * @param {Editor} this
29656 * @param {Mixed} value The current field value
29657 * @param {Mixed} startValue The original field value
29659 "beforecomplete" : true,
29662 * Fires after editing is complete and any changed value has been written to the underlying field.
29663 * @param {Editor} this
29664 * @param {Mixed} value The current field value
29665 * @param {Mixed} startValue The original field value
29669 * @event specialkey
29670 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29671 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29672 * @param {Roo.form.Field} this
29673 * @param {Roo.EventObject} e The event object
29675 "specialkey" : true
29679 Roo.extend(Roo.Editor, Roo.Component, {
29681 * @cfg {Boolean/String} autosize
29682 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29683 * or "height" to adopt the height only (defaults to false)
29686 * @cfg {Boolean} revertInvalid
29687 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29688 * validation fails (defaults to true)
29691 * @cfg {Boolean} ignoreNoChange
29692 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29693 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29694 * will never be ignored.
29697 * @cfg {Boolean} hideEl
29698 * False to keep the bound element visible while the editor is displayed (defaults to true)
29701 * @cfg {Mixed} value
29702 * The data value of the underlying field (defaults to "")
29706 * @cfg {String} alignment
29707 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29711 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29712 * for bottom-right shadow (defaults to "frame")
29716 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29720 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29722 completeOnEnter : false,
29724 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29726 cancelOnEsc : false,
29728 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29733 onRender : function(ct, position){
29734 this.el = new Roo.Layer({
29735 shadow: this.shadow,
29741 constrain: this.constrain
29743 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29744 if(this.field.msgTarget != 'title'){
29745 this.field.msgTarget = 'qtip';
29747 this.field.render(this.el);
29749 this.field.el.dom.setAttribute('autocomplete', 'off');
29751 this.field.on("specialkey", this.onSpecialKey, this);
29752 if(this.swallowKeys){
29753 this.field.el.swallowEvent(['keydown','keypress']);
29756 this.field.on("blur", this.onBlur, this);
29757 if(this.field.grow){
29758 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29762 onSpecialKey : function(field, e)
29764 //Roo.log('editor onSpecialKey');
29765 if(this.completeOnEnter && e.getKey() == e.ENTER){
29767 this.completeEdit();
29770 // do not fire special key otherwise it might hide close the editor...
29771 if(e.getKey() == e.ENTER){
29774 if(this.cancelOnEsc && e.getKey() == e.ESC){
29778 this.fireEvent('specialkey', field, e);
29783 * Starts the editing process and shows the editor.
29784 * @param {String/HTMLElement/Element} el The element to edit
29785 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29786 * to the innerHTML of el.
29788 startEdit : function(el, value){
29790 this.completeEdit();
29792 this.boundEl = Roo.get(el);
29793 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29794 if(!this.rendered){
29795 this.render(this.parentEl || document.body);
29797 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29800 this.startValue = v;
29801 this.field.setValue(v);
29803 var sz = this.boundEl.getSize();
29804 switch(this.autoSize){
29806 this.setSize(sz.width, "");
29809 this.setSize("", sz.height);
29812 this.setSize(sz.width, sz.height);
29815 this.el.alignTo(this.boundEl, this.alignment);
29816 this.editing = true;
29818 Roo.QuickTips.disable();
29824 * Sets the height and width of this editor.
29825 * @param {Number} width The new width
29826 * @param {Number} height The new height
29828 setSize : function(w, h){
29829 this.field.setSize(w, h);
29836 * Realigns the editor to the bound field based on the current alignment config value.
29838 realign : function(){
29839 this.el.alignTo(this.boundEl, this.alignment);
29843 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29844 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29846 completeEdit : function(remainVisible){
29850 var v = this.getValue();
29851 if(this.revertInvalid !== false && !this.field.isValid()){
29852 v = this.startValue;
29853 this.cancelEdit(true);
29855 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29856 this.editing = false;
29860 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29861 this.editing = false;
29862 if(this.updateEl && this.boundEl){
29863 this.boundEl.update(v);
29865 if(remainVisible !== true){
29868 this.fireEvent("complete", this, v, this.startValue);
29873 onShow : function(){
29875 if(this.hideEl !== false){
29876 this.boundEl.hide();
29879 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29880 this.fixIEFocus = true;
29881 this.deferredFocus.defer(50, this);
29883 this.field.focus();
29885 this.fireEvent("startedit", this.boundEl, this.startValue);
29888 deferredFocus : function(){
29890 this.field.focus();
29895 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29896 * reverted to the original starting value.
29897 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29898 * cancel (defaults to false)
29900 cancelEdit : function(remainVisible){
29902 this.setValue(this.startValue);
29903 if(remainVisible !== true){
29910 onBlur : function(){
29911 if(this.allowBlur !== true && this.editing){
29912 this.completeEdit();
29917 onHide : function(){
29919 this.completeEdit();
29923 if(this.field.collapse){
29924 this.field.collapse();
29927 if(this.hideEl !== false){
29928 this.boundEl.show();
29931 Roo.QuickTips.enable();
29936 * Sets the data value of the editor
29937 * @param {Mixed} value Any valid value supported by the underlying field
29939 setValue : function(v){
29940 this.field.setValue(v);
29944 * Gets the data value of the editor
29945 * @return {Mixed} The data value
29947 getValue : function(){
29948 return this.field.getValue();
29952 * Ext JS Library 1.1.1
29953 * Copyright(c) 2006-2007, Ext JS, LLC.
29955 * Originally Released Under LGPL - original licence link has changed is not relivant.
29958 * <script type="text/javascript">
29962 * @class Roo.BasicDialog
29963 * @extends Roo.util.Observable
29964 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29966 var dlg = new Roo.BasicDialog("my-dlg", {
29975 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29976 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29977 dlg.addButton('Cancel', dlg.hide, dlg);
29980 <b>A Dialog should always be a direct child of the body element.</b>
29981 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29982 * @cfg {String} title Default text to display in the title bar (defaults to null)
29983 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29984 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29985 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29986 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29987 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29988 * (defaults to null with no animation)
29989 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29990 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29991 * property for valid values (defaults to 'all')
29992 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29993 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29994 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29995 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29996 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29997 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29998 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29999 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30000 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30001 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30002 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30003 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30004 * draggable = true (defaults to false)
30005 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30006 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30007 * shadow (defaults to false)
30008 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30009 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30010 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30011 * @cfg {Array} buttons Array of buttons
30012 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30014 * Create a new BasicDialog.
30015 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30016 * @param {Object} config Configuration options
30018 Roo.BasicDialog = function(el, config){
30019 this.el = Roo.get(el);
30020 var dh = Roo.DomHelper;
30021 if(!this.el && config && config.autoCreate){
30022 if(typeof config.autoCreate == "object"){
30023 if(!config.autoCreate.id){
30024 config.autoCreate.id = el;
30026 this.el = dh.append(document.body,
30027 config.autoCreate, true);
30029 this.el = dh.append(document.body,
30030 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30034 el.setDisplayed(true);
30035 el.hide = this.hideAction;
30037 el.addClass("x-dlg");
30039 Roo.apply(this, config);
30041 this.proxy = el.createProxy("x-dlg-proxy");
30042 this.proxy.hide = this.hideAction;
30043 this.proxy.setOpacity(.5);
30047 el.setWidth(config.width);
30050 el.setHeight(config.height);
30052 this.size = el.getSize();
30053 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30054 this.xy = [config.x,config.y];
30056 this.xy = el.getCenterXY(true);
30058 /** The header element @type Roo.Element */
30059 this.header = el.child("> .x-dlg-hd");
30060 /** The body element @type Roo.Element */
30061 this.body = el.child("> .x-dlg-bd");
30062 /** The footer element @type Roo.Element */
30063 this.footer = el.child("> .x-dlg-ft");
30066 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30069 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30072 this.header.unselectable();
30074 this.header.update(this.title);
30076 // this element allows the dialog to be focused for keyboard event
30077 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30078 this.focusEl.swallowEvent("click", true);
30080 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30082 // wrap the body and footer for special rendering
30083 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30085 this.bwrap.dom.appendChild(this.footer.dom);
30088 this.bg = this.el.createChild({
30089 tag: "div", cls:"x-dlg-bg",
30090 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30092 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30095 if(this.autoScroll !== false && !this.autoTabs){
30096 this.body.setStyle("overflow", "auto");
30099 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30101 if(this.closable !== false){
30102 this.el.addClass("x-dlg-closable");
30103 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30104 this.close.on("click", this.closeClick, this);
30105 this.close.addClassOnOver("x-dlg-close-over");
30107 if(this.collapsible !== false){
30108 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30109 this.collapseBtn.on("click", this.collapseClick, this);
30110 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30111 this.header.on("dblclick", this.collapseClick, this);
30113 if(this.resizable !== false){
30114 this.el.addClass("x-dlg-resizable");
30115 this.resizer = new Roo.Resizable(el, {
30116 minWidth: this.minWidth || 80,
30117 minHeight:this.minHeight || 80,
30118 handles: this.resizeHandles || "all",
30121 this.resizer.on("beforeresize", this.beforeResize, this);
30122 this.resizer.on("resize", this.onResize, this);
30124 if(this.draggable !== false){
30125 el.addClass("x-dlg-draggable");
30126 if (!this.proxyDrag) {
30127 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30130 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30132 dd.setHandleElId(this.header.id);
30133 dd.endDrag = this.endMove.createDelegate(this);
30134 dd.startDrag = this.startMove.createDelegate(this);
30135 dd.onDrag = this.onDrag.createDelegate(this);
30140 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30141 this.mask.enableDisplayMode("block");
30143 this.el.addClass("x-dlg-modal");
30146 this.shadow = new Roo.Shadow({
30147 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30148 offset : this.shadowOffset
30151 this.shadowOffset = 0;
30153 if(Roo.useShims && this.shim !== false){
30154 this.shim = this.el.createShim();
30155 this.shim.hide = this.hideAction;
30163 if (this.buttons) {
30164 var bts= this.buttons;
30166 Roo.each(bts, function(b) {
30175 * Fires when a key is pressed
30176 * @param {Roo.BasicDialog} this
30177 * @param {Roo.EventObject} e
30182 * Fires when this dialog is moved by the user.
30183 * @param {Roo.BasicDialog} this
30184 * @param {Number} x The new page X
30185 * @param {Number} y The new page Y
30190 * Fires when this dialog is resized by the user.
30191 * @param {Roo.BasicDialog} this
30192 * @param {Number} width The new width
30193 * @param {Number} height The new height
30197 * @event beforehide
30198 * Fires before this dialog is hidden.
30199 * @param {Roo.BasicDialog} this
30201 "beforehide" : true,
30204 * Fires when this dialog is hidden.
30205 * @param {Roo.BasicDialog} this
30209 * @event beforeshow
30210 * Fires before this dialog is shown.
30211 * @param {Roo.BasicDialog} this
30213 "beforeshow" : true,
30216 * Fires when this dialog is shown.
30217 * @param {Roo.BasicDialog} this
30221 el.on("keydown", this.onKeyDown, this);
30222 el.on("mousedown", this.toFront, this);
30223 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30225 Roo.DialogManager.register(this);
30226 Roo.BasicDialog.superclass.constructor.call(this);
30229 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30230 shadowOffset: Roo.isIE ? 6 : 5,
30233 minButtonWidth: 75,
30234 defaultButton: null,
30235 buttonAlign: "right",
30240 * Sets the dialog title text
30241 * @param {String} text The title text to display
30242 * @return {Roo.BasicDialog} this
30244 setTitle : function(text){
30245 this.header.update(text);
30250 closeClick : function(){
30255 collapseClick : function(){
30256 this[this.collapsed ? "expand" : "collapse"]();
30260 * Collapses the dialog to its minimized state (only the title bar is visible).
30261 * Equivalent to the user clicking the collapse dialog button.
30263 collapse : function(){
30264 if(!this.collapsed){
30265 this.collapsed = true;
30266 this.el.addClass("x-dlg-collapsed");
30267 this.restoreHeight = this.el.getHeight();
30268 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30273 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30274 * clicking the expand dialog button.
30276 expand : function(){
30277 if(this.collapsed){
30278 this.collapsed = false;
30279 this.el.removeClass("x-dlg-collapsed");
30280 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30285 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30286 * @return {Roo.TabPanel} The tabs component
30288 initTabs : function(){
30289 var tabs = this.getTabs();
30290 while(tabs.getTab(0)){
30293 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30295 tabs.addTab(Roo.id(dom), dom.title);
30303 beforeResize : function(){
30304 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30308 onResize : function(){
30309 this.refreshSize();
30310 this.syncBodyHeight();
30311 this.adjustAssets();
30313 this.fireEvent("resize", this, this.size.width, this.size.height);
30317 onKeyDown : function(e){
30318 if(this.isVisible()){
30319 this.fireEvent("keydown", this, e);
30324 * Resizes the dialog.
30325 * @param {Number} width
30326 * @param {Number} height
30327 * @return {Roo.BasicDialog} this
30329 resizeTo : function(width, height){
30330 this.el.setSize(width, height);
30331 this.size = {width: width, height: height};
30332 this.syncBodyHeight();
30333 if(this.fixedcenter){
30336 if(this.isVisible()){
30337 this.constrainXY();
30338 this.adjustAssets();
30340 this.fireEvent("resize", this, width, height);
30346 * Resizes the dialog to fit the specified content size.
30347 * @param {Number} width
30348 * @param {Number} height
30349 * @return {Roo.BasicDialog} this
30351 setContentSize : function(w, h){
30352 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30353 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30354 //if(!this.el.isBorderBox()){
30355 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30356 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30359 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30360 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30362 this.resizeTo(w, h);
30367 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30368 * executed in response to a particular key being pressed while the dialog is active.
30369 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30370 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30371 * @param {Function} fn The function to call
30372 * @param {Object} scope (optional) The scope of the function
30373 * @return {Roo.BasicDialog} this
30375 addKeyListener : function(key, fn, scope){
30376 var keyCode, shift, ctrl, alt;
30377 if(typeof key == "object" && !(key instanceof Array)){
30378 keyCode = key["key"];
30379 shift = key["shift"];
30380 ctrl = key["ctrl"];
30385 var handler = function(dlg, e){
30386 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30387 var k = e.getKey();
30388 if(keyCode instanceof Array){
30389 for(var i = 0, len = keyCode.length; i < len; i++){
30390 if(keyCode[i] == k){
30391 fn.call(scope || window, dlg, k, e);
30397 fn.call(scope || window, dlg, k, e);
30402 this.on("keydown", handler);
30407 * Returns the TabPanel component (creates it if it doesn't exist).
30408 * Note: If you wish to simply check for the existence of tabs without creating them,
30409 * check for a null 'tabs' property.
30410 * @return {Roo.TabPanel} The tabs component
30412 getTabs : function(){
30414 this.el.addClass("x-dlg-auto-tabs");
30415 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30416 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30422 * Adds a button to the footer section of the dialog.
30423 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30424 * object or a valid Roo.DomHelper element config
30425 * @param {Function} handler The function called when the button is clicked
30426 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30427 * @return {Roo.Button} The new button
30429 addButton : function(config, handler, scope){
30430 var dh = Roo.DomHelper;
30432 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30434 if(!this.btnContainer){
30435 var tb = this.footer.createChild({
30437 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30438 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30440 this.btnContainer = tb.firstChild.firstChild.firstChild;
30445 minWidth: this.minButtonWidth,
30448 if(typeof config == "string"){
30449 bconfig.text = config;
30452 bconfig.dhconfig = config;
30454 Roo.apply(bconfig, config);
30458 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30459 bconfig.position = Math.max(0, bconfig.position);
30460 fc = this.btnContainer.childNodes[bconfig.position];
30463 var btn = new Roo.Button(
30465 this.btnContainer.insertBefore(document.createElement("td"),fc)
30466 : this.btnContainer.appendChild(document.createElement("td")),
30467 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30470 this.syncBodyHeight();
30473 * Array of all the buttons that have been added to this dialog via addButton
30478 this.buttons.push(btn);
30483 * Sets the default button to be focused when the dialog is displayed.
30484 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30485 * @return {Roo.BasicDialog} this
30487 setDefaultButton : function(btn){
30488 this.defaultButton = btn;
30493 getHeaderFooterHeight : function(safe){
30496 height += this.header.getHeight();
30499 var fm = this.footer.getMargins();
30500 height += (this.footer.getHeight()+fm.top+fm.bottom);
30502 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30503 height += this.centerBg.getPadding("tb");
30508 syncBodyHeight : function()
30510 var bd = this.body, // the text
30511 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30513 var height = this.size.height - this.getHeaderFooterHeight(false);
30514 bd.setHeight(height-bd.getMargins("tb"));
30515 var hh = this.header.getHeight();
30516 var h = this.size.height-hh;
30519 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30520 bw.setHeight(h-cb.getPadding("tb"));
30522 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30523 bd.setWidth(bw.getWidth(true));
30525 this.tabs.syncHeight();
30527 this.tabs.el.repaint();
30533 * Restores the previous state of the dialog if Roo.state is configured.
30534 * @return {Roo.BasicDialog} this
30536 restoreState : function(){
30537 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30538 if(box && box.width){
30539 this.xy = [box.x, box.y];
30540 this.resizeTo(box.width, box.height);
30546 beforeShow : function(){
30548 if(this.fixedcenter){
30549 this.xy = this.el.getCenterXY(true);
30552 Roo.get(document.body).addClass("x-body-masked");
30553 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30556 this.constrainXY();
30560 animShow : function(){
30561 var b = Roo.get(this.animateTarget).getBox();
30562 this.proxy.setSize(b.width, b.height);
30563 this.proxy.setLocation(b.x, b.y);
30565 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30566 true, .35, this.showEl.createDelegate(this));
30570 * Shows the dialog.
30571 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30572 * @return {Roo.BasicDialog} this
30574 show : function(animateTarget){
30575 if (this.fireEvent("beforeshow", this) === false){
30578 if(this.syncHeightBeforeShow){
30579 this.syncBodyHeight();
30580 }else if(this.firstShow){
30581 this.firstShow = false;
30582 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30584 this.animateTarget = animateTarget || this.animateTarget;
30585 if(!this.el.isVisible()){
30587 if(this.animateTarget && Roo.get(this.animateTarget)){
30597 showEl : function(){
30599 this.el.setXY(this.xy);
30601 this.adjustAssets(true);
30604 // IE peekaboo bug - fix found by Dave Fenwick
30608 this.fireEvent("show", this);
30612 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30613 * dialog itself will receive focus.
30615 focus : function(){
30616 if(this.defaultButton){
30617 this.defaultButton.focus();
30619 this.focusEl.focus();
30624 constrainXY : function(){
30625 if(this.constraintoviewport !== false){
30626 if(!this.viewSize){
30627 if(this.container){
30628 var s = this.container.getSize();
30629 this.viewSize = [s.width, s.height];
30631 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30634 var s = Roo.get(this.container||document).getScroll();
30636 var x = this.xy[0], y = this.xy[1];
30637 var w = this.size.width, h = this.size.height;
30638 var vw = this.viewSize[0], vh = this.viewSize[1];
30639 // only move it if it needs it
30641 // first validate right/bottom
30642 if(x + w > vw+s.left){
30646 if(y + h > vh+s.top){
30650 // then make sure top/left isn't negative
30662 if(this.isVisible()){
30663 this.el.setLocation(x, y);
30664 this.adjustAssets();
30671 onDrag : function(){
30672 if(!this.proxyDrag){
30673 this.xy = this.el.getXY();
30674 this.adjustAssets();
30679 adjustAssets : function(doShow){
30680 var x = this.xy[0], y = this.xy[1];
30681 var w = this.size.width, h = this.size.height;
30682 if(doShow === true){
30684 this.shadow.show(this.el);
30690 if(this.shadow && this.shadow.isVisible()){
30691 this.shadow.show(this.el);
30693 if(this.shim && this.shim.isVisible()){
30694 this.shim.setBounds(x, y, w, h);
30699 adjustViewport : function(w, h){
30701 w = Roo.lib.Dom.getViewWidth();
30702 h = Roo.lib.Dom.getViewHeight();
30705 this.viewSize = [w, h];
30706 if(this.modal && this.mask.isVisible()){
30707 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30708 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30710 if(this.isVisible()){
30711 this.constrainXY();
30716 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30717 * shadow, proxy, mask, etc.) Also removes all event listeners.
30718 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30720 destroy : function(removeEl){
30721 if(this.isVisible()){
30722 this.animateTarget = null;
30725 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30727 this.tabs.destroy(removeEl);
30740 for(var i = 0, len = this.buttons.length; i < len; i++){
30741 this.buttons[i].destroy();
30744 this.el.removeAllListeners();
30745 if(removeEl === true){
30746 this.el.update("");
30749 Roo.DialogManager.unregister(this);
30753 startMove : function(){
30754 if(this.proxyDrag){
30757 if(this.constraintoviewport !== false){
30758 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30763 endMove : function(){
30764 if(!this.proxyDrag){
30765 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30767 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30770 this.refreshSize();
30771 this.adjustAssets();
30773 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30777 * Brings this dialog to the front of any other visible dialogs
30778 * @return {Roo.BasicDialog} this
30780 toFront : function(){
30781 Roo.DialogManager.bringToFront(this);
30786 * Sends this dialog to the back (under) of any other visible dialogs
30787 * @return {Roo.BasicDialog} this
30789 toBack : function(){
30790 Roo.DialogManager.sendToBack(this);
30795 * Centers this dialog in the viewport
30796 * @return {Roo.BasicDialog} this
30798 center : function(){
30799 var xy = this.el.getCenterXY(true);
30800 this.moveTo(xy[0], xy[1]);
30805 * Moves the dialog's top-left corner to the specified point
30806 * @param {Number} x
30807 * @param {Number} y
30808 * @return {Roo.BasicDialog} this
30810 moveTo : function(x, y){
30812 if(this.isVisible()){
30813 this.el.setXY(this.xy);
30814 this.adjustAssets();
30820 * Aligns the dialog to the specified element
30821 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30822 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30823 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30824 * @return {Roo.BasicDialog} this
30826 alignTo : function(element, position, offsets){
30827 this.xy = this.el.getAlignToXY(element, position, offsets);
30828 if(this.isVisible()){
30829 this.el.setXY(this.xy);
30830 this.adjustAssets();
30836 * Anchors an element to another element and realigns it when the window is resized.
30837 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30838 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30839 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30840 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30841 * is a number, it is used as the buffer delay (defaults to 50ms).
30842 * @return {Roo.BasicDialog} this
30844 anchorTo : function(el, alignment, offsets, monitorScroll){
30845 var action = function(){
30846 this.alignTo(el, alignment, offsets);
30848 Roo.EventManager.onWindowResize(action, this);
30849 var tm = typeof monitorScroll;
30850 if(tm != 'undefined'){
30851 Roo.EventManager.on(window, 'scroll', action, this,
30852 {buffer: tm == 'number' ? monitorScroll : 50});
30859 * Returns true if the dialog is visible
30860 * @return {Boolean}
30862 isVisible : function(){
30863 return this.el.isVisible();
30867 animHide : function(callback){
30868 var b = Roo.get(this.animateTarget).getBox();
30870 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30872 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30873 this.hideEl.createDelegate(this, [callback]));
30877 * Hides the dialog.
30878 * @param {Function} callback (optional) Function to call when the dialog is hidden
30879 * @return {Roo.BasicDialog} this
30881 hide : function(callback){
30882 if (this.fireEvent("beforehide", this) === false){
30886 this.shadow.hide();
30891 // sometimes animateTarget seems to get set.. causing problems...
30892 // this just double checks..
30893 if(this.animateTarget && Roo.get(this.animateTarget)) {
30894 this.animHide(callback);
30897 this.hideEl(callback);
30903 hideEl : function(callback){
30907 Roo.get(document.body).removeClass("x-body-masked");
30909 this.fireEvent("hide", this);
30910 if(typeof callback == "function"){
30916 hideAction : function(){
30917 this.setLeft("-10000px");
30918 this.setTop("-10000px");
30919 this.setStyle("visibility", "hidden");
30923 refreshSize : function(){
30924 this.size = this.el.getSize();
30925 this.xy = this.el.getXY();
30926 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30930 // z-index is managed by the DialogManager and may be overwritten at any time
30931 setZIndex : function(index){
30933 this.mask.setStyle("z-index", index);
30936 this.shim.setStyle("z-index", ++index);
30939 this.shadow.setZIndex(++index);
30941 this.el.setStyle("z-index", ++index);
30943 this.proxy.setStyle("z-index", ++index);
30946 this.resizer.proxy.setStyle("z-index", ++index);
30949 this.lastZIndex = index;
30953 * Returns the element for this dialog
30954 * @return {Roo.Element} The underlying dialog Element
30956 getEl : function(){
30962 * @class Roo.DialogManager
30963 * Provides global access to BasicDialogs that have been created and
30964 * support for z-indexing (layering) multiple open dialogs.
30966 Roo.DialogManager = function(){
30968 var accessList = [];
30972 var sortDialogs = function(d1, d2){
30973 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30977 var orderDialogs = function(){
30978 accessList.sort(sortDialogs);
30979 var seed = Roo.DialogManager.zseed;
30980 for(var i = 0, len = accessList.length; i < len; i++){
30981 var dlg = accessList[i];
30983 dlg.setZIndex(seed + (i*10));
30990 * The starting z-index for BasicDialogs (defaults to 9000)
30991 * @type Number The z-index value
30996 register : function(dlg){
30997 list[dlg.id] = dlg;
30998 accessList.push(dlg);
31002 unregister : function(dlg){
31003 delete list[dlg.id];
31006 if(!accessList.indexOf){
31007 for( i = 0, len = accessList.length; i < len; i++){
31008 if(accessList[i] == dlg){
31009 accessList.splice(i, 1);
31014 i = accessList.indexOf(dlg);
31016 accessList.splice(i, 1);
31022 * Gets a registered dialog by id
31023 * @param {String/Object} id The id of the dialog or a dialog
31024 * @return {Roo.BasicDialog} this
31026 get : function(id){
31027 return typeof id == "object" ? id : list[id];
31031 * Brings the specified dialog to the front
31032 * @param {String/Object} dlg The id of the dialog or a dialog
31033 * @return {Roo.BasicDialog} this
31035 bringToFront : function(dlg){
31036 dlg = this.get(dlg);
31039 dlg._lastAccess = new Date().getTime();
31046 * Sends the specified dialog to the back
31047 * @param {String/Object} dlg The id of the dialog or a dialog
31048 * @return {Roo.BasicDialog} this
31050 sendToBack : function(dlg){
31051 dlg = this.get(dlg);
31052 dlg._lastAccess = -(new Date().getTime());
31058 * Hides all dialogs
31060 hideAll : function(){
31061 for(var id in list){
31062 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31071 * @class Roo.LayoutDialog
31072 * @extends Roo.BasicDialog
31073 * Dialog which provides adjustments for working with a layout in a Dialog.
31074 * Add your necessary layout config options to the dialog's config.<br>
31075 * Example usage (including a nested layout):
31078 dialog = new Roo.LayoutDialog("download-dlg", {
31087 // layout config merges with the dialog config
31089 tabPosition: "top",
31090 alwaysShowTabs: true
31093 dialog.addKeyListener(27, dialog.hide, dialog);
31094 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31095 dialog.addButton("Build It!", this.getDownload, this);
31097 // we can even add nested layouts
31098 var innerLayout = new Roo.BorderLayout("dl-inner", {
31108 innerLayout.beginUpdate();
31109 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31110 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31111 innerLayout.endUpdate(true);
31113 var layout = dialog.getLayout();
31114 layout.beginUpdate();
31115 layout.add("center", new Roo.ContentPanel("standard-panel",
31116 {title: "Download the Source", fitToFrame:true}));
31117 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31118 {title: "Build your own roo.js"}));
31119 layout.getRegion("center").showPanel(sp);
31120 layout.endUpdate();
31124 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31125 * @param {Object} config configuration options
31127 Roo.LayoutDialog = function(el, cfg){
31130 if (typeof(cfg) == 'undefined') {
31131 config = Roo.apply({}, el);
31132 // not sure why we use documentElement here.. - it should always be body.
31133 // IE7 borks horribly if we use documentElement.
31134 // webkit also does not like documentElement - it creates a body element...
31135 el = Roo.get( document.body || document.documentElement ).createChild();
31136 //config.autoCreate = true;
31140 config.autoTabs = false;
31141 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31142 this.body.setStyle({overflow:"hidden", position:"relative"});
31143 this.layout = new Roo.BorderLayout(this.body.dom, config);
31144 this.layout.monitorWindowResize = false;
31145 this.el.addClass("x-dlg-auto-layout");
31146 // fix case when center region overwrites center function
31147 this.center = Roo.BasicDialog.prototype.center;
31148 this.on("show", this.layout.layout, this.layout, true);
31149 if (config.items) {
31150 var xitems = config.items;
31151 delete config.items;
31152 Roo.each(xitems, this.addxtype, this);
31157 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31159 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31162 endUpdate : function(){
31163 this.layout.endUpdate();
31167 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31170 beginUpdate : function(){
31171 this.layout.beginUpdate();
31175 * Get the BorderLayout for this dialog
31176 * @return {Roo.BorderLayout}
31178 getLayout : function(){
31179 return this.layout;
31182 showEl : function(){
31183 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31185 this.layout.layout();
31190 // Use the syncHeightBeforeShow config option to control this automatically
31191 syncBodyHeight : function(){
31192 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31193 if(this.layout){this.layout.layout();}
31197 * Add an xtype element (actually adds to the layout.)
31198 * @return {Object} xdata xtype object data.
31201 addxtype : function(c) {
31202 return this.layout.addxtype(c);
31206 * Ext JS Library 1.1.1
31207 * Copyright(c) 2006-2007, Ext JS, LLC.
31209 * Originally Released Under LGPL - original licence link has changed is not relivant.
31212 * <script type="text/javascript">
31216 * @class Roo.MessageBox
31217 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31221 Roo.Msg.alert('Status', 'Changes saved successfully.');
31223 // Prompt for user data:
31224 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31226 // process text value...
31230 // Show a dialog using config options:
31232 title:'Save Changes?',
31233 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31234 buttons: Roo.Msg.YESNOCANCEL,
31241 Roo.MessageBox = function(){
31242 var dlg, opt, mask, waitTimer;
31243 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31244 var buttons, activeTextEl, bwidth;
31247 var handleButton = function(button){
31249 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31253 var handleHide = function(){
31254 if(opt && opt.cls){
31255 dlg.el.removeClass(opt.cls);
31258 Roo.TaskMgr.stop(waitTimer);
31264 var updateButtons = function(b){
31267 buttons["ok"].hide();
31268 buttons["cancel"].hide();
31269 buttons["yes"].hide();
31270 buttons["no"].hide();
31271 dlg.footer.dom.style.display = 'none';
31274 dlg.footer.dom.style.display = '';
31275 for(var k in buttons){
31276 if(typeof buttons[k] != "function"){
31279 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31280 width += buttons[k].el.getWidth()+15;
31290 var handleEsc = function(d, k, e){
31291 if(opt && opt.closable !== false){
31301 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31302 * @return {Roo.BasicDialog} The BasicDialog element
31304 getDialog : function(){
31306 dlg = new Roo.BasicDialog("x-msg-box", {
31311 constraintoviewport:false,
31313 collapsible : false,
31316 width:400, height:100,
31317 buttonAlign:"center",
31318 closeClick : function(){
31319 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31320 handleButton("no");
31322 handleButton("cancel");
31326 dlg.on("hide", handleHide);
31328 dlg.addKeyListener(27, handleEsc);
31330 var bt = this.buttonText;
31331 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31332 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31333 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31334 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31335 bodyEl = dlg.body.createChild({
31337 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>'
31339 msgEl = bodyEl.dom.firstChild;
31340 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31341 textboxEl.enableDisplayMode();
31342 textboxEl.addKeyListener([10,13], function(){
31343 if(dlg.isVisible() && opt && opt.buttons){
31344 if(opt.buttons.ok){
31345 handleButton("ok");
31346 }else if(opt.buttons.yes){
31347 handleButton("yes");
31351 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31352 textareaEl.enableDisplayMode();
31353 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31354 progressEl.enableDisplayMode();
31355 var pf = progressEl.dom.firstChild;
31357 pp = Roo.get(pf.firstChild);
31358 pp.setHeight(pf.offsetHeight);
31366 * Updates the message box body text
31367 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31368 * the XHTML-compliant non-breaking space character '&#160;')
31369 * @return {Roo.MessageBox} This message box
31371 updateText : function(text){
31372 if(!dlg.isVisible() && !opt.width){
31373 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31375 msgEl.innerHTML = text || ' ';
31377 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31378 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31380 Math.min(opt.width || cw , this.maxWidth),
31381 Math.max(opt.minWidth || this.minWidth, bwidth)
31384 activeTextEl.setWidth(w);
31386 if(dlg.isVisible()){
31387 dlg.fixedcenter = false;
31389 // to big, make it scroll. = But as usual stupid IE does not support
31392 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31393 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31394 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31396 bodyEl.dom.style.height = '';
31397 bodyEl.dom.style.overflowY = '';
31400 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31402 bodyEl.dom.style.overflowX = '';
31405 dlg.setContentSize(w, bodyEl.getHeight());
31406 if(dlg.isVisible()){
31407 dlg.fixedcenter = true;
31413 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31414 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31415 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31416 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31417 * @return {Roo.MessageBox} This message box
31419 updateProgress : function(value, text){
31421 this.updateText(text);
31423 if (pp) { // weird bug on my firefox - for some reason this is not defined
31424 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31430 * Returns true if the message box is currently displayed
31431 * @return {Boolean} True if the message box is visible, else false
31433 isVisible : function(){
31434 return dlg && dlg.isVisible();
31438 * Hides the message box if it is displayed
31441 if(this.isVisible()){
31447 * Displays a new message box, or reinitializes an existing message box, based on the config options
31448 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31449 * The following config object properties are supported:
31451 Property Type Description
31452 ---------- --------------- ------------------------------------------------------------------------------------
31453 animEl String/Element An id or Element from which the message box should animate as it opens and
31454 closes (defaults to undefined)
31455 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31456 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31457 closable Boolean False to hide the top-right close button (defaults to true). Note that
31458 progress and wait dialogs will ignore this property and always hide the
31459 close button as they can only be closed programmatically.
31460 cls String A custom CSS class to apply to the message box element
31461 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31462 displayed (defaults to 75)
31463 fn Function A callback function to execute after closing the dialog. The arguments to the
31464 function will be btn (the name of the button that was clicked, if applicable,
31465 e.g. "ok"), and text (the value of the active text field, if applicable).
31466 Progress and wait dialogs will ignore this option since they do not respond to
31467 user actions and can only be closed programmatically, so any required function
31468 should be called by the same code after it closes the dialog.
31469 icon String A CSS class that provides a background image to be used as an icon for
31470 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31471 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31472 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31473 modal Boolean False to allow user interaction with the page while the message box is
31474 displayed (defaults to true)
31475 msg String A string that will replace the existing message box body text (defaults
31476 to the XHTML-compliant non-breaking space character ' ')
31477 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31478 progress Boolean True to display a progress bar (defaults to false)
31479 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31480 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31481 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31482 title String The title text
31483 value String The string value to set into the active textbox element if displayed
31484 wait Boolean True to display a progress bar (defaults to false)
31485 width Number The width of the dialog in pixels
31492 msg: 'Please enter your address:',
31494 buttons: Roo.MessageBox.OKCANCEL,
31497 animEl: 'addAddressBtn'
31500 * @param {Object} config Configuration options
31501 * @return {Roo.MessageBox} This message box
31503 show : function(options)
31506 // this causes nightmares if you show one dialog after another
31507 // especially on callbacks..
31509 if(this.isVisible()){
31512 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31513 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31514 Roo.log("New Dialog Message:" + options.msg )
31515 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31516 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31519 var d = this.getDialog();
31521 d.setTitle(opt.title || " ");
31522 d.close.setDisplayed(opt.closable !== false);
31523 activeTextEl = textboxEl;
31524 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31529 textareaEl.setHeight(typeof opt.multiline == "number" ?
31530 opt.multiline : this.defaultTextHeight);
31531 activeTextEl = textareaEl;
31540 progressEl.setDisplayed(opt.progress === true);
31541 this.updateProgress(0);
31542 activeTextEl.dom.value = opt.value || "";
31544 dlg.setDefaultButton(activeTextEl);
31546 var bs = opt.buttons;
31549 db = buttons["ok"];
31550 }else if(bs && bs.yes){
31551 db = buttons["yes"];
31553 dlg.setDefaultButton(db);
31555 bwidth = updateButtons(opt.buttons);
31556 this.updateText(opt.msg);
31558 d.el.addClass(opt.cls);
31560 d.proxyDrag = opt.proxyDrag === true;
31561 d.modal = opt.modal !== false;
31562 d.mask = opt.modal !== false ? mask : false;
31563 if(!d.isVisible()){
31564 // force it to the end of the z-index stack so it gets a cursor in FF
31565 document.body.appendChild(dlg.el.dom);
31566 d.animateTarget = null;
31567 d.show(options.animEl);
31573 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31574 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31575 * and closing the message box when the process is complete.
31576 * @param {String} title The title bar text
31577 * @param {String} msg The message box body text
31578 * @return {Roo.MessageBox} This message box
31580 progress : function(title, msg){
31587 minWidth: this.minProgressWidth,
31594 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31595 * If a callback function is passed it will be called after the user clicks the button, and the
31596 * id of the button that was clicked will be passed as the only parameter to the callback
31597 * (could also be the top-right close button).
31598 * @param {String} title The title bar text
31599 * @param {String} msg The message box body text
31600 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31601 * @param {Object} scope (optional) The scope of the callback function
31602 * @return {Roo.MessageBox} This message box
31604 alert : function(title, msg, fn, scope){
31617 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31618 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31619 * You are responsible for closing the message box when the process is complete.
31620 * @param {String} msg The message box body text
31621 * @param {String} title (optional) The title bar text
31622 * @return {Roo.MessageBox} This message box
31624 wait : function(msg, title){
31635 waitTimer = Roo.TaskMgr.start({
31637 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31645 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31646 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31647 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31648 * @param {String} title The title bar text
31649 * @param {String} msg The message box body text
31650 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31651 * @param {Object} scope (optional) The scope of the callback function
31652 * @return {Roo.MessageBox} This message box
31654 confirm : function(title, msg, fn, scope){
31658 buttons: this.YESNO,
31667 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31668 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31669 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31670 * (could also be the top-right close button) and the text that was entered will be passed as the two
31671 * parameters to the callback.
31672 * @param {String} title The title bar text
31673 * @param {String} msg The message box body text
31674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31675 * @param {Object} scope (optional) The scope of the callback function
31676 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31677 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31678 * @return {Roo.MessageBox} This message box
31680 prompt : function(title, msg, fn, scope, multiline){
31684 buttons: this.OKCANCEL,
31689 multiline: multiline,
31696 * Button config that displays a single OK button
31701 * Button config that displays Yes and No buttons
31704 YESNO : {yes:true, no:true},
31706 * Button config that displays OK and Cancel buttons
31709 OKCANCEL : {ok:true, cancel:true},
31711 * Button config that displays Yes, No and Cancel buttons
31714 YESNOCANCEL : {yes:true, no:true, cancel:true},
31717 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31720 defaultTextHeight : 75,
31722 * The maximum width in pixels of the message box (defaults to 600)
31727 * The minimum width in pixels of the message box (defaults to 100)
31732 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31733 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31736 minProgressWidth : 250,
31738 * An object containing the default button text strings that can be overriden for localized language support.
31739 * Supported properties are: ok, cancel, yes and no.
31740 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31753 * Shorthand for {@link Roo.MessageBox}
31755 Roo.Msg = Roo.MessageBox;/*
31757 * Ext JS Library 1.1.1
31758 * Copyright(c) 2006-2007, Ext JS, LLC.
31760 * Originally Released Under LGPL - original licence link has changed is not relivant.
31763 * <script type="text/javascript">
31766 * @class Roo.QuickTips
31767 * Provides attractive and customizable tooltips for any element.
31770 Roo.QuickTips = function(){
31771 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31772 var ce, bd, xy, dd;
31773 var visible = false, disabled = true, inited = false;
31774 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31776 var onOver = function(e){
31780 var t = e.getTarget();
31781 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31784 if(ce && t == ce.el){
31785 clearTimeout(hideProc);
31788 if(t && tagEls[t.id]){
31789 tagEls[t.id].el = t;
31790 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31793 var ttp, et = Roo.fly(t);
31794 var ns = cfg.namespace;
31795 if(tm.interceptTitles && t.title){
31798 t.removeAttribute("title");
31799 e.preventDefault();
31801 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31804 showProc = show.defer(tm.showDelay, tm, [{
31807 width: et.getAttributeNS(ns, cfg.width),
31808 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31809 title: et.getAttributeNS(ns, cfg.title),
31810 cls: et.getAttributeNS(ns, cfg.cls)
31815 var onOut = function(e){
31816 clearTimeout(showProc);
31817 var t = e.getTarget();
31818 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31819 hideProc = setTimeout(hide, tm.hideDelay);
31823 var onMove = function(e){
31829 if(tm.trackMouse && ce){
31834 var onDown = function(e){
31835 clearTimeout(showProc);
31836 clearTimeout(hideProc);
31838 if(tm.hideOnClick){
31841 tm.enable.defer(100, tm);
31846 var getPad = function(){
31847 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31850 var show = function(o){
31854 clearTimeout(dismissProc);
31856 if(removeCls){ // in case manually hidden
31857 el.removeClass(removeCls);
31861 el.addClass(ce.cls);
31862 removeCls = ce.cls;
31865 tipTitle.update(ce.title);
31868 tipTitle.update('');
31871 el.dom.style.width = tm.maxWidth+'px';
31872 //tipBody.dom.style.width = '';
31873 tipBodyText.update(o.text);
31874 var p = getPad(), w = ce.width;
31876 var td = tipBodyText.dom;
31877 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31878 if(aw > tm.maxWidth){
31880 }else if(aw < tm.minWidth){
31886 //tipBody.setWidth(w);
31887 el.setWidth(parseInt(w, 10) + p);
31888 if(ce.autoHide === false){
31889 close.setDisplayed(true);
31894 close.setDisplayed(false);
31900 el.avoidY = xy[1]-18;
31905 el.setStyle("visibility", "visible");
31906 el.fadeIn({callback: afterShow});
31912 var afterShow = function(){
31916 if(tm.autoDismiss && ce.autoHide !== false){
31917 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31922 var hide = function(noanim){
31923 clearTimeout(dismissProc);
31924 clearTimeout(hideProc);
31926 if(el.isVisible()){
31928 if(noanim !== true && tm.animate){
31929 el.fadeOut({callback: afterHide});
31936 var afterHide = function(){
31939 el.removeClass(removeCls);
31946 * @cfg {Number} minWidth
31947 * The minimum width of the quick tip (defaults to 40)
31951 * @cfg {Number} maxWidth
31952 * The maximum width of the quick tip (defaults to 300)
31956 * @cfg {Boolean} interceptTitles
31957 * True to automatically use the element's DOM title value if available (defaults to false)
31959 interceptTitles : false,
31961 * @cfg {Boolean} trackMouse
31962 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31964 trackMouse : false,
31966 * @cfg {Boolean} hideOnClick
31967 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31969 hideOnClick : true,
31971 * @cfg {Number} showDelay
31972 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31976 * @cfg {Number} hideDelay
31977 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31981 * @cfg {Boolean} autoHide
31982 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31983 * Used in conjunction with hideDelay.
31988 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31989 * (defaults to true). Used in conjunction with autoDismissDelay.
31991 autoDismiss : true,
31994 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31996 autoDismissDelay : 5000,
31998 * @cfg {Boolean} animate
31999 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32004 * @cfg {String} title
32005 * Title text to display (defaults to ''). This can be any valid HTML markup.
32009 * @cfg {String} text
32010 * Body text to display (defaults to ''). This can be any valid HTML markup.
32014 * @cfg {String} cls
32015 * A CSS class to apply to the base quick tip element (defaults to '').
32019 * @cfg {Number} width
32020 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32021 * minWidth or maxWidth.
32026 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32027 * or display QuickTips in a page.
32030 tm = Roo.QuickTips;
32031 cfg = tm.tagConfig;
32033 if(!Roo.isReady){ // allow calling of init() before onReady
32034 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32037 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32038 el.fxDefaults = {stopFx: true};
32039 // maximum custom styling
32040 //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>');
32041 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>');
32042 tipTitle = el.child('h3');
32043 tipTitle.enableDisplayMode("block");
32044 tipBody = el.child('div.x-tip-bd');
32045 tipBodyText = el.child('div.x-tip-bd-inner');
32046 //bdLeft = el.child('div.x-tip-bd-left');
32047 //bdRight = el.child('div.x-tip-bd-right');
32048 close = el.child('div.x-tip-close');
32049 close.enableDisplayMode("block");
32050 close.on("click", hide);
32051 var d = Roo.get(document);
32052 d.on("mousedown", onDown);
32053 d.on("mouseover", onOver);
32054 d.on("mouseout", onOut);
32055 d.on("mousemove", onMove);
32056 esc = d.addKeyListener(27, hide);
32059 dd = el.initDD("default", null, {
32060 onDrag : function(){
32064 dd.setHandleElId(tipTitle.id);
32073 * Configures a new quick tip instance and assigns it to a target element. The following config options
32076 Property Type Description
32077 ---------- --------------------- ------------------------------------------------------------------------
32078 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32080 * @param {Object} config The config object
32082 register : function(config){
32083 var cs = config instanceof Array ? config : arguments;
32084 for(var i = 0, len = cs.length; i < len; i++) {
32086 var target = c.target;
32088 if(target instanceof Array){
32089 for(var j = 0, jlen = target.length; j < jlen; j++){
32090 tagEls[target[j]] = c;
32093 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32100 * Removes this quick tip from its element and destroys it.
32101 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32103 unregister : function(el){
32104 delete tagEls[Roo.id(el)];
32108 * Enable this quick tip.
32110 enable : function(){
32111 if(inited && disabled){
32113 if(locks.length < 1){
32120 * Disable this quick tip.
32122 disable : function(){
32124 clearTimeout(showProc);
32125 clearTimeout(hideProc);
32126 clearTimeout(dismissProc);
32134 * Returns true if the quick tip is enabled, else false.
32136 isEnabled : function(){
32143 attribute : "qtip",
32153 // backwards compat
32154 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32156 * Ext JS Library 1.1.1
32157 * Copyright(c) 2006-2007, Ext JS, LLC.
32159 * Originally Released Under LGPL - original licence link has changed is not relivant.
32162 * <script type="text/javascript">
32167 * @class Roo.tree.TreePanel
32168 * @extends Roo.data.Tree
32170 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32171 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32172 * @cfg {Boolean} enableDD true to enable drag and drop
32173 * @cfg {Boolean} enableDrag true to enable just drag
32174 * @cfg {Boolean} enableDrop true to enable just drop
32175 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32176 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32177 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32178 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32179 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32180 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32181 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32182 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32183 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32184 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32185 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32186 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32187 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32188 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32189 * @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>
32190 * @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>
32193 * @param {String/HTMLElement/Element} el The container element
32194 * @param {Object} config
32196 Roo.tree.TreePanel = function(el, config){
32198 var loader = false;
32200 root = config.root;
32201 delete config.root;
32203 if (config.loader) {
32204 loader = config.loader;
32205 delete config.loader;
32208 Roo.apply(this, config);
32209 Roo.tree.TreePanel.superclass.constructor.call(this);
32210 this.el = Roo.get(el);
32211 this.el.addClass('x-tree');
32212 //console.log(root);
32214 this.setRootNode( Roo.factory(root, Roo.tree));
32217 this.loader = Roo.factory(loader, Roo.tree);
32220 * Read-only. The id of the container element becomes this TreePanel's id.
32222 this.id = this.el.id;
32225 * @event beforeload
32226 * Fires before a node is loaded, return false to cancel
32227 * @param {Node} node The node being loaded
32229 "beforeload" : true,
32232 * Fires when a node is loaded
32233 * @param {Node} node The node that was loaded
32237 * @event textchange
32238 * Fires when the text for a node is changed
32239 * @param {Node} node The node
32240 * @param {String} text The new text
32241 * @param {String} oldText The old text
32243 "textchange" : true,
32245 * @event beforeexpand
32246 * Fires before a node is expanded, return false to cancel.
32247 * @param {Node} node The node
32248 * @param {Boolean} deep
32249 * @param {Boolean} anim
32251 "beforeexpand" : true,
32253 * @event beforecollapse
32254 * Fires before a node is collapsed, return false to cancel.
32255 * @param {Node} node The node
32256 * @param {Boolean} deep
32257 * @param {Boolean} anim
32259 "beforecollapse" : true,
32262 * Fires when a node is expanded
32263 * @param {Node} node The node
32267 * @event disabledchange
32268 * Fires when the disabled status of a node changes
32269 * @param {Node} node The node
32270 * @param {Boolean} disabled
32272 "disabledchange" : true,
32275 * Fires when a node is collapsed
32276 * @param {Node} node The node
32280 * @event beforeclick
32281 * Fires before click processing on a node. Return false to cancel the default action.
32282 * @param {Node} node The node
32283 * @param {Roo.EventObject} e The event object
32285 "beforeclick":true,
32287 * @event checkchange
32288 * Fires when a node with a checkbox's checked property changes
32289 * @param {Node} this This node
32290 * @param {Boolean} checked
32292 "checkchange":true,
32295 * Fires when a node is clicked
32296 * @param {Node} node The node
32297 * @param {Roo.EventObject} e The event object
32302 * Fires when a node is double clicked
32303 * @param {Node} node The node
32304 * @param {Roo.EventObject} e The event object
32308 * @event contextmenu
32309 * Fires when a node is right clicked
32310 * @param {Node} node The node
32311 * @param {Roo.EventObject} e The event object
32313 "contextmenu":true,
32315 * @event beforechildrenrendered
32316 * Fires right before the child nodes for a node are rendered
32317 * @param {Node} node The node
32319 "beforechildrenrendered":true,
32322 * Fires when a node starts being dragged
32323 * @param {Roo.tree.TreePanel} this
32324 * @param {Roo.tree.TreeNode} node
32325 * @param {event} e The raw browser event
32327 "startdrag" : true,
32330 * Fires when a drag operation is complete
32331 * @param {Roo.tree.TreePanel} this
32332 * @param {Roo.tree.TreeNode} node
32333 * @param {event} e The raw browser event
32338 * Fires when a dragged node is dropped on a valid DD target
32339 * @param {Roo.tree.TreePanel} this
32340 * @param {Roo.tree.TreeNode} node
32341 * @param {DD} dd The dd it was dropped on
32342 * @param {event} e The raw browser event
32346 * @event beforenodedrop
32347 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32348 * passed to handlers has the following properties:<br />
32349 * <ul style="padding:5px;padding-left:16px;">
32350 * <li>tree - The TreePanel</li>
32351 * <li>target - The node being targeted for the drop</li>
32352 * <li>data - The drag data from the drag source</li>
32353 * <li>point - The point of the drop - append, above or below</li>
32354 * <li>source - The drag source</li>
32355 * <li>rawEvent - Raw mouse event</li>
32356 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32357 * to be inserted by setting them on this object.</li>
32358 * <li>cancel - Set this to true to cancel the drop.</li>
32360 * @param {Object} dropEvent
32362 "beforenodedrop" : true,
32365 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32366 * passed to handlers has the following properties:<br />
32367 * <ul style="padding:5px;padding-left:16px;">
32368 * <li>tree - The TreePanel</li>
32369 * <li>target - The node being targeted for the drop</li>
32370 * <li>data - The drag data from the drag source</li>
32371 * <li>point - The point of the drop - append, above or below</li>
32372 * <li>source - The drag source</li>
32373 * <li>rawEvent - Raw mouse event</li>
32374 * <li>dropNode - Dropped node(s).</li>
32376 * @param {Object} dropEvent
32380 * @event nodedragover
32381 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32382 * passed to handlers has the following properties:<br />
32383 * <ul style="padding:5px;padding-left:16px;">
32384 * <li>tree - The TreePanel</li>
32385 * <li>target - The node being targeted for the drop</li>
32386 * <li>data - The drag data from the drag source</li>
32387 * <li>point - The point of the drop - append, above or below</li>
32388 * <li>source - The drag source</li>
32389 * <li>rawEvent - Raw mouse event</li>
32390 * <li>dropNode - Drop node(s) provided by the source.</li>
32391 * <li>cancel - Set this to true to signal drop not allowed.</li>
32393 * @param {Object} dragOverEvent
32395 "nodedragover" : true
32398 if(this.singleExpand){
32399 this.on("beforeexpand", this.restrictExpand, this);
32402 this.editor.tree = this;
32403 this.editor = Roo.factory(this.editor, Roo.tree);
32406 if (this.selModel) {
32407 this.selModel = Roo.factory(this.selModel, Roo.tree);
32411 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32412 rootVisible : true,
32413 animate: Roo.enableFx,
32416 hlDrop : Roo.enableFx,
32420 rendererTip: false,
32422 restrictExpand : function(node){
32423 var p = node.parentNode;
32425 if(p.expandedChild && p.expandedChild.parentNode == p){
32426 p.expandedChild.collapse();
32428 p.expandedChild = node;
32432 // private override
32433 setRootNode : function(node){
32434 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32435 if(!this.rootVisible){
32436 node.ui = new Roo.tree.RootTreeNodeUI(node);
32442 * Returns the container element for this TreePanel
32444 getEl : function(){
32449 * Returns the default TreeLoader for this TreePanel
32451 getLoader : function(){
32452 return this.loader;
32458 expandAll : function(){
32459 this.root.expand(true);
32463 * Collapse all nodes
32465 collapseAll : function(){
32466 this.root.collapse(true);
32470 * Returns the selection model used by this TreePanel
32472 getSelectionModel : function(){
32473 if(!this.selModel){
32474 this.selModel = new Roo.tree.DefaultSelectionModel();
32476 return this.selModel;
32480 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32481 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32482 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32485 getChecked : function(a, startNode){
32486 startNode = startNode || this.root;
32488 var f = function(){
32489 if(this.attributes.checked){
32490 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32493 startNode.cascade(f);
32498 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32499 * @param {String} path
32500 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32501 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32502 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32504 expandPath : function(path, attr, callback){
32505 attr = attr || "id";
32506 var keys = path.split(this.pathSeparator);
32507 var curNode = this.root;
32508 if(curNode.attributes[attr] != keys[1]){ // invalid root
32510 callback(false, null);
32515 var f = function(){
32516 if(++index == keys.length){
32518 callback(true, curNode);
32522 var c = curNode.findChild(attr, keys[index]);
32525 callback(false, curNode);
32530 c.expand(false, false, f);
32532 curNode.expand(false, false, f);
32536 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32537 * @param {String} path
32538 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32539 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32540 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32542 selectPath : function(path, attr, callback){
32543 attr = attr || "id";
32544 var keys = path.split(this.pathSeparator);
32545 var v = keys.pop();
32546 if(keys.length > 0){
32547 var f = function(success, node){
32548 if(success && node){
32549 var n = node.findChild(attr, v);
32555 }else if(callback){
32556 callback(false, n);
32560 callback(false, n);
32564 this.expandPath(keys.join(this.pathSeparator), attr, f);
32566 this.root.select();
32568 callback(true, this.root);
32573 getTreeEl : function(){
32578 * Trigger rendering of this TreePanel
32580 render : function(){
32581 if (this.innerCt) {
32582 return this; // stop it rendering more than once!!
32585 this.innerCt = this.el.createChild({tag:"ul",
32586 cls:"x-tree-root-ct " +
32587 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32589 if(this.containerScroll){
32590 Roo.dd.ScrollManager.register(this.el);
32592 if((this.enableDD || this.enableDrop) && !this.dropZone){
32594 * The dropZone used by this tree if drop is enabled
32595 * @type Roo.tree.TreeDropZone
32597 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32598 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32601 if((this.enableDD || this.enableDrag) && !this.dragZone){
32603 * The dragZone used by this tree if drag is enabled
32604 * @type Roo.tree.TreeDragZone
32606 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32607 ddGroup: this.ddGroup || "TreeDD",
32608 scroll: this.ddScroll
32611 this.getSelectionModel().init(this);
32613 Roo.log("ROOT not set in tree");
32616 this.root.render();
32617 if(!this.rootVisible){
32618 this.root.renderChildren();
32624 * Ext JS Library 1.1.1
32625 * Copyright(c) 2006-2007, Ext JS, LLC.
32627 * Originally Released Under LGPL - original licence link has changed is not relivant.
32630 * <script type="text/javascript">
32635 * @class Roo.tree.DefaultSelectionModel
32636 * @extends Roo.util.Observable
32637 * The default single selection for a TreePanel.
32638 * @param {Object} cfg Configuration
32640 Roo.tree.DefaultSelectionModel = function(cfg){
32641 this.selNode = null;
32647 * @event selectionchange
32648 * Fires when the selected node changes
32649 * @param {DefaultSelectionModel} this
32650 * @param {TreeNode} node the new selection
32652 "selectionchange" : true,
32655 * @event beforeselect
32656 * Fires before the selected node changes, return false to cancel the change
32657 * @param {DefaultSelectionModel} this
32658 * @param {TreeNode} node the new selection
32659 * @param {TreeNode} node the old selection
32661 "beforeselect" : true
32664 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32667 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32668 init : function(tree){
32670 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32671 tree.on("click", this.onNodeClick, this);
32674 onNodeClick : function(node, e){
32675 if (e.ctrlKey && this.selNode == node) {
32676 this.unselect(node);
32684 * @param {TreeNode} node The node to select
32685 * @return {TreeNode} The selected node
32687 select : function(node){
32688 var last = this.selNode;
32689 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32691 last.ui.onSelectedChange(false);
32693 this.selNode = node;
32694 node.ui.onSelectedChange(true);
32695 this.fireEvent("selectionchange", this, node, last);
32702 * @param {TreeNode} node The node to unselect
32704 unselect : function(node){
32705 if(this.selNode == node){
32706 this.clearSelections();
32711 * Clear all selections
32713 clearSelections : function(){
32714 var n = this.selNode;
32716 n.ui.onSelectedChange(false);
32717 this.selNode = null;
32718 this.fireEvent("selectionchange", this, null);
32724 * Get the selected node
32725 * @return {TreeNode} The selected node
32727 getSelectedNode : function(){
32728 return this.selNode;
32732 * Returns true if the node is selected
32733 * @param {TreeNode} node The node to check
32734 * @return {Boolean}
32736 isSelected : function(node){
32737 return this.selNode == node;
32741 * Selects the node above the selected node in the tree, intelligently walking the nodes
32742 * @return TreeNode The new selection
32744 selectPrevious : function(){
32745 var s = this.selNode || this.lastSelNode;
32749 var ps = s.previousSibling;
32751 if(!ps.isExpanded() || ps.childNodes.length < 1){
32752 return this.select(ps);
32754 var lc = ps.lastChild;
32755 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32758 return this.select(lc);
32760 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32761 return this.select(s.parentNode);
32767 * Selects the node above the selected node in the tree, intelligently walking the nodes
32768 * @return TreeNode The new selection
32770 selectNext : function(){
32771 var s = this.selNode || this.lastSelNode;
32775 if(s.firstChild && s.isExpanded()){
32776 return this.select(s.firstChild);
32777 }else if(s.nextSibling){
32778 return this.select(s.nextSibling);
32779 }else if(s.parentNode){
32781 s.parentNode.bubble(function(){
32782 if(this.nextSibling){
32783 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32792 onKeyDown : function(e){
32793 var s = this.selNode || this.lastSelNode;
32794 // undesirable, but required
32799 var k = e.getKey();
32807 this.selectPrevious();
32810 e.preventDefault();
32811 if(s.hasChildNodes()){
32812 if(!s.isExpanded()){
32814 }else if(s.firstChild){
32815 this.select(s.firstChild, e);
32820 e.preventDefault();
32821 if(s.hasChildNodes() && s.isExpanded()){
32823 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32824 this.select(s.parentNode, e);
32832 * @class Roo.tree.MultiSelectionModel
32833 * @extends Roo.util.Observable
32834 * Multi selection for a TreePanel.
32835 * @param {Object} cfg Configuration
32837 Roo.tree.MultiSelectionModel = function(){
32838 this.selNodes = [];
32842 * @event selectionchange
32843 * Fires when the selected nodes change
32844 * @param {MultiSelectionModel} this
32845 * @param {Array} nodes Array of the selected nodes
32847 "selectionchange" : true
32849 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32853 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32854 init : function(tree){
32856 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32857 tree.on("click", this.onNodeClick, this);
32860 onNodeClick : function(node, e){
32861 this.select(node, e, e.ctrlKey);
32866 * @param {TreeNode} node The node to select
32867 * @param {EventObject} e (optional) An event associated with the selection
32868 * @param {Boolean} keepExisting True to retain existing selections
32869 * @return {TreeNode} The selected node
32871 select : function(node, e, keepExisting){
32872 if(keepExisting !== true){
32873 this.clearSelections(true);
32875 if(this.isSelected(node)){
32876 this.lastSelNode = node;
32879 this.selNodes.push(node);
32880 this.selMap[node.id] = node;
32881 this.lastSelNode = node;
32882 node.ui.onSelectedChange(true);
32883 this.fireEvent("selectionchange", this, this.selNodes);
32889 * @param {TreeNode} node The node to unselect
32891 unselect : function(node){
32892 if(this.selMap[node.id]){
32893 node.ui.onSelectedChange(false);
32894 var sn = this.selNodes;
32897 index = sn.indexOf(node);
32899 for(var i = 0, len = sn.length; i < len; i++){
32907 this.selNodes.splice(index, 1);
32909 delete this.selMap[node.id];
32910 this.fireEvent("selectionchange", this, this.selNodes);
32915 * Clear all selections
32917 clearSelections : function(suppressEvent){
32918 var sn = this.selNodes;
32920 for(var i = 0, len = sn.length; i < len; i++){
32921 sn[i].ui.onSelectedChange(false);
32923 this.selNodes = [];
32925 if(suppressEvent !== true){
32926 this.fireEvent("selectionchange", this, this.selNodes);
32932 * Returns true if the node is selected
32933 * @param {TreeNode} node The node to check
32934 * @return {Boolean}
32936 isSelected : function(node){
32937 return this.selMap[node.id] ? true : false;
32941 * Returns an array of the selected nodes
32944 getSelectedNodes : function(){
32945 return this.selNodes;
32948 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32950 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32952 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32955 * Ext JS Library 1.1.1
32956 * Copyright(c) 2006-2007, Ext JS, LLC.
32958 * Originally Released Under LGPL - original licence link has changed is not relivant.
32961 * <script type="text/javascript">
32965 * @class Roo.tree.TreeNode
32966 * @extends Roo.data.Node
32967 * @cfg {String} text The text for this node
32968 * @cfg {Boolean} expanded true to start the node expanded
32969 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32970 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32971 * @cfg {Boolean} disabled true to start the node disabled
32972 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32973 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32974 * @cfg {String} cls A css class to be added to the node
32975 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32976 * @cfg {String} href URL of the link used for the node (defaults to #)
32977 * @cfg {String} hrefTarget target frame for the link
32978 * @cfg {String} qtip An Ext QuickTip for the node
32979 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32980 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32981 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32982 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32983 * (defaults to undefined with no checkbox rendered)
32985 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32987 Roo.tree.TreeNode = function(attributes){
32988 attributes = attributes || {};
32989 if(typeof attributes == "string"){
32990 attributes = {text: attributes};
32992 this.childrenRendered = false;
32993 this.rendered = false;
32994 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32995 this.expanded = attributes.expanded === true;
32996 this.isTarget = attributes.isTarget !== false;
32997 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32998 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33001 * Read-only. The text for this node. To change it use setText().
33004 this.text = attributes.text;
33006 * True if this node is disabled.
33009 this.disabled = attributes.disabled === true;
33013 * @event textchange
33014 * Fires when the text for this node is changed
33015 * @param {Node} this This node
33016 * @param {String} text The new text
33017 * @param {String} oldText The old text
33019 "textchange" : true,
33021 * @event beforeexpand
33022 * Fires before this node is expanded, return false to cancel.
33023 * @param {Node} this This node
33024 * @param {Boolean} deep
33025 * @param {Boolean} anim
33027 "beforeexpand" : true,
33029 * @event beforecollapse
33030 * Fires before this node is collapsed, return false to cancel.
33031 * @param {Node} this This node
33032 * @param {Boolean} deep
33033 * @param {Boolean} anim
33035 "beforecollapse" : true,
33038 * Fires when this node is expanded
33039 * @param {Node} this This node
33043 * @event disabledchange
33044 * Fires when the disabled status of this node changes
33045 * @param {Node} this This node
33046 * @param {Boolean} disabled
33048 "disabledchange" : true,
33051 * Fires when this node is collapsed
33052 * @param {Node} this This node
33056 * @event beforeclick
33057 * Fires before click processing. Return false to cancel the default action.
33058 * @param {Node} this This node
33059 * @param {Roo.EventObject} e The event object
33061 "beforeclick":true,
33063 * @event checkchange
33064 * Fires when a node with a checkbox's checked property changes
33065 * @param {Node} this This node
33066 * @param {Boolean} checked
33068 "checkchange":true,
33071 * Fires when this node is clicked
33072 * @param {Node} this This node
33073 * @param {Roo.EventObject} e The event object
33078 * Fires when this node is double clicked
33079 * @param {Node} this This node
33080 * @param {Roo.EventObject} e The event object
33084 * @event contextmenu
33085 * Fires when this node is right clicked
33086 * @param {Node} this This node
33087 * @param {Roo.EventObject} e The event object
33089 "contextmenu":true,
33091 * @event beforechildrenrendered
33092 * Fires right before the child nodes for this node are rendered
33093 * @param {Node} this This node
33095 "beforechildrenrendered":true
33098 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33101 * Read-only. The UI for this node
33104 this.ui = new uiClass(this);
33106 // finally support items[]
33107 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33112 Roo.each(this.attributes.items, function(c) {
33113 this.appendChild(Roo.factory(c,Roo.Tree));
33115 delete this.attributes.items;
33120 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33121 preventHScroll: true,
33123 * Returns true if this node is expanded
33124 * @return {Boolean}
33126 isExpanded : function(){
33127 return this.expanded;
33131 * Returns the UI object for this node
33132 * @return {TreeNodeUI}
33134 getUI : function(){
33138 // private override
33139 setFirstChild : function(node){
33140 var of = this.firstChild;
33141 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33142 if(this.childrenRendered && of && node != of){
33143 of.renderIndent(true, true);
33146 this.renderIndent(true, true);
33150 // private override
33151 setLastChild : function(node){
33152 var ol = this.lastChild;
33153 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33154 if(this.childrenRendered && ol && node != ol){
33155 ol.renderIndent(true, true);
33158 this.renderIndent(true, true);
33162 // these methods are overridden to provide lazy rendering support
33163 // private override
33164 appendChild : function()
33166 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33167 if(node && this.childrenRendered){
33170 this.ui.updateExpandIcon();
33174 // private override
33175 removeChild : function(node){
33176 this.ownerTree.getSelectionModel().unselect(node);
33177 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33178 // if it's been rendered remove dom node
33179 if(this.childrenRendered){
33182 if(this.childNodes.length < 1){
33183 this.collapse(false, false);
33185 this.ui.updateExpandIcon();
33187 if(!this.firstChild) {
33188 this.childrenRendered = false;
33193 // private override
33194 insertBefore : function(node, refNode){
33195 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33196 if(newNode && refNode && this.childrenRendered){
33199 this.ui.updateExpandIcon();
33204 * Sets the text for this node
33205 * @param {String} text
33207 setText : function(text){
33208 var oldText = this.text;
33210 this.attributes.text = text;
33211 if(this.rendered){ // event without subscribing
33212 this.ui.onTextChange(this, text, oldText);
33214 this.fireEvent("textchange", this, text, oldText);
33218 * Triggers selection of this node
33220 select : function(){
33221 this.getOwnerTree().getSelectionModel().select(this);
33225 * Triggers deselection of this node
33227 unselect : function(){
33228 this.getOwnerTree().getSelectionModel().unselect(this);
33232 * Returns true if this node is selected
33233 * @return {Boolean}
33235 isSelected : function(){
33236 return this.getOwnerTree().getSelectionModel().isSelected(this);
33240 * Expand this node.
33241 * @param {Boolean} deep (optional) True to expand all children as well
33242 * @param {Boolean} anim (optional) false to cancel the default animation
33243 * @param {Function} callback (optional) A callback to be called when
33244 * expanding this node completes (does not wait for deep expand to complete).
33245 * Called with 1 parameter, this node.
33247 expand : function(deep, anim, callback){
33248 if(!this.expanded){
33249 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33252 if(!this.childrenRendered){
33253 this.renderChildren();
33255 this.expanded = true;
33256 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33257 this.ui.animExpand(function(){
33258 this.fireEvent("expand", this);
33259 if(typeof callback == "function"){
33263 this.expandChildNodes(true);
33265 }.createDelegate(this));
33269 this.fireEvent("expand", this);
33270 if(typeof callback == "function"){
33275 if(typeof callback == "function"){
33280 this.expandChildNodes(true);
33284 isHiddenRoot : function(){
33285 return this.isRoot && !this.getOwnerTree().rootVisible;
33289 * Collapse this node.
33290 * @param {Boolean} deep (optional) True to collapse all children as well
33291 * @param {Boolean} anim (optional) false to cancel the default animation
33293 collapse : function(deep, anim){
33294 if(this.expanded && !this.isHiddenRoot()){
33295 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33298 this.expanded = false;
33299 if((this.getOwnerTree().animate && anim !== false) || anim){
33300 this.ui.animCollapse(function(){
33301 this.fireEvent("collapse", this);
33303 this.collapseChildNodes(true);
33305 }.createDelegate(this));
33308 this.ui.collapse();
33309 this.fireEvent("collapse", this);
33313 var cs = this.childNodes;
33314 for(var i = 0, len = cs.length; i < len; i++) {
33315 cs[i].collapse(true, false);
33321 delayedExpand : function(delay){
33322 if(!this.expandProcId){
33323 this.expandProcId = this.expand.defer(delay, this);
33328 cancelExpand : function(){
33329 if(this.expandProcId){
33330 clearTimeout(this.expandProcId);
33332 this.expandProcId = false;
33336 * Toggles expanded/collapsed state of the node
33338 toggle : function(){
33347 * Ensures all parent nodes are expanded
33349 ensureVisible : function(callback){
33350 var tree = this.getOwnerTree();
33351 tree.expandPath(this.parentNode.getPath(), false, function(){
33352 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33353 Roo.callback(callback);
33354 }.createDelegate(this));
33358 * Expand all child nodes
33359 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33361 expandChildNodes : function(deep){
33362 var cs = this.childNodes;
33363 for(var i = 0, len = cs.length; i < len; i++) {
33364 cs[i].expand(deep);
33369 * Collapse all child nodes
33370 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33372 collapseChildNodes : function(deep){
33373 var cs = this.childNodes;
33374 for(var i = 0, len = cs.length; i < len; i++) {
33375 cs[i].collapse(deep);
33380 * Disables this node
33382 disable : function(){
33383 this.disabled = true;
33385 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33386 this.ui.onDisableChange(this, true);
33388 this.fireEvent("disabledchange", this, true);
33392 * Enables this node
33394 enable : function(){
33395 this.disabled = false;
33396 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33397 this.ui.onDisableChange(this, false);
33399 this.fireEvent("disabledchange", this, false);
33403 renderChildren : function(suppressEvent){
33404 if(suppressEvent !== false){
33405 this.fireEvent("beforechildrenrendered", this);
33407 var cs = this.childNodes;
33408 for(var i = 0, len = cs.length; i < len; i++){
33409 cs[i].render(true);
33411 this.childrenRendered = true;
33415 sort : function(fn, scope){
33416 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33417 if(this.childrenRendered){
33418 var cs = this.childNodes;
33419 for(var i = 0, len = cs.length; i < len; i++){
33420 cs[i].render(true);
33426 render : function(bulkRender){
33427 this.ui.render(bulkRender);
33428 if(!this.rendered){
33429 this.rendered = true;
33431 this.expanded = false;
33432 this.expand(false, false);
33438 renderIndent : function(deep, refresh){
33440 this.ui.childIndent = null;
33442 this.ui.renderIndent();
33443 if(deep === true && this.childrenRendered){
33444 var cs = this.childNodes;
33445 for(var i = 0, len = cs.length; i < len; i++){
33446 cs[i].renderIndent(true, refresh);
33452 * Ext JS Library 1.1.1
33453 * Copyright(c) 2006-2007, Ext JS, LLC.
33455 * Originally Released Under LGPL - original licence link has changed is not relivant.
33458 * <script type="text/javascript">
33462 * @class Roo.tree.AsyncTreeNode
33463 * @extends Roo.tree.TreeNode
33464 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33466 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33468 Roo.tree.AsyncTreeNode = function(config){
33469 this.loaded = false;
33470 this.loading = false;
33471 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33473 * @event beforeload
33474 * Fires before this node is loaded, return false to cancel
33475 * @param {Node} this This node
33477 this.addEvents({'beforeload':true, 'load': true});
33480 * Fires when this node is loaded
33481 * @param {Node} this This node
33484 * The loader used by this node (defaults to using the tree's defined loader)
33489 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33490 expand : function(deep, anim, callback){
33491 if(this.loading){ // if an async load is already running, waiting til it's done
33493 var f = function(){
33494 if(!this.loading){ // done loading
33495 clearInterval(timer);
33496 this.expand(deep, anim, callback);
33498 }.createDelegate(this);
33499 timer = setInterval(f, 200);
33503 if(this.fireEvent("beforeload", this) === false){
33506 this.loading = true;
33507 this.ui.beforeLoad(this);
33508 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33510 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33514 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33518 * Returns true if this node is currently loading
33519 * @return {Boolean}
33521 isLoading : function(){
33522 return this.loading;
33525 loadComplete : function(deep, anim, callback){
33526 this.loading = false;
33527 this.loaded = true;
33528 this.ui.afterLoad(this);
33529 this.fireEvent("load", this);
33530 this.expand(deep, anim, callback);
33534 * Returns true if this node has been loaded
33535 * @return {Boolean}
33537 isLoaded : function(){
33538 return this.loaded;
33541 hasChildNodes : function(){
33542 if(!this.isLeaf() && !this.loaded){
33545 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33550 * Trigger a reload for this node
33551 * @param {Function} callback
33553 reload : function(callback){
33554 this.collapse(false, false);
33555 while(this.firstChild){
33556 this.removeChild(this.firstChild);
33558 this.childrenRendered = false;
33559 this.loaded = false;
33560 if(this.isHiddenRoot()){
33561 this.expanded = false;
33563 this.expand(false, false, callback);
33567 * Ext JS Library 1.1.1
33568 * Copyright(c) 2006-2007, Ext JS, LLC.
33570 * Originally Released Under LGPL - original licence link has changed is not relivant.
33573 * <script type="text/javascript">
33577 * @class Roo.tree.TreeNodeUI
33579 * @param {Object} node The node to render
33580 * The TreeNode UI implementation is separate from the
33581 * tree implementation. Unless you are customizing the tree UI,
33582 * you should never have to use this directly.
33584 Roo.tree.TreeNodeUI = function(node){
33586 this.rendered = false;
33587 this.animating = false;
33588 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33591 Roo.tree.TreeNodeUI.prototype = {
33592 removeChild : function(node){
33594 this.ctNode.removeChild(node.ui.getEl());
33598 beforeLoad : function(){
33599 this.addClass("x-tree-node-loading");
33602 afterLoad : function(){
33603 this.removeClass("x-tree-node-loading");
33606 onTextChange : function(node, text, oldText){
33608 this.textNode.innerHTML = text;
33612 onDisableChange : function(node, state){
33613 this.disabled = state;
33615 this.addClass("x-tree-node-disabled");
33617 this.removeClass("x-tree-node-disabled");
33621 onSelectedChange : function(state){
33624 this.addClass("x-tree-selected");
33627 this.removeClass("x-tree-selected");
33631 onMove : function(tree, node, oldParent, newParent, index, refNode){
33632 this.childIndent = null;
33634 var targetNode = newParent.ui.getContainer();
33635 if(!targetNode){//target not rendered
33636 this.holder = document.createElement("div");
33637 this.holder.appendChild(this.wrap);
33640 var insertBefore = refNode ? refNode.ui.getEl() : null;
33642 targetNode.insertBefore(this.wrap, insertBefore);
33644 targetNode.appendChild(this.wrap);
33646 this.node.renderIndent(true);
33650 addClass : function(cls){
33652 Roo.fly(this.elNode).addClass(cls);
33656 removeClass : function(cls){
33658 Roo.fly(this.elNode).removeClass(cls);
33662 remove : function(){
33664 this.holder = document.createElement("div");
33665 this.holder.appendChild(this.wrap);
33669 fireEvent : function(){
33670 return this.node.fireEvent.apply(this.node, arguments);
33673 initEvents : function(){
33674 this.node.on("move", this.onMove, this);
33675 var E = Roo.EventManager;
33676 var a = this.anchor;
33678 var el = Roo.fly(a, '_treeui');
33680 if(Roo.isOpera){ // opera render bug ignores the CSS
33681 el.setStyle("text-decoration", "none");
33684 el.on("click", this.onClick, this);
33685 el.on("dblclick", this.onDblClick, this);
33688 Roo.EventManager.on(this.checkbox,
33689 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33692 el.on("contextmenu", this.onContextMenu, this);
33694 var icon = Roo.fly(this.iconNode);
33695 icon.on("click", this.onClick, this);
33696 icon.on("dblclick", this.onDblClick, this);
33697 icon.on("contextmenu", this.onContextMenu, this);
33698 E.on(this.ecNode, "click", this.ecClick, this, true);
33700 if(this.node.disabled){
33701 this.addClass("x-tree-node-disabled");
33703 if(this.node.hidden){
33704 this.addClass("x-tree-node-disabled");
33706 var ot = this.node.getOwnerTree();
33707 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33708 if(dd && (!this.node.isRoot || ot.rootVisible)){
33709 Roo.dd.Registry.register(this.elNode, {
33711 handles: this.getDDHandles(),
33717 getDDHandles : function(){
33718 return [this.iconNode, this.textNode];
33723 this.wrap.style.display = "none";
33729 this.wrap.style.display = "";
33733 onContextMenu : function(e){
33734 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33735 e.preventDefault();
33737 this.fireEvent("contextmenu", this.node, e);
33741 onClick : function(e){
33746 if(this.fireEvent("beforeclick", this.node, e) !== false){
33747 if(!this.disabled && this.node.attributes.href){
33748 this.fireEvent("click", this.node, e);
33751 e.preventDefault();
33756 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33757 this.node.toggle();
33760 this.fireEvent("click", this.node, e);
33766 onDblClick : function(e){
33767 e.preventDefault();
33772 this.toggleCheck();
33774 if(!this.animating && this.node.hasChildNodes()){
33775 this.node.toggle();
33777 this.fireEvent("dblclick", this.node, e);
33780 onCheckChange : function(){
33781 var checked = this.checkbox.checked;
33782 this.node.attributes.checked = checked;
33783 this.fireEvent('checkchange', this.node, checked);
33786 ecClick : function(e){
33787 if(!this.animating && this.node.hasChildNodes()){
33788 this.node.toggle();
33792 startDrop : function(){
33793 this.dropping = true;
33796 // delayed drop so the click event doesn't get fired on a drop
33797 endDrop : function(){
33798 setTimeout(function(){
33799 this.dropping = false;
33800 }.createDelegate(this), 50);
33803 expand : function(){
33804 this.updateExpandIcon();
33805 this.ctNode.style.display = "";
33808 focus : function(){
33809 if(!this.node.preventHScroll){
33810 try{this.anchor.focus();
33812 }else if(!Roo.isIE){
33814 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33815 var l = noscroll.scrollLeft;
33816 this.anchor.focus();
33817 noscroll.scrollLeft = l;
33822 toggleCheck : function(value){
33823 var cb = this.checkbox;
33825 cb.checked = (value === undefined ? !cb.checked : value);
33831 this.anchor.blur();
33835 animExpand : function(callback){
33836 var ct = Roo.get(this.ctNode);
33838 if(!this.node.hasChildNodes()){
33839 this.updateExpandIcon();
33840 this.ctNode.style.display = "";
33841 Roo.callback(callback);
33844 this.animating = true;
33845 this.updateExpandIcon();
33848 callback : function(){
33849 this.animating = false;
33850 Roo.callback(callback);
33853 duration: this.node.ownerTree.duration || .25
33857 highlight : function(){
33858 var tree = this.node.getOwnerTree();
33859 Roo.fly(this.wrap).highlight(
33860 tree.hlColor || "C3DAF9",
33861 {endColor: tree.hlBaseColor}
33865 collapse : function(){
33866 this.updateExpandIcon();
33867 this.ctNode.style.display = "none";
33870 animCollapse : function(callback){
33871 var ct = Roo.get(this.ctNode);
33872 ct.enableDisplayMode('block');
33875 this.animating = true;
33876 this.updateExpandIcon();
33879 callback : function(){
33880 this.animating = false;
33881 Roo.callback(callback);
33884 duration: this.node.ownerTree.duration || .25
33888 getContainer : function(){
33889 return this.ctNode;
33892 getEl : function(){
33896 appendDDGhost : function(ghostNode){
33897 ghostNode.appendChild(this.elNode.cloneNode(true));
33900 getDDRepairXY : function(){
33901 return Roo.lib.Dom.getXY(this.iconNode);
33904 onRender : function(){
33908 render : function(bulkRender){
33909 var n = this.node, a = n.attributes;
33910 var targetNode = n.parentNode ?
33911 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33913 if(!this.rendered){
33914 this.rendered = true;
33916 this.renderElements(n, a, targetNode, bulkRender);
33919 if(this.textNode.setAttributeNS){
33920 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33922 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33925 this.textNode.setAttribute("ext:qtip", a.qtip);
33927 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33930 }else if(a.qtipCfg){
33931 a.qtipCfg.target = Roo.id(this.textNode);
33932 Roo.QuickTips.register(a.qtipCfg);
33935 if(!this.node.expanded){
33936 this.updateExpandIcon();
33939 if(bulkRender === true) {
33940 targetNode.appendChild(this.wrap);
33945 renderElements : function(n, a, targetNode, bulkRender)
33947 // add some indent caching, this helps performance when rendering a large tree
33948 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33949 var t = n.getOwnerTree();
33950 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33951 if (typeof(n.attributes.html) != 'undefined') {
33952 txt = n.attributes.html;
33954 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33955 var cb = typeof a.checked == 'boolean';
33956 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33957 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33958 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33959 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33960 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33961 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33962 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33963 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33964 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33965 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33968 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33969 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33970 n.nextSibling.ui.getEl(), buf.join(""));
33972 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33975 this.elNode = this.wrap.childNodes[0];
33976 this.ctNode = this.wrap.childNodes[1];
33977 var cs = this.elNode.childNodes;
33978 this.indentNode = cs[0];
33979 this.ecNode = cs[1];
33980 this.iconNode = cs[2];
33983 this.checkbox = cs[3];
33986 this.anchor = cs[index];
33987 this.textNode = cs[index].firstChild;
33990 getAnchor : function(){
33991 return this.anchor;
33994 getTextEl : function(){
33995 return this.textNode;
33998 getIconEl : function(){
33999 return this.iconNode;
34002 isChecked : function(){
34003 return this.checkbox ? this.checkbox.checked : false;
34006 updateExpandIcon : function(){
34008 var n = this.node, c1, c2;
34009 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34010 var hasChild = n.hasChildNodes();
34014 c1 = "x-tree-node-collapsed";
34015 c2 = "x-tree-node-expanded";
34018 c1 = "x-tree-node-expanded";
34019 c2 = "x-tree-node-collapsed";
34022 this.removeClass("x-tree-node-leaf");
34023 this.wasLeaf = false;
34025 if(this.c1 != c1 || this.c2 != c2){
34026 Roo.fly(this.elNode).replaceClass(c1, c2);
34027 this.c1 = c1; this.c2 = c2;
34030 // this changes non-leafs into leafs if they have no children.
34031 // it's not very rational behaviour..
34033 if(!this.wasLeaf && this.node.leaf){
34034 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34037 this.wasLeaf = true;
34040 var ecc = "x-tree-ec-icon "+cls;
34041 if(this.ecc != ecc){
34042 this.ecNode.className = ecc;
34048 getChildIndent : function(){
34049 if(!this.childIndent){
34053 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34055 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34057 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34062 this.childIndent = buf.join("");
34064 return this.childIndent;
34067 renderIndent : function(){
34070 var p = this.node.parentNode;
34072 indent = p.ui.getChildIndent();
34074 if(this.indentMarkup != indent){ // don't rerender if not required
34075 this.indentNode.innerHTML = indent;
34076 this.indentMarkup = indent;
34078 this.updateExpandIcon();
34083 Roo.tree.RootTreeNodeUI = function(){
34084 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34086 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34087 render : function(){
34088 if(!this.rendered){
34089 var targetNode = this.node.ownerTree.innerCt.dom;
34090 this.node.expanded = true;
34091 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34092 this.wrap = this.ctNode = targetNode.firstChild;
34095 collapse : function(){
34097 expand : function(){
34101 * Ext JS Library 1.1.1
34102 * Copyright(c) 2006-2007, Ext JS, LLC.
34104 * Originally Released Under LGPL - original licence link has changed is not relivant.
34107 * <script type="text/javascript">
34110 * @class Roo.tree.TreeLoader
34111 * @extends Roo.util.Observable
34112 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34113 * nodes from a specified URL. The response must be a javascript Array definition
34114 * who's elements are node definition objects. eg:
34119 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34120 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34127 * The old style respose with just an array is still supported, but not recommended.
34130 * A server request is sent, and child nodes are loaded only when a node is expanded.
34131 * The loading node's id is passed to the server under the parameter name "node" to
34132 * enable the server to produce the correct child nodes.
34134 * To pass extra parameters, an event handler may be attached to the "beforeload"
34135 * event, and the parameters specified in the TreeLoader's baseParams property:
34137 myTreeLoader.on("beforeload", function(treeLoader, node) {
34138 this.baseParams.category = node.attributes.category;
34141 * This would pass an HTTP parameter called "category" to the server containing
34142 * the value of the Node's "category" attribute.
34144 * Creates a new Treeloader.
34145 * @param {Object} config A config object containing config properties.
34147 Roo.tree.TreeLoader = function(config){
34148 this.baseParams = {};
34149 this.requestMethod = "POST";
34150 Roo.apply(this, config);
34155 * @event beforeload
34156 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34157 * @param {Object} This TreeLoader object.
34158 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34159 * @param {Object} callback The callback function specified in the {@link #load} call.
34164 * Fires when the node has been successfuly loaded.
34165 * @param {Object} This TreeLoader object.
34166 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34167 * @param {Object} response The response object containing the data from the server.
34171 * @event loadexception
34172 * Fires if the network request failed.
34173 * @param {Object} This TreeLoader object.
34174 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34175 * @param {Object} response The response object containing the data from the server.
34177 loadexception : true,
34180 * Fires before a node is created, enabling you to return custom Node types
34181 * @param {Object} This TreeLoader object.
34182 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34187 Roo.tree.TreeLoader.superclass.constructor.call(this);
34190 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34192 * @cfg {String} dataUrl The URL from which to request a Json string which
34193 * specifies an array of node definition object representing the child nodes
34197 * @cfg {String} requestMethod either GET or POST
34198 * defaults to POST (due to BC)
34202 * @cfg {Object} baseParams (optional) An object containing properties which
34203 * specify HTTP parameters to be passed to each request for child nodes.
34206 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34207 * created by this loader. If the attributes sent by the server have an attribute in this object,
34208 * they take priority.
34211 * @cfg {Object} uiProviders (optional) An object containing properties which
34213 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34214 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34215 * <i>uiProvider</i> attribute of a returned child node is a string rather
34216 * than a reference to a TreeNodeUI implementation, this that string value
34217 * is used as a property name in the uiProviders object. You can define the provider named
34218 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34223 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34224 * child nodes before loading.
34226 clearOnLoad : true,
34229 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34230 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34231 * Grid query { data : [ .....] }
34236 * @cfg {String} queryParam (optional)
34237 * Name of the query as it will be passed on the querystring (defaults to 'node')
34238 * eg. the request will be ?node=[id]
34245 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34246 * This is called automatically when a node is expanded, but may be used to reload
34247 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34248 * @param {Roo.tree.TreeNode} node
34249 * @param {Function} callback
34251 load : function(node, callback){
34252 if(this.clearOnLoad){
34253 while(node.firstChild){
34254 node.removeChild(node.firstChild);
34257 if(node.attributes.children){ // preloaded json children
34258 var cs = node.attributes.children;
34259 for(var i = 0, len = cs.length; i < len; i++){
34260 node.appendChild(this.createNode(cs[i]));
34262 if(typeof callback == "function"){
34265 }else if(this.dataUrl){
34266 this.requestData(node, callback);
34270 getParams: function(node){
34271 var buf = [], bp = this.baseParams;
34272 for(var key in bp){
34273 if(typeof bp[key] != "function"){
34274 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34277 var n = this.queryParam === false ? 'node' : this.queryParam;
34278 buf.push(n + "=", encodeURIComponent(node.id));
34279 return buf.join("");
34282 requestData : function(node, callback){
34283 if(this.fireEvent("beforeload", this, node, callback) !== false){
34284 this.transId = Roo.Ajax.request({
34285 method:this.requestMethod,
34286 url: this.dataUrl||this.url,
34287 success: this.handleResponse,
34288 failure: this.handleFailure,
34290 argument: {callback: callback, node: node},
34291 params: this.getParams(node)
34294 // if the load is cancelled, make sure we notify
34295 // the node that we are done
34296 if(typeof callback == "function"){
34302 isLoading : function(){
34303 return this.transId ? true : false;
34306 abort : function(){
34307 if(this.isLoading()){
34308 Roo.Ajax.abort(this.transId);
34313 createNode : function(attr)
34315 // apply baseAttrs, nice idea Corey!
34316 if(this.baseAttrs){
34317 Roo.applyIf(attr, this.baseAttrs);
34319 if(this.applyLoader !== false){
34320 attr.loader = this;
34322 // uiProvider = depreciated..
34324 if(typeof(attr.uiProvider) == 'string'){
34325 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34326 /** eval:var:attr */ eval(attr.uiProvider);
34328 if(typeof(this.uiProviders['default']) != 'undefined') {
34329 attr.uiProvider = this.uiProviders['default'];
34332 this.fireEvent('create', this, attr);
34334 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34336 new Roo.tree.TreeNode(attr) :
34337 new Roo.tree.AsyncTreeNode(attr));
34340 processResponse : function(response, node, callback)
34342 var json = response.responseText;
34345 var o = Roo.decode(json);
34347 if (this.root === false && typeof(o.success) != undefined) {
34348 this.root = 'data'; // the default behaviour for list like data..
34351 if (this.root !== false && !o.success) {
34352 // it's a failure condition.
34353 var a = response.argument;
34354 this.fireEvent("loadexception", this, a.node, response);
34355 Roo.log("Load failed - should have a handler really");
34361 if (this.root !== false) {
34365 for(var i = 0, len = o.length; i < len; i++){
34366 var n = this.createNode(o[i]);
34368 node.appendChild(n);
34371 if(typeof callback == "function"){
34372 callback(this, node);
34375 this.handleFailure(response);
34379 handleResponse : function(response){
34380 this.transId = false;
34381 var a = response.argument;
34382 this.processResponse(response, a.node, a.callback);
34383 this.fireEvent("load", this, a.node, response);
34386 handleFailure : function(response)
34388 // should handle failure better..
34389 this.transId = false;
34390 var a = response.argument;
34391 this.fireEvent("loadexception", this, a.node, response);
34392 if(typeof a.callback == "function"){
34393 a.callback(this, a.node);
34398 * Ext JS Library 1.1.1
34399 * Copyright(c) 2006-2007, Ext JS, LLC.
34401 * Originally Released Under LGPL - original licence link has changed is not relivant.
34404 * <script type="text/javascript">
34408 * @class Roo.tree.TreeFilter
34409 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34410 * @param {TreePanel} tree
34411 * @param {Object} config (optional)
34413 Roo.tree.TreeFilter = function(tree, config){
34415 this.filtered = {};
34416 Roo.apply(this, config);
34419 Roo.tree.TreeFilter.prototype = {
34426 * Filter the data by a specific attribute.
34427 * @param {String/RegExp} value Either string that the attribute value
34428 * should start with or a RegExp to test against the attribute
34429 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34430 * @param {TreeNode} startNode (optional) The node to start the filter at.
34432 filter : function(value, attr, startNode){
34433 attr = attr || "text";
34435 if(typeof value == "string"){
34436 var vlen = value.length;
34437 // auto clear empty filter
34438 if(vlen == 0 && this.clearBlank){
34442 value = value.toLowerCase();
34444 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34446 }else if(value.exec){ // regex?
34448 return value.test(n.attributes[attr]);
34451 throw 'Illegal filter type, must be string or regex';
34453 this.filterBy(f, null, startNode);
34457 * Filter by a function. The passed function will be called with each
34458 * node in the tree (or from the startNode). If the function returns true, the node is kept
34459 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34460 * @param {Function} fn The filter function
34461 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34463 filterBy : function(fn, scope, startNode){
34464 startNode = startNode || this.tree.root;
34465 if(this.autoClear){
34468 var af = this.filtered, rv = this.reverse;
34469 var f = function(n){
34470 if(n == startNode){
34476 var m = fn.call(scope || n, n);
34484 startNode.cascade(f);
34487 if(typeof id != "function"){
34489 if(n && n.parentNode){
34490 n.parentNode.removeChild(n);
34498 * Clears the current filter. Note: with the "remove" option
34499 * set a filter cannot be cleared.
34501 clear : function(){
34503 var af = this.filtered;
34505 if(typeof id != "function"){
34512 this.filtered = {};
34517 * Ext JS Library 1.1.1
34518 * Copyright(c) 2006-2007, Ext JS, LLC.
34520 * Originally Released Under LGPL - original licence link has changed is not relivant.
34523 * <script type="text/javascript">
34528 * @class Roo.tree.TreeSorter
34529 * Provides sorting of nodes in a TreePanel
34531 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34532 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34533 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34534 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34535 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34536 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34538 * @param {TreePanel} tree
34539 * @param {Object} config
34541 Roo.tree.TreeSorter = function(tree, config){
34542 Roo.apply(this, config);
34543 tree.on("beforechildrenrendered", this.doSort, this);
34544 tree.on("append", this.updateSort, this);
34545 tree.on("insert", this.updateSort, this);
34547 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34548 var p = this.property || "text";
34549 var sortType = this.sortType;
34550 var fs = this.folderSort;
34551 var cs = this.caseSensitive === true;
34552 var leafAttr = this.leafAttr || 'leaf';
34554 this.sortFn = function(n1, n2){
34556 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34559 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34563 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34564 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34566 return dsc ? +1 : -1;
34568 return dsc ? -1 : +1;
34575 Roo.tree.TreeSorter.prototype = {
34576 doSort : function(node){
34577 node.sort(this.sortFn);
34580 compareNodes : function(n1, n2){
34581 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34584 updateSort : function(tree, node){
34585 if(node.childrenRendered){
34586 this.doSort.defer(1, this, [node]);
34591 * Ext JS Library 1.1.1
34592 * Copyright(c) 2006-2007, Ext JS, LLC.
34594 * Originally Released Under LGPL - original licence link has changed is not relivant.
34597 * <script type="text/javascript">
34600 if(Roo.dd.DropZone){
34602 Roo.tree.TreeDropZone = function(tree, config){
34603 this.allowParentInsert = false;
34604 this.allowContainerDrop = false;
34605 this.appendOnly = false;
34606 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34608 this.lastInsertClass = "x-tree-no-status";
34609 this.dragOverData = {};
34612 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34613 ddGroup : "TreeDD",
34616 expandDelay : 1000,
34618 expandNode : function(node){
34619 if(node.hasChildNodes() && !node.isExpanded()){
34620 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34624 queueExpand : function(node){
34625 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34628 cancelExpand : function(){
34629 if(this.expandProcId){
34630 clearTimeout(this.expandProcId);
34631 this.expandProcId = false;
34635 isValidDropPoint : function(n, pt, dd, e, data){
34636 if(!n || !data){ return false; }
34637 var targetNode = n.node;
34638 var dropNode = data.node;
34639 // default drop rules
34640 if(!(targetNode && targetNode.isTarget && pt)){
34643 if(pt == "append" && targetNode.allowChildren === false){
34646 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34649 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34652 // reuse the object
34653 var overEvent = this.dragOverData;
34654 overEvent.tree = this.tree;
34655 overEvent.target = targetNode;
34656 overEvent.data = data;
34657 overEvent.point = pt;
34658 overEvent.source = dd;
34659 overEvent.rawEvent = e;
34660 overEvent.dropNode = dropNode;
34661 overEvent.cancel = false;
34662 var result = this.tree.fireEvent("nodedragover", overEvent);
34663 return overEvent.cancel === false && result !== false;
34666 getDropPoint : function(e, n, dd)
34670 return tn.allowChildren !== false ? "append" : false; // always append for root
34672 var dragEl = n.ddel;
34673 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34674 var y = Roo.lib.Event.getPageY(e);
34675 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34677 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34678 var noAppend = tn.allowChildren === false;
34679 if(this.appendOnly || tn.parentNode.allowChildren === false){
34680 return noAppend ? false : "append";
34682 var noBelow = false;
34683 if(!this.allowParentInsert){
34684 noBelow = tn.hasChildNodes() && tn.isExpanded();
34686 var q = (b - t) / (noAppend ? 2 : 3);
34687 if(y >= t && y < (t + q)){
34689 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34696 onNodeEnter : function(n, dd, e, data)
34698 this.cancelExpand();
34701 onNodeOver : function(n, dd, e, data)
34704 var pt = this.getDropPoint(e, n, dd);
34707 // auto node expand check
34708 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34709 this.queueExpand(node);
34710 }else if(pt != "append"){
34711 this.cancelExpand();
34714 // set the insert point style on the target node
34715 var returnCls = this.dropNotAllowed;
34716 if(this.isValidDropPoint(n, pt, dd, e, data)){
34721 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34722 cls = "x-tree-drag-insert-above";
34723 }else if(pt == "below"){
34724 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34725 cls = "x-tree-drag-insert-below";
34727 returnCls = "x-tree-drop-ok-append";
34728 cls = "x-tree-drag-append";
34730 if(this.lastInsertClass != cls){
34731 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34732 this.lastInsertClass = cls;
34739 onNodeOut : function(n, dd, e, data){
34741 this.cancelExpand();
34742 this.removeDropIndicators(n);
34745 onNodeDrop : function(n, dd, e, data){
34746 var point = this.getDropPoint(e, n, dd);
34747 var targetNode = n.node;
34748 targetNode.ui.startDrop();
34749 if(!this.isValidDropPoint(n, point, dd, e, data)){
34750 targetNode.ui.endDrop();
34753 // first try to find the drop node
34754 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34757 target: targetNode,
34762 dropNode: dropNode,
34765 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34766 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34767 targetNode.ui.endDrop();
34770 // allow target changing
34771 targetNode = dropEvent.target;
34772 if(point == "append" && !targetNode.isExpanded()){
34773 targetNode.expand(false, null, function(){
34774 this.completeDrop(dropEvent);
34775 }.createDelegate(this));
34777 this.completeDrop(dropEvent);
34782 completeDrop : function(de){
34783 var ns = de.dropNode, p = de.point, t = de.target;
34784 if(!(ns instanceof Array)){
34788 for(var i = 0, len = ns.length; i < len; i++){
34791 t.parentNode.insertBefore(n, t);
34792 }else if(p == "below"){
34793 t.parentNode.insertBefore(n, t.nextSibling);
34799 if(this.tree.hlDrop){
34803 this.tree.fireEvent("nodedrop", de);
34806 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34807 if(this.tree.hlDrop){
34808 dropNode.ui.focus();
34809 dropNode.ui.highlight();
34811 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34814 getTree : function(){
34818 removeDropIndicators : function(n){
34821 Roo.fly(el).removeClass([
34822 "x-tree-drag-insert-above",
34823 "x-tree-drag-insert-below",
34824 "x-tree-drag-append"]);
34825 this.lastInsertClass = "_noclass";
34829 beforeDragDrop : function(target, e, id){
34830 this.cancelExpand();
34834 afterRepair : function(data){
34835 if(data && Roo.enableFx){
34836 data.node.ui.highlight();
34846 * Ext JS Library 1.1.1
34847 * Copyright(c) 2006-2007, Ext JS, LLC.
34849 * Originally Released Under LGPL - original licence link has changed is not relivant.
34852 * <script type="text/javascript">
34856 if(Roo.dd.DragZone){
34857 Roo.tree.TreeDragZone = function(tree, config){
34858 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34862 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34863 ddGroup : "TreeDD",
34865 onBeforeDrag : function(data, e){
34867 return n && n.draggable && !n.disabled;
34871 onInitDrag : function(e){
34872 var data = this.dragData;
34873 this.tree.getSelectionModel().select(data.node);
34874 this.proxy.update("");
34875 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34876 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34879 getRepairXY : function(e, data){
34880 return data.node.ui.getDDRepairXY();
34883 onEndDrag : function(data, e){
34884 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34889 onValidDrop : function(dd, e, id){
34890 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34894 beforeInvalidDrop : function(e, id){
34895 // this scrolls the original position back into view
34896 var sm = this.tree.getSelectionModel();
34897 sm.clearSelections();
34898 sm.select(this.dragData.node);
34903 * Ext JS Library 1.1.1
34904 * Copyright(c) 2006-2007, Ext JS, LLC.
34906 * Originally Released Under LGPL - original licence link has changed is not relivant.
34909 * <script type="text/javascript">
34912 * @class Roo.tree.TreeEditor
34913 * @extends Roo.Editor
34914 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34915 * as the editor field.
34917 * @param {Object} config (used to be the tree panel.)
34918 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34920 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34921 * @cfg {Roo.form.TextField|Object} field The field configuration
34925 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34928 if (oldconfig) { // old style..
34929 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34932 tree = config.tree;
34933 config.field = config.field || {};
34934 config.field.xtype = 'TextField';
34935 field = Roo.factory(config.field, Roo.form);
34937 config = config || {};
34942 * @event beforenodeedit
34943 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34944 * false from the handler of this event.
34945 * @param {Editor} this
34946 * @param {Roo.tree.Node} node
34948 "beforenodeedit" : true
34952 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34956 tree.on('beforeclick', this.beforeNodeClick, this);
34957 tree.getTreeEl().on('mousedown', this.hide, this);
34958 this.on('complete', this.updateNode, this);
34959 this.on('beforestartedit', this.fitToTree, this);
34960 this.on('startedit', this.bindScroll, this, {delay:10});
34961 this.on('specialkey', this.onSpecialKey, this);
34964 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34966 * @cfg {String} alignment
34967 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34973 * @cfg {Boolean} hideEl
34974 * True to hide the bound element while the editor is displayed (defaults to false)
34978 * @cfg {String} cls
34979 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34981 cls: "x-small-editor x-tree-editor",
34983 * @cfg {Boolean} shim
34984 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34990 * @cfg {Number} maxWidth
34991 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34992 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34993 * scroll and client offsets into account prior to each edit.
35000 fitToTree : function(ed, el){
35001 var td = this.tree.getTreeEl().dom, nd = el.dom;
35002 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35003 td.scrollLeft = nd.offsetLeft;
35007 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35008 this.setSize(w, '');
35010 return this.fireEvent('beforenodeedit', this, this.editNode);
35015 triggerEdit : function(node){
35016 this.completeEdit();
35017 this.editNode = node;
35018 this.startEdit(node.ui.textNode, node.text);
35022 bindScroll : function(){
35023 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35027 beforeNodeClick : function(node, e){
35028 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35029 this.lastClick = new Date();
35030 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35032 this.triggerEdit(node);
35039 updateNode : function(ed, value){
35040 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35041 this.editNode.setText(value);
35045 onHide : function(){
35046 Roo.tree.TreeEditor.superclass.onHide.call(this);
35048 this.editNode.ui.focus();
35053 onSpecialKey : function(field, e){
35054 var k = e.getKey();
35058 }else if(k == e.ENTER && !e.hasModifier()){
35060 this.completeEdit();
35063 });//<Script type="text/javascript">
35066 * Ext JS Library 1.1.1
35067 * Copyright(c) 2006-2007, Ext JS, LLC.
35069 * Originally Released Under LGPL - original licence link has changed is not relivant.
35072 * <script type="text/javascript">
35076 * Not documented??? - probably should be...
35079 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35080 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35082 renderElements : function(n, a, targetNode, bulkRender){
35083 //consel.log("renderElements?");
35084 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35086 var t = n.getOwnerTree();
35087 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35089 var cols = t.columns;
35090 var bw = t.borderWidth;
35092 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35093 var cb = typeof a.checked == "boolean";
35094 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35095 var colcls = 'x-t-' + tid + '-c0';
35097 '<li class="x-tree-node">',
35100 '<div class="x-tree-node-el ', a.cls,'">',
35102 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35105 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35106 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35107 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35108 (a.icon ? ' x-tree-node-inline-icon' : ''),
35109 (a.iconCls ? ' '+a.iconCls : ''),
35110 '" unselectable="on" />',
35111 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35112 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35114 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35115 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35116 '<span unselectable="on" qtip="' + tx + '">',
35120 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35121 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35123 for(var i = 1, len = cols.length; i < len; i++){
35125 colcls = 'x-t-' + tid + '-c' +i;
35126 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35127 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35128 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35134 '<div class="x-clear"></div></div>',
35135 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35138 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35139 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35140 n.nextSibling.ui.getEl(), buf.join(""));
35142 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35144 var el = this.wrap.firstChild;
35146 this.elNode = el.firstChild;
35147 this.ranchor = el.childNodes[1];
35148 this.ctNode = this.wrap.childNodes[1];
35149 var cs = el.firstChild.childNodes;
35150 this.indentNode = cs[0];
35151 this.ecNode = cs[1];
35152 this.iconNode = cs[2];
35155 this.checkbox = cs[3];
35158 this.anchor = cs[index];
35160 this.textNode = cs[index].firstChild;
35162 //el.on("click", this.onClick, this);
35163 //el.on("dblclick", this.onDblClick, this);
35166 // console.log(this);
35168 initEvents : function(){
35169 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35172 var a = this.ranchor;
35174 var el = Roo.get(a);
35176 if(Roo.isOpera){ // opera render bug ignores the CSS
35177 el.setStyle("text-decoration", "none");
35180 el.on("click", this.onClick, this);
35181 el.on("dblclick", this.onDblClick, this);
35182 el.on("contextmenu", this.onContextMenu, this);
35186 /*onSelectedChange : function(state){
35189 this.addClass("x-tree-selected");
35192 this.removeClass("x-tree-selected");
35195 addClass : function(cls){
35197 Roo.fly(this.elRow).addClass(cls);
35203 removeClass : function(cls){
35205 Roo.fly(this.elRow).removeClass(cls);
35211 });//<Script type="text/javascript">
35215 * Ext JS Library 1.1.1
35216 * Copyright(c) 2006-2007, Ext JS, LLC.
35218 * Originally Released Under LGPL - original licence link has changed is not relivant.
35221 * <script type="text/javascript">
35226 * @class Roo.tree.ColumnTree
35227 * @extends Roo.data.TreePanel
35228 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35229 * @cfg {int} borderWidth compined right/left border allowance
35231 * @param {String/HTMLElement/Element} el The container element
35232 * @param {Object} config
35234 Roo.tree.ColumnTree = function(el, config)
35236 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35240 * Fire this event on a container when it resizes
35241 * @param {int} w Width
35242 * @param {int} h Height
35246 this.on('resize', this.onResize, this);
35249 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35253 borderWidth: Roo.isBorderBox ? 0 : 2,
35256 render : function(){
35257 // add the header.....
35259 Roo.tree.ColumnTree.superclass.render.apply(this);
35261 this.el.addClass('x-column-tree');
35263 this.headers = this.el.createChild(
35264 {cls:'x-tree-headers'},this.innerCt.dom);
35266 var cols = this.columns, c;
35267 var totalWidth = 0;
35269 var len = cols.length;
35270 for(var i = 0; i < len; i++){
35272 totalWidth += c.width;
35273 this.headEls.push(this.headers.createChild({
35274 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35276 cls:'x-tree-hd-text',
35279 style:'width:'+(c.width-this.borderWidth)+'px;'
35282 this.headers.createChild({cls:'x-clear'});
35283 // prevent floats from wrapping when clipped
35284 this.headers.setWidth(totalWidth);
35285 //this.innerCt.setWidth(totalWidth);
35286 this.innerCt.setStyle({ overflow: 'auto' });
35287 this.onResize(this.width, this.height);
35291 onResize : function(w,h)
35296 this.innerCt.setWidth(this.width);
35297 this.innerCt.setHeight(this.height-20);
35300 var cols = this.columns, c;
35301 var totalWidth = 0;
35303 var len = cols.length;
35304 for(var i = 0; i < len; i++){
35306 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35307 // it's the expander..
35308 expEl = this.headEls[i];
35311 totalWidth += c.width;
35315 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35317 this.headers.setWidth(w-20);
35326 * Ext JS Library 1.1.1
35327 * Copyright(c) 2006-2007, Ext JS, LLC.
35329 * Originally Released Under LGPL - original licence link has changed is not relivant.
35332 * <script type="text/javascript">
35336 * @class Roo.menu.Menu
35337 * @extends Roo.util.Observable
35338 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35339 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35341 * Creates a new Menu
35342 * @param {Object} config Configuration options
35344 Roo.menu.Menu = function(config){
35345 Roo.apply(this, config);
35346 this.id = this.id || Roo.id();
35349 * @event beforeshow
35350 * Fires before this menu is displayed
35351 * @param {Roo.menu.Menu} this
35355 * @event beforehide
35356 * Fires before this menu is hidden
35357 * @param {Roo.menu.Menu} this
35362 * Fires after this menu is displayed
35363 * @param {Roo.menu.Menu} this
35368 * Fires after this menu is hidden
35369 * @param {Roo.menu.Menu} this
35374 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35375 * @param {Roo.menu.Menu} this
35376 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35377 * @param {Roo.EventObject} e
35382 * Fires when the mouse is hovering over this menu
35383 * @param {Roo.menu.Menu} this
35384 * @param {Roo.EventObject} e
35385 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35390 * Fires when the mouse exits this menu
35391 * @param {Roo.menu.Menu} this
35392 * @param {Roo.EventObject} e
35393 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35398 * Fires when a menu item contained in this menu is clicked
35399 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35400 * @param {Roo.EventObject} e
35404 if (this.registerMenu) {
35405 Roo.menu.MenuMgr.register(this);
35408 var mis = this.items;
35409 this.items = new Roo.util.MixedCollection();
35411 this.add.apply(this, mis);
35415 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35417 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35421 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35422 * for bottom-right shadow (defaults to "sides")
35426 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35427 * this menu (defaults to "tl-tr?")
35429 subMenuAlign : "tl-tr?",
35431 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35432 * relative to its element of origin (defaults to "tl-bl?")
35434 defaultAlign : "tl-bl?",
35436 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35438 allowOtherMenus : false,
35440 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35442 registerMenu : true,
35447 render : function(){
35451 var el = this.el = new Roo.Layer({
35453 shadow:this.shadow,
35455 parentEl: this.parentEl || document.body,
35459 this.keyNav = new Roo.menu.MenuNav(this);
35462 el.addClass("x-menu-plain");
35465 el.addClass(this.cls);
35467 // generic focus element
35468 this.focusEl = el.createChild({
35469 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35471 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35472 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35474 ul.on("mouseover", this.onMouseOver, this);
35475 ul.on("mouseout", this.onMouseOut, this);
35476 this.items.each(function(item){
35481 var li = document.createElement("li");
35482 li.className = "x-menu-list-item";
35483 ul.dom.appendChild(li);
35484 item.render(li, this);
35491 autoWidth : function(){
35492 var el = this.el, ul = this.ul;
35496 var w = this.width;
35499 }else if(Roo.isIE){
35500 el.setWidth(this.minWidth);
35501 var t = el.dom.offsetWidth; // force recalc
35502 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35507 delayAutoWidth : function(){
35510 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35512 this.awTask.delay(20);
35517 findTargetItem : function(e){
35518 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35519 if(t && t.menuItemId){
35520 return this.items.get(t.menuItemId);
35525 onClick : function(e){
35526 Roo.log("menu.onClick");
35527 var t = this.findTargetItem(e);
35532 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35533 if(t == this.activeItem && t.shouldDeactivate(e)){
35534 this.activeItem.deactivate();
35535 delete this.activeItem;
35539 this.setActiveItem(t, true);
35547 this.fireEvent("click", this, t, e);
35551 setActiveItem : function(item, autoExpand){
35552 if(item != this.activeItem){
35553 if(this.activeItem){
35554 this.activeItem.deactivate();
35556 this.activeItem = item;
35557 item.activate(autoExpand);
35558 }else if(autoExpand){
35564 tryActivate : function(start, step){
35565 var items = this.items;
35566 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35567 var item = items.get(i);
35568 if(!item.disabled && item.canActivate){
35569 this.setActiveItem(item, false);
35577 onMouseOver : function(e){
35579 if(t = this.findTargetItem(e)){
35580 if(t.canActivate && !t.disabled){
35581 this.setActiveItem(t, true);
35584 this.fireEvent("mouseover", this, e, t);
35588 onMouseOut : function(e){
35590 if(t = this.findTargetItem(e)){
35591 if(t == this.activeItem && t.shouldDeactivate(e)){
35592 this.activeItem.deactivate();
35593 delete this.activeItem;
35596 this.fireEvent("mouseout", this, e, t);
35600 * Read-only. Returns true if the menu is currently displayed, else false.
35603 isVisible : function(){
35604 return this.el && !this.hidden;
35608 * Displays this menu relative to another element
35609 * @param {String/HTMLElement/Roo.Element} element The element to align to
35610 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35611 * the element (defaults to this.defaultAlign)
35612 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35614 show : function(el, pos, parentMenu){
35615 this.parentMenu = parentMenu;
35619 this.fireEvent("beforeshow", this);
35620 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35624 * Displays this menu at a specific xy position
35625 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35626 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35628 showAt : function(xy, parentMenu, /* private: */_e){
35629 this.parentMenu = parentMenu;
35634 this.fireEvent("beforeshow", this);
35635 xy = this.el.adjustForConstraints(xy);
35639 this.hidden = false;
35641 this.fireEvent("show", this);
35644 focus : function(){
35646 this.doFocus.defer(50, this);
35650 doFocus : function(){
35652 this.focusEl.focus();
35657 * Hides this menu and optionally all parent menus
35658 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35660 hide : function(deep){
35661 if(this.el && this.isVisible()){
35662 this.fireEvent("beforehide", this);
35663 if(this.activeItem){
35664 this.activeItem.deactivate();
35665 this.activeItem = null;
35668 this.hidden = true;
35669 this.fireEvent("hide", this);
35671 if(deep === true && this.parentMenu){
35672 this.parentMenu.hide(true);
35677 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35678 * Any of the following are valid:
35680 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35681 * <li>An HTMLElement object which will be converted to a menu item</li>
35682 * <li>A menu item config object that will be created as a new menu item</li>
35683 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35684 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35689 var menu = new Roo.menu.Menu();
35691 // Create a menu item to add by reference
35692 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35694 // Add a bunch of items at once using different methods.
35695 // Only the last item added will be returned.
35696 var item = menu.add(
35697 menuItem, // add existing item by ref
35698 'Dynamic Item', // new TextItem
35699 '-', // new separator
35700 { text: 'Config Item' } // new item by config
35703 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35704 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35707 var a = arguments, l = a.length, item;
35708 for(var i = 0; i < l; i++){
35710 if ((typeof(el) == "object") && el.xtype && el.xns) {
35711 el = Roo.factory(el, Roo.menu);
35714 if(el.render){ // some kind of Item
35715 item = this.addItem(el);
35716 }else if(typeof el == "string"){ // string
35717 if(el == "separator" || el == "-"){
35718 item = this.addSeparator();
35720 item = this.addText(el);
35722 }else if(el.tagName || el.el){ // element
35723 item = this.addElement(el);
35724 }else if(typeof el == "object"){ // must be menu item config?
35725 item = this.addMenuItem(el);
35732 * Returns this menu's underlying {@link Roo.Element} object
35733 * @return {Roo.Element} The element
35735 getEl : function(){
35743 * Adds a separator bar to the menu
35744 * @return {Roo.menu.Item} The menu item that was added
35746 addSeparator : function(){
35747 return this.addItem(new Roo.menu.Separator());
35751 * Adds an {@link Roo.Element} object to the menu
35752 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35753 * @return {Roo.menu.Item} The menu item that was added
35755 addElement : function(el){
35756 return this.addItem(new Roo.menu.BaseItem(el));
35760 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35761 * @param {Roo.menu.Item} item The menu item to add
35762 * @return {Roo.menu.Item} The menu item that was added
35764 addItem : function(item){
35765 this.items.add(item);
35767 var li = document.createElement("li");
35768 li.className = "x-menu-list-item";
35769 this.ul.dom.appendChild(li);
35770 item.render(li, this);
35771 this.delayAutoWidth();
35777 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35778 * @param {Object} config A MenuItem config object
35779 * @return {Roo.menu.Item} The menu item that was added
35781 addMenuItem : function(config){
35782 if(!(config instanceof Roo.menu.Item)){
35783 if(typeof config.checked == "boolean"){ // must be check menu item config?
35784 config = new Roo.menu.CheckItem(config);
35786 config = new Roo.menu.Item(config);
35789 return this.addItem(config);
35793 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35794 * @param {String} text The text to display in the menu item
35795 * @return {Roo.menu.Item} The menu item that was added
35797 addText : function(text){
35798 return this.addItem(new Roo.menu.TextItem({ text : text }));
35802 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35803 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35804 * @param {Roo.menu.Item} item The menu item to add
35805 * @return {Roo.menu.Item} The menu item that was added
35807 insert : function(index, item){
35808 this.items.insert(index, item);
35810 var li = document.createElement("li");
35811 li.className = "x-menu-list-item";
35812 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35813 item.render(li, this);
35814 this.delayAutoWidth();
35820 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35821 * @param {Roo.menu.Item} item The menu item to remove
35823 remove : function(item){
35824 this.items.removeKey(item.id);
35829 * Removes and destroys all items in the menu
35831 removeAll : function(){
35833 while(f = this.items.first()){
35839 // MenuNav is a private utility class used internally by the Menu
35840 Roo.menu.MenuNav = function(menu){
35841 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35842 this.scope = this.menu = menu;
35845 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35846 doRelay : function(e, h){
35847 var k = e.getKey();
35848 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35849 this.menu.tryActivate(0, 1);
35852 return h.call(this.scope || this, e, this.menu);
35855 up : function(e, m){
35856 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35857 m.tryActivate(m.items.length-1, -1);
35861 down : function(e, m){
35862 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35863 m.tryActivate(0, 1);
35867 right : function(e, m){
35869 m.activeItem.expandMenu(true);
35873 left : function(e, m){
35875 if(m.parentMenu && m.parentMenu.activeItem){
35876 m.parentMenu.activeItem.activate();
35880 enter : function(e, m){
35882 e.stopPropagation();
35883 m.activeItem.onClick(e);
35884 m.fireEvent("click", this, m.activeItem);
35890 * Ext JS Library 1.1.1
35891 * Copyright(c) 2006-2007, Ext JS, LLC.
35893 * Originally Released Under LGPL - original licence link has changed is not relivant.
35896 * <script type="text/javascript">
35900 * @class Roo.menu.MenuMgr
35901 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35904 Roo.menu.MenuMgr = function(){
35905 var menus, active, groups = {}, attached = false, lastShow = new Date();
35907 // private - called when first menu is created
35910 active = new Roo.util.MixedCollection();
35911 Roo.get(document).addKeyListener(27, function(){
35912 if(active.length > 0){
35919 function hideAll(){
35920 if(active && active.length > 0){
35921 var c = active.clone();
35922 c.each(function(m){
35929 function onHide(m){
35931 if(active.length < 1){
35932 Roo.get(document).un("mousedown", onMouseDown);
35938 function onShow(m){
35939 var last = active.last();
35940 lastShow = new Date();
35943 Roo.get(document).on("mousedown", onMouseDown);
35947 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35948 m.parentMenu.activeChild = m;
35949 }else if(last && last.isVisible()){
35950 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35955 function onBeforeHide(m){
35957 m.activeChild.hide();
35959 if(m.autoHideTimer){
35960 clearTimeout(m.autoHideTimer);
35961 delete m.autoHideTimer;
35966 function onBeforeShow(m){
35967 var pm = m.parentMenu;
35968 if(!pm && !m.allowOtherMenus){
35970 }else if(pm && pm.activeChild && active != m){
35971 pm.activeChild.hide();
35976 function onMouseDown(e){
35977 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35983 function onBeforeCheck(mi, state){
35985 var g = groups[mi.group];
35986 for(var i = 0, l = g.length; i < l; i++){
35988 g[i].setChecked(false);
35997 * Hides all menus that are currently visible
35999 hideAll : function(){
36004 register : function(menu){
36008 menus[menu.id] = menu;
36009 menu.on("beforehide", onBeforeHide);
36010 menu.on("hide", onHide);
36011 menu.on("beforeshow", onBeforeShow);
36012 menu.on("show", onShow);
36013 var g = menu.group;
36014 if(g && menu.events["checkchange"]){
36018 groups[g].push(menu);
36019 menu.on("checkchange", onCheck);
36024 * Returns a {@link Roo.menu.Menu} object
36025 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36026 * be used to generate and return a new Menu instance.
36028 get : function(menu){
36029 if(typeof menu == "string"){ // menu id
36030 return menus[menu];
36031 }else if(menu.events){ // menu instance
36033 }else if(typeof menu.length == 'number'){ // array of menu items?
36034 return new Roo.menu.Menu({items:menu});
36035 }else{ // otherwise, must be a config
36036 return new Roo.menu.Menu(menu);
36041 unregister : function(menu){
36042 delete menus[menu.id];
36043 menu.un("beforehide", onBeforeHide);
36044 menu.un("hide", onHide);
36045 menu.un("beforeshow", onBeforeShow);
36046 menu.un("show", onShow);
36047 var g = menu.group;
36048 if(g && menu.events["checkchange"]){
36049 groups[g].remove(menu);
36050 menu.un("checkchange", onCheck);
36055 registerCheckable : function(menuItem){
36056 var g = menuItem.group;
36061 groups[g].push(menuItem);
36062 menuItem.on("beforecheckchange", onBeforeCheck);
36067 unregisterCheckable : function(menuItem){
36068 var g = menuItem.group;
36070 groups[g].remove(menuItem);
36071 menuItem.un("beforecheckchange", onBeforeCheck);
36077 * Ext JS Library 1.1.1
36078 * Copyright(c) 2006-2007, Ext JS, LLC.
36080 * Originally Released Under LGPL - original licence link has changed is not relivant.
36083 * <script type="text/javascript">
36088 * @class Roo.menu.BaseItem
36089 * @extends Roo.Component
36090 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36091 * management and base configuration options shared by all menu components.
36093 * Creates a new BaseItem
36094 * @param {Object} config Configuration options
36096 Roo.menu.BaseItem = function(config){
36097 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36102 * Fires when this item is clicked
36103 * @param {Roo.menu.BaseItem} this
36104 * @param {Roo.EventObject} e
36109 * Fires when this item is activated
36110 * @param {Roo.menu.BaseItem} this
36114 * @event deactivate
36115 * Fires when this item is deactivated
36116 * @param {Roo.menu.BaseItem} this
36122 this.on("click", this.handler, this.scope, true);
36126 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36128 * @cfg {Function} handler
36129 * A function that will handle the click event of this menu item (defaults to undefined)
36132 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36134 canActivate : false,
36137 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36142 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36144 activeClass : "x-menu-item-active",
36146 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36148 hideOnClick : true,
36150 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36155 ctype: "Roo.menu.BaseItem",
36158 actionMode : "container",
36161 render : function(container, parentMenu){
36162 this.parentMenu = parentMenu;
36163 Roo.menu.BaseItem.superclass.render.call(this, container);
36164 this.container.menuItemId = this.id;
36168 onRender : function(container, position){
36169 this.el = Roo.get(this.el);
36170 container.dom.appendChild(this.el.dom);
36174 onClick : function(e){
36175 if(!this.disabled && this.fireEvent("click", this, e) !== false
36176 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36177 this.handleClick(e);
36184 activate : function(){
36188 var li = this.container;
36189 li.addClass(this.activeClass);
36190 this.region = li.getRegion().adjust(2, 2, -2, -2);
36191 this.fireEvent("activate", this);
36196 deactivate : function(){
36197 this.container.removeClass(this.activeClass);
36198 this.fireEvent("deactivate", this);
36202 shouldDeactivate : function(e){
36203 return !this.region || !this.region.contains(e.getPoint());
36207 handleClick : function(e){
36208 if(this.hideOnClick){
36209 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36214 expandMenu : function(autoActivate){
36219 hideMenu : function(){
36224 * Ext JS Library 1.1.1
36225 * Copyright(c) 2006-2007, Ext JS, LLC.
36227 * Originally Released Under LGPL - original licence link has changed is not relivant.
36230 * <script type="text/javascript">
36234 * @class Roo.menu.Adapter
36235 * @extends Roo.menu.BaseItem
36236 * 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.
36237 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36239 * Creates a new Adapter
36240 * @param {Object} config Configuration options
36242 Roo.menu.Adapter = function(component, config){
36243 Roo.menu.Adapter.superclass.constructor.call(this, config);
36244 this.component = component;
36246 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36248 canActivate : true,
36251 onRender : function(container, position){
36252 this.component.render(container);
36253 this.el = this.component.getEl();
36257 activate : function(){
36261 this.component.focus();
36262 this.fireEvent("activate", this);
36267 deactivate : function(){
36268 this.fireEvent("deactivate", this);
36272 disable : function(){
36273 this.component.disable();
36274 Roo.menu.Adapter.superclass.disable.call(this);
36278 enable : function(){
36279 this.component.enable();
36280 Roo.menu.Adapter.superclass.enable.call(this);
36284 * Ext JS Library 1.1.1
36285 * Copyright(c) 2006-2007, Ext JS, LLC.
36287 * Originally Released Under LGPL - original licence link has changed is not relivant.
36290 * <script type="text/javascript">
36294 * @class Roo.menu.TextItem
36295 * @extends Roo.menu.BaseItem
36296 * Adds a static text string to a menu, usually used as either a heading or group separator.
36297 * Note: old style constructor with text is still supported.
36300 * Creates a new TextItem
36301 * @param {Object} cfg Configuration
36303 Roo.menu.TextItem = function(cfg){
36304 if (typeof(cfg) == 'string') {
36307 Roo.apply(this,cfg);
36310 Roo.menu.TextItem.superclass.constructor.call(this);
36313 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36315 * @cfg {Boolean} text Text to show on item.
36320 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36322 hideOnClick : false,
36324 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36326 itemCls : "x-menu-text",
36329 onRender : function(){
36330 var s = document.createElement("span");
36331 s.className = this.itemCls;
36332 s.innerHTML = this.text;
36334 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36338 * Ext JS Library 1.1.1
36339 * Copyright(c) 2006-2007, Ext JS, LLC.
36341 * Originally Released Under LGPL - original licence link has changed is not relivant.
36344 * <script type="text/javascript">
36348 * @class Roo.menu.Separator
36349 * @extends Roo.menu.BaseItem
36350 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36351 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36353 * @param {Object} config Configuration options
36355 Roo.menu.Separator = function(config){
36356 Roo.menu.Separator.superclass.constructor.call(this, config);
36359 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36361 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36363 itemCls : "x-menu-sep",
36365 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36367 hideOnClick : false,
36370 onRender : function(li){
36371 var s = document.createElement("span");
36372 s.className = this.itemCls;
36373 s.innerHTML = " ";
36375 li.addClass("x-menu-sep-li");
36376 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36380 * Ext JS Library 1.1.1
36381 * Copyright(c) 2006-2007, Ext JS, LLC.
36383 * Originally Released Under LGPL - original licence link has changed is not relivant.
36386 * <script type="text/javascript">
36389 * @class Roo.menu.Item
36390 * @extends Roo.menu.BaseItem
36391 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36392 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36393 * activation and click handling.
36395 * Creates a new Item
36396 * @param {Object} config Configuration options
36398 Roo.menu.Item = function(config){
36399 Roo.menu.Item.superclass.constructor.call(this, config);
36401 this.menu = Roo.menu.MenuMgr.get(this.menu);
36404 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36407 * @cfg {String} text
36408 * The text to show on the menu item.
36412 * @cfg {String} HTML to render in menu
36413 * The text to show on the menu item (HTML version).
36417 * @cfg {String} icon
36418 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36422 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36424 itemCls : "x-menu-item",
36426 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36428 canActivate : true,
36430 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36433 // doc'd in BaseItem
36437 ctype: "Roo.menu.Item",
36440 onRender : function(container, position){
36441 var el = document.createElement("a");
36442 el.hideFocus = true;
36443 el.unselectable = "on";
36444 el.href = this.href || "#";
36445 if(this.hrefTarget){
36446 el.target = this.hrefTarget;
36448 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36450 var html = this.html.length ? this.html : String.format('{0}',this.text);
36452 el.innerHTML = String.format(
36453 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36454 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36456 Roo.menu.Item.superclass.onRender.call(this, container, position);
36460 * Sets the text to display in this menu item
36461 * @param {String} text The text to display
36462 * @param {Boolean} isHTML true to indicate text is pure html.
36464 setText : function(text, isHTML){
36472 var html = this.html.length ? this.html : String.format('{0}',this.text);
36474 this.el.update(String.format(
36475 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36476 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36477 this.parentMenu.autoWidth();
36482 handleClick : function(e){
36483 if(!this.href){ // if no link defined, stop the event automatically
36486 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36490 activate : function(autoExpand){
36491 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36501 shouldDeactivate : function(e){
36502 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36503 if(this.menu && this.menu.isVisible()){
36504 return !this.menu.getEl().getRegion().contains(e.getPoint());
36512 deactivate : function(){
36513 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36518 expandMenu : function(autoActivate){
36519 if(!this.disabled && this.menu){
36520 clearTimeout(this.hideTimer);
36521 delete this.hideTimer;
36522 if(!this.menu.isVisible() && !this.showTimer){
36523 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36524 }else if (this.menu.isVisible() && autoActivate){
36525 this.menu.tryActivate(0, 1);
36531 deferExpand : function(autoActivate){
36532 delete this.showTimer;
36533 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36535 this.menu.tryActivate(0, 1);
36540 hideMenu : function(){
36541 clearTimeout(this.showTimer);
36542 delete this.showTimer;
36543 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36544 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36549 deferHide : function(){
36550 delete this.hideTimer;
36555 * Ext JS Library 1.1.1
36556 * Copyright(c) 2006-2007, Ext JS, LLC.
36558 * Originally Released Under LGPL - original licence link has changed is not relivant.
36561 * <script type="text/javascript">
36565 * @class Roo.menu.CheckItem
36566 * @extends Roo.menu.Item
36567 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36569 * Creates a new CheckItem
36570 * @param {Object} config Configuration options
36572 Roo.menu.CheckItem = function(config){
36573 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36576 * @event beforecheckchange
36577 * Fires before the checked value is set, providing an opportunity to cancel if needed
36578 * @param {Roo.menu.CheckItem} this
36579 * @param {Boolean} checked The new checked value that will be set
36581 "beforecheckchange" : true,
36583 * @event checkchange
36584 * Fires after the checked value has been set
36585 * @param {Roo.menu.CheckItem} this
36586 * @param {Boolean} checked The checked value that was set
36588 "checkchange" : true
36590 if(this.checkHandler){
36591 this.on('checkchange', this.checkHandler, this.scope);
36594 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36596 * @cfg {String} group
36597 * All check items with the same group name will automatically be grouped into a single-select
36598 * radio button group (defaults to '')
36601 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36603 itemCls : "x-menu-item x-menu-check-item",
36605 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36607 groupClass : "x-menu-group-item",
36610 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36611 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36612 * initialized with checked = true will be rendered as checked.
36617 ctype: "Roo.menu.CheckItem",
36620 onRender : function(c){
36621 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36623 this.el.addClass(this.groupClass);
36625 Roo.menu.MenuMgr.registerCheckable(this);
36627 this.checked = false;
36628 this.setChecked(true, true);
36633 destroy : function(){
36635 Roo.menu.MenuMgr.unregisterCheckable(this);
36637 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36641 * Set the checked state of this item
36642 * @param {Boolean} checked The new checked value
36643 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36645 setChecked : function(state, suppressEvent){
36646 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36647 if(this.container){
36648 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36650 this.checked = state;
36651 if(suppressEvent !== true){
36652 this.fireEvent("checkchange", this, state);
36658 handleClick : function(e){
36659 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36660 this.setChecked(!this.checked);
36662 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36666 * Ext JS Library 1.1.1
36667 * Copyright(c) 2006-2007, Ext JS, LLC.
36669 * Originally Released Under LGPL - original licence link has changed is not relivant.
36672 * <script type="text/javascript">
36676 * @class Roo.menu.DateItem
36677 * @extends Roo.menu.Adapter
36678 * A menu item that wraps the {@link Roo.DatPicker} component.
36680 * Creates a new DateItem
36681 * @param {Object} config Configuration options
36683 Roo.menu.DateItem = function(config){
36684 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36685 /** The Roo.DatePicker object @type Roo.DatePicker */
36686 this.picker = this.component;
36687 this.addEvents({select: true});
36689 this.picker.on("render", function(picker){
36690 picker.getEl().swallowEvent("click");
36691 picker.container.addClass("x-menu-date-item");
36694 this.picker.on("select", this.onSelect, this);
36697 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36699 onSelect : function(picker, date){
36700 this.fireEvent("select", this, date, picker);
36701 Roo.menu.DateItem.superclass.handleClick.call(this);
36705 * Ext JS Library 1.1.1
36706 * Copyright(c) 2006-2007, Ext JS, LLC.
36708 * Originally Released Under LGPL - original licence link has changed is not relivant.
36711 * <script type="text/javascript">
36715 * @class Roo.menu.ColorItem
36716 * @extends Roo.menu.Adapter
36717 * A menu item that wraps the {@link Roo.ColorPalette} component.
36719 * Creates a new ColorItem
36720 * @param {Object} config Configuration options
36722 Roo.menu.ColorItem = function(config){
36723 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36724 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36725 this.palette = this.component;
36726 this.relayEvents(this.palette, ["select"]);
36727 if(this.selectHandler){
36728 this.on('select', this.selectHandler, this.scope);
36731 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36733 * Ext JS Library 1.1.1
36734 * Copyright(c) 2006-2007, Ext JS, LLC.
36736 * Originally Released Under LGPL - original licence link has changed is not relivant.
36739 * <script type="text/javascript">
36744 * @class Roo.menu.DateMenu
36745 * @extends Roo.menu.Menu
36746 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36748 * Creates a new DateMenu
36749 * @param {Object} config Configuration options
36751 Roo.menu.DateMenu = function(config){
36752 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36754 var di = new Roo.menu.DateItem(config);
36757 * The {@link Roo.DatePicker} instance for this DateMenu
36760 this.picker = di.picker;
36763 * @param {DatePicker} picker
36764 * @param {Date} date
36766 this.relayEvents(di, ["select"]);
36767 this.on('beforeshow', function(){
36769 this.picker.hideMonthPicker(false);
36773 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36777 * Ext JS Library 1.1.1
36778 * Copyright(c) 2006-2007, Ext JS, LLC.
36780 * Originally Released Under LGPL - original licence link has changed is not relivant.
36783 * <script type="text/javascript">
36788 * @class Roo.menu.ColorMenu
36789 * @extends Roo.menu.Menu
36790 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36792 * Creates a new ColorMenu
36793 * @param {Object} config Configuration options
36795 Roo.menu.ColorMenu = function(config){
36796 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36798 var ci = new Roo.menu.ColorItem(config);
36801 * The {@link Roo.ColorPalette} instance for this ColorMenu
36802 * @type ColorPalette
36804 this.palette = ci.palette;
36807 * @param {ColorPalette} palette
36808 * @param {String} color
36810 this.relayEvents(ci, ["select"]);
36812 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36814 * Ext JS Library 1.1.1
36815 * Copyright(c) 2006-2007, Ext JS, LLC.
36817 * Originally Released Under LGPL - original licence link has changed is not relivant.
36820 * <script type="text/javascript">
36824 * @class Roo.form.Field
36825 * @extends Roo.BoxComponent
36826 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36828 * Creates a new Field
36829 * @param {Object} config Configuration options
36831 Roo.form.Field = function(config){
36832 Roo.form.Field.superclass.constructor.call(this, config);
36835 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36837 * @cfg {String} fieldLabel Label to use when rendering a form.
36840 * @cfg {String} qtip Mouse over tip
36844 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36846 invalidClass : "x-form-invalid",
36848 * @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")
36850 invalidText : "The value in this field is invalid",
36852 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36854 focusClass : "x-form-focus",
36856 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36857 automatic validation (defaults to "keyup").
36859 validationEvent : "keyup",
36861 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36863 validateOnBlur : true,
36865 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36867 validationDelay : 250,
36869 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36870 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36872 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36874 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36876 fieldClass : "x-form-field",
36878 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36881 ----------- ----------------------------------------------------------------------
36882 qtip Display a quick tip when the user hovers over the field
36883 title Display a default browser title attribute popup
36884 under Add a block div beneath the field containing the error text
36885 side Add an error icon to the right of the field with a popup on hover
36886 [element id] Add the error text directly to the innerHTML of the specified element
36889 msgTarget : 'qtip',
36891 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36896 * @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.
36901 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36906 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36908 inputType : undefined,
36911 * @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).
36913 tabIndex : undefined,
36916 isFormField : true,
36921 * @property {Roo.Element} fieldEl
36922 * Element Containing the rendered Field (with label etc.)
36925 * @cfg {Mixed} value A value to initialize this field with.
36930 * @cfg {String} name The field's HTML name attribute.
36933 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36937 initComponent : function(){
36938 Roo.form.Field.superclass.initComponent.call(this);
36942 * Fires when this field receives input focus.
36943 * @param {Roo.form.Field} this
36948 * Fires when this field loses input focus.
36949 * @param {Roo.form.Field} this
36953 * @event specialkey
36954 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36955 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36956 * @param {Roo.form.Field} this
36957 * @param {Roo.EventObject} e The event object
36962 * Fires just before the field blurs if the field value has changed.
36963 * @param {Roo.form.Field} this
36964 * @param {Mixed} newValue The new value
36965 * @param {Mixed} oldValue The original value
36970 * Fires after the field has been marked as invalid.
36971 * @param {Roo.form.Field} this
36972 * @param {String} msg The validation message
36977 * Fires after the field has been validated with no errors.
36978 * @param {Roo.form.Field} this
36983 * Fires after the key up
36984 * @param {Roo.form.Field} this
36985 * @param {Roo.EventObject} e The event Object
36992 * Returns the name attribute of the field if available
36993 * @return {String} name The field name
36995 getName: function(){
36996 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37000 onRender : function(ct, position){
37001 Roo.form.Field.superclass.onRender.call(this, ct, position);
37003 var cfg = this.getAutoCreate();
37005 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37007 if (!cfg.name.length) {
37010 if(this.inputType){
37011 cfg.type = this.inputType;
37013 this.el = ct.createChild(cfg, position);
37015 var type = this.el.dom.type;
37017 if(type == 'password'){
37020 this.el.addClass('x-form-'+type);
37023 this.el.dom.readOnly = true;
37025 if(this.tabIndex !== undefined){
37026 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37029 this.el.addClass([this.fieldClass, this.cls]);
37034 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37035 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37036 * @return {Roo.form.Field} this
37038 applyTo : function(target){
37039 this.allowDomMove = false;
37040 this.el = Roo.get(target);
37041 this.render(this.el.dom.parentNode);
37046 initValue : function(){
37047 if(this.value !== undefined){
37048 this.setValue(this.value);
37049 }else if(this.el.dom.value.length > 0){
37050 this.setValue(this.el.dom.value);
37055 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37057 isDirty : function() {
37058 if(this.disabled) {
37061 return String(this.getValue()) !== String(this.originalValue);
37065 afterRender : function(){
37066 Roo.form.Field.superclass.afterRender.call(this);
37071 fireKey : function(e){
37072 //Roo.log('field ' + e.getKey());
37073 if(e.isNavKeyPress()){
37074 this.fireEvent("specialkey", this, e);
37079 * Resets the current field value to the originally loaded value and clears any validation messages
37081 reset : function(){
37082 this.setValue(this.resetValue);
37083 this.clearInvalid();
37087 initEvents : function(){
37088 // safari killled keypress - so keydown is now used..
37089 this.el.on("keydown" , this.fireKey, this);
37090 this.el.on("focus", this.onFocus, this);
37091 this.el.on("blur", this.onBlur, this);
37092 this.el.relayEvent('keyup', this);
37094 // reference to original value for reset
37095 this.originalValue = this.getValue();
37096 this.resetValue = this.getValue();
37100 onFocus : function(){
37101 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37102 this.el.addClass(this.focusClass);
37104 if(!this.hasFocus){
37105 this.hasFocus = true;
37106 this.startValue = this.getValue();
37107 this.fireEvent("focus", this);
37111 beforeBlur : Roo.emptyFn,
37114 onBlur : function(){
37116 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37117 this.el.removeClass(this.focusClass);
37119 this.hasFocus = false;
37120 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37123 var v = this.getValue();
37124 if(String(v) !== String(this.startValue)){
37125 this.fireEvent('change', this, v, this.startValue);
37127 this.fireEvent("blur", this);
37131 * Returns whether or not the field value is currently valid
37132 * @param {Boolean} preventMark True to disable marking the field invalid
37133 * @return {Boolean} True if the value is valid, else false
37135 isValid : function(preventMark){
37139 var restore = this.preventMark;
37140 this.preventMark = preventMark === true;
37141 var v = this.validateValue(this.processValue(this.getRawValue()));
37142 this.preventMark = restore;
37147 * Validates the field value
37148 * @return {Boolean} True if the value is valid, else false
37150 validate : function(){
37151 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37152 this.clearInvalid();
37158 processValue : function(value){
37163 // Subclasses should provide the validation implementation by overriding this
37164 validateValue : function(value){
37169 * Mark this field as invalid
37170 * @param {String} msg The validation message
37172 markInvalid : function(msg){
37173 if(!this.rendered || this.preventMark){ // not rendered
37177 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37179 obj.el.addClass(this.invalidClass);
37180 msg = msg || this.invalidText;
37181 switch(this.msgTarget){
37183 obj.el.dom.qtip = msg;
37184 obj.el.dom.qclass = 'x-form-invalid-tip';
37185 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37186 Roo.QuickTips.enable();
37190 this.el.dom.title = msg;
37194 var elp = this.el.findParent('.x-form-element', 5, true);
37195 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37196 this.errorEl.setWidth(elp.getWidth(true)-20);
37198 this.errorEl.update(msg);
37199 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37202 if(!this.errorIcon){
37203 var elp = this.el.findParent('.x-form-element', 5, true);
37204 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37206 this.alignErrorIcon();
37207 this.errorIcon.dom.qtip = msg;
37208 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37209 this.errorIcon.show();
37210 this.on('resize', this.alignErrorIcon, this);
37213 var t = Roo.getDom(this.msgTarget);
37215 t.style.display = this.msgDisplay;
37218 this.fireEvent('invalid', this, msg);
37222 alignErrorIcon : function(){
37223 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37227 * Clear any invalid styles/messages for this field
37229 clearInvalid : function(){
37230 if(!this.rendered || this.preventMark){ // not rendered
37233 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37235 obj.el.removeClass(this.invalidClass);
37236 switch(this.msgTarget){
37238 obj.el.dom.qtip = '';
37241 this.el.dom.title = '';
37245 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37249 if(this.errorIcon){
37250 this.errorIcon.dom.qtip = '';
37251 this.errorIcon.hide();
37252 this.un('resize', this.alignErrorIcon, this);
37256 var t = Roo.getDom(this.msgTarget);
37258 t.style.display = 'none';
37261 this.fireEvent('valid', this);
37265 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37266 * @return {Mixed} value The field value
37268 getRawValue : function(){
37269 var v = this.el.getValue();
37275 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37276 * @return {Mixed} value The field value
37278 getValue : function(){
37279 var v = this.el.getValue();
37285 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37286 * @param {Mixed} value The value to set
37288 setRawValue : function(v){
37289 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37293 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37294 * @param {Mixed} value The value to set
37296 setValue : function(v){
37299 this.el.dom.value = (v === null || v === undefined ? '' : v);
37304 adjustSize : function(w, h){
37305 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37306 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37310 adjustWidth : function(tag, w){
37311 tag = tag.toLowerCase();
37312 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37313 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37314 if(tag == 'input'){
37317 if(tag == 'textarea'){
37320 }else if(Roo.isOpera){
37321 if(tag == 'input'){
37324 if(tag == 'textarea'){
37334 // anything other than normal should be considered experimental
37335 Roo.form.Field.msgFx = {
37337 show: function(msgEl, f){
37338 msgEl.setDisplayed('block');
37341 hide : function(msgEl, f){
37342 msgEl.setDisplayed(false).update('');
37347 show: function(msgEl, f){
37348 msgEl.slideIn('t', {stopFx:true});
37351 hide : function(msgEl, f){
37352 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37357 show: function(msgEl, f){
37358 msgEl.fixDisplay();
37359 msgEl.alignTo(f.el, 'tl-tr');
37360 msgEl.slideIn('l', {stopFx:true});
37363 hide : function(msgEl, f){
37364 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37369 * Ext JS Library 1.1.1
37370 * Copyright(c) 2006-2007, Ext JS, LLC.
37372 * Originally Released Under LGPL - original licence link has changed is not relivant.
37375 * <script type="text/javascript">
37380 * @class Roo.form.TextField
37381 * @extends Roo.form.Field
37382 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37383 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37385 * Creates a new TextField
37386 * @param {Object} config Configuration options
37388 Roo.form.TextField = function(config){
37389 Roo.form.TextField.superclass.constructor.call(this, config);
37393 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37394 * according to the default logic, but this event provides a hook for the developer to apply additional
37395 * logic at runtime to resize the field if needed.
37396 * @param {Roo.form.Field} this This text field
37397 * @param {Number} width The new field width
37403 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37405 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37409 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37413 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37417 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37421 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37425 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37427 disableKeyFilter : false,
37429 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37433 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37437 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37439 maxLength : Number.MAX_VALUE,
37441 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37443 minLengthText : "The minimum length for this field is {0}",
37445 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37447 maxLengthText : "The maximum length for this field is {0}",
37449 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37451 selectOnFocus : false,
37453 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37455 blankText : "This field is required",
37457 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37458 * If available, this function will be called only after the basic validators all return true, and will be passed the
37459 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37463 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37464 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37465 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37469 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37473 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37479 initEvents : function()
37481 if (this.emptyText) {
37482 this.el.attr('placeholder', this.emptyText);
37485 Roo.form.TextField.superclass.initEvents.call(this);
37486 if(this.validationEvent == 'keyup'){
37487 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37488 this.el.on('keyup', this.filterValidation, this);
37490 else if(this.validationEvent !== false){
37491 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37494 if(this.selectOnFocus){
37495 this.on("focus", this.preFocus, this);
37498 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37499 this.el.on("keypress", this.filterKeys, this);
37502 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37503 this.el.on("click", this.autoSize, this);
37505 if(this.el.is('input[type=password]') && Roo.isSafari){
37506 this.el.on('keydown', this.SafariOnKeyDown, this);
37510 processValue : function(value){
37511 if(this.stripCharsRe){
37512 var newValue = value.replace(this.stripCharsRe, '');
37513 if(newValue !== value){
37514 this.setRawValue(newValue);
37521 filterValidation : function(e){
37522 if(!e.isNavKeyPress()){
37523 this.validationTask.delay(this.validationDelay);
37528 onKeyUp : function(e){
37529 if(!e.isNavKeyPress()){
37535 * Resets the current field value to the originally-loaded value and clears any validation messages.
37538 reset : function(){
37539 Roo.form.TextField.superclass.reset.call(this);
37545 preFocus : function(){
37547 if(this.selectOnFocus){
37548 this.el.dom.select();
37554 filterKeys : function(e){
37555 var k = e.getKey();
37556 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37559 var c = e.getCharCode(), cc = String.fromCharCode(c);
37560 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37563 if(!this.maskRe.test(cc)){
37568 setValue : function(v){
37570 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37576 * Validates a value according to the field's validation rules and marks the field as invalid
37577 * if the validation fails
37578 * @param {Mixed} value The value to validate
37579 * @return {Boolean} True if the value is valid, else false
37581 validateValue : function(value){
37582 if(value.length < 1) { // if it's blank
37583 if(this.allowBlank){
37584 this.clearInvalid();
37587 this.markInvalid(this.blankText);
37591 if(value.length < this.minLength){
37592 this.markInvalid(String.format(this.minLengthText, this.minLength));
37595 if(value.length > this.maxLength){
37596 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37600 var vt = Roo.form.VTypes;
37601 if(!vt[this.vtype](value, this)){
37602 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37606 if(typeof this.validator == "function"){
37607 var msg = this.validator(value);
37609 this.markInvalid(msg);
37613 if(this.regex && !this.regex.test(value)){
37614 this.markInvalid(this.regexText);
37621 * Selects text in this field
37622 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37623 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37625 selectText : function(start, end){
37626 var v = this.getRawValue();
37628 start = start === undefined ? 0 : start;
37629 end = end === undefined ? v.length : end;
37630 var d = this.el.dom;
37631 if(d.setSelectionRange){
37632 d.setSelectionRange(start, end);
37633 }else if(d.createTextRange){
37634 var range = d.createTextRange();
37635 range.moveStart("character", start);
37636 range.moveEnd("character", v.length-end);
37643 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37644 * This only takes effect if grow = true, and fires the autosize event.
37646 autoSize : function(){
37647 if(!this.grow || !this.rendered){
37651 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37654 var v = el.dom.value;
37655 var d = document.createElement('div');
37656 d.appendChild(document.createTextNode(v));
37660 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37661 this.el.setWidth(w);
37662 this.fireEvent("autosize", this, w);
37666 SafariOnKeyDown : function(event)
37668 // this is a workaround for a password hang bug on chrome/ webkit.
37670 var isSelectAll = false;
37672 if(this.el.dom.selectionEnd > 0){
37673 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37675 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37676 event.preventDefault();
37681 if(isSelectAll){ // backspace and delete key
37683 event.preventDefault();
37684 // this is very hacky as keydown always get's upper case.
37686 var cc = String.fromCharCode(event.getCharCode());
37687 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37695 * Ext JS Library 1.1.1
37696 * Copyright(c) 2006-2007, Ext JS, LLC.
37698 * Originally Released Under LGPL - original licence link has changed is not relivant.
37701 * <script type="text/javascript">
37705 * @class Roo.form.Hidden
37706 * @extends Roo.form.TextField
37707 * Simple Hidden element used on forms
37709 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37712 * Creates a new Hidden form element.
37713 * @param {Object} config Configuration options
37718 // easy hidden field...
37719 Roo.form.Hidden = function(config){
37720 Roo.form.Hidden.superclass.constructor.call(this, config);
37723 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37725 inputType: 'hidden',
37728 labelSeparator: '',
37730 itemCls : 'x-form-item-display-none'
37738 * Ext JS Library 1.1.1
37739 * Copyright(c) 2006-2007, Ext JS, LLC.
37741 * Originally Released Under LGPL - original licence link has changed is not relivant.
37744 * <script type="text/javascript">
37748 * @class Roo.form.TriggerField
37749 * @extends Roo.form.TextField
37750 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37751 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37752 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37753 * for which you can provide a custom implementation. For example:
37755 var trigger = new Roo.form.TriggerField();
37756 trigger.onTriggerClick = myTriggerFn;
37757 trigger.applyTo('my-field');
37760 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37761 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37762 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37763 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37765 * Create a new TriggerField.
37766 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37767 * to the base TextField)
37769 Roo.form.TriggerField = function(config){
37770 this.mimicing = false;
37771 Roo.form.TriggerField.superclass.constructor.call(this, config);
37774 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37776 * @cfg {String} triggerClass A CSS class to apply to the trigger
37779 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37780 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37782 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37784 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37788 /** @cfg {Boolean} grow @hide */
37789 /** @cfg {Number} growMin @hide */
37790 /** @cfg {Number} growMax @hide */
37796 autoSize: Roo.emptyFn,
37800 deferHeight : true,
37803 actionMode : 'wrap',
37805 onResize : function(w, h){
37806 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37807 if(typeof w == 'number'){
37808 var x = w - this.trigger.getWidth();
37809 this.el.setWidth(this.adjustWidth('input', x));
37810 this.trigger.setStyle('left', x+'px');
37815 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37818 getResizeEl : function(){
37823 getPositionEl : function(){
37828 alignErrorIcon : function(){
37829 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37833 onRender : function(ct, position){
37834 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37835 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37836 this.trigger = this.wrap.createChild(this.triggerConfig ||
37837 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37838 if(this.hideTrigger){
37839 this.trigger.setDisplayed(false);
37841 this.initTrigger();
37843 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37848 initTrigger : function(){
37849 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37850 this.trigger.addClassOnOver('x-form-trigger-over');
37851 this.trigger.addClassOnClick('x-form-trigger-click');
37855 onDestroy : function(){
37857 this.trigger.removeAllListeners();
37858 this.trigger.remove();
37861 this.wrap.remove();
37863 Roo.form.TriggerField.superclass.onDestroy.call(this);
37867 onFocus : function(){
37868 Roo.form.TriggerField.superclass.onFocus.call(this);
37869 if(!this.mimicing){
37870 this.wrap.addClass('x-trigger-wrap-focus');
37871 this.mimicing = true;
37872 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37873 if(this.monitorTab){
37874 this.el.on("keydown", this.checkTab, this);
37880 checkTab : function(e){
37881 if(e.getKey() == e.TAB){
37882 this.triggerBlur();
37887 onBlur : function(){
37892 mimicBlur : function(e, t){
37893 if(!this.wrap.contains(t) && this.validateBlur()){
37894 this.triggerBlur();
37899 triggerBlur : function(){
37900 this.mimicing = false;
37901 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37902 if(this.monitorTab){
37903 this.el.un("keydown", this.checkTab, this);
37905 this.wrap.removeClass('x-trigger-wrap-focus');
37906 Roo.form.TriggerField.superclass.onBlur.call(this);
37910 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37911 validateBlur : function(e, t){
37916 onDisable : function(){
37917 Roo.form.TriggerField.superclass.onDisable.call(this);
37919 this.wrap.addClass('x-item-disabled');
37924 onEnable : function(){
37925 Roo.form.TriggerField.superclass.onEnable.call(this);
37927 this.wrap.removeClass('x-item-disabled');
37932 onShow : function(){
37933 var ae = this.getActionEl();
37936 ae.dom.style.display = '';
37937 ae.dom.style.visibility = 'visible';
37943 onHide : function(){
37944 var ae = this.getActionEl();
37945 ae.dom.style.display = 'none';
37949 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37950 * by an implementing function.
37952 * @param {EventObject} e
37954 onTriggerClick : Roo.emptyFn
37957 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37958 // to be extended by an implementing class. For an example of implementing this class, see the custom
37959 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37960 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37961 initComponent : function(){
37962 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37964 this.triggerConfig = {
37965 tag:'span', cls:'x-form-twin-triggers', cn:[
37966 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37967 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37971 getTrigger : function(index){
37972 return this.triggers[index];
37975 initTrigger : function(){
37976 var ts = this.trigger.select('.x-form-trigger', true);
37977 this.wrap.setStyle('overflow', 'hidden');
37978 var triggerField = this;
37979 ts.each(function(t, all, index){
37980 t.hide = function(){
37981 var w = triggerField.wrap.getWidth();
37982 this.dom.style.display = 'none';
37983 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37985 t.show = function(){
37986 var w = triggerField.wrap.getWidth();
37987 this.dom.style.display = '';
37988 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37990 var triggerIndex = 'Trigger'+(index+1);
37992 if(this['hide'+triggerIndex]){
37993 t.dom.style.display = 'none';
37995 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37996 t.addClassOnOver('x-form-trigger-over');
37997 t.addClassOnClick('x-form-trigger-click');
37999 this.triggers = ts.elements;
38002 onTrigger1Click : Roo.emptyFn,
38003 onTrigger2Click : Roo.emptyFn
38006 * Ext JS Library 1.1.1
38007 * Copyright(c) 2006-2007, Ext JS, LLC.
38009 * Originally Released Under LGPL - original licence link has changed is not relivant.
38012 * <script type="text/javascript">
38016 * @class Roo.form.TextArea
38017 * @extends Roo.form.TextField
38018 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38019 * support for auto-sizing.
38021 * Creates a new TextArea
38022 * @param {Object} config Configuration options
38024 Roo.form.TextArea = function(config){
38025 Roo.form.TextArea.superclass.constructor.call(this, config);
38026 // these are provided exchanges for backwards compat
38027 // minHeight/maxHeight were replaced by growMin/growMax to be
38028 // compatible with TextField growing config values
38029 if(this.minHeight !== undefined){
38030 this.growMin = this.minHeight;
38032 if(this.maxHeight !== undefined){
38033 this.growMax = this.maxHeight;
38037 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38039 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38043 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38047 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38048 * in the field (equivalent to setting overflow: hidden, defaults to false)
38050 preventScrollbars: false,
38052 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38053 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38057 onRender : function(ct, position){
38059 this.defaultAutoCreate = {
38061 style:"width:300px;height:60px;",
38062 autocomplete: "off"
38065 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38067 this.textSizeEl = Roo.DomHelper.append(document.body, {
38068 tag: "pre", cls: "x-form-grow-sizer"
38070 if(this.preventScrollbars){
38071 this.el.setStyle("overflow", "hidden");
38073 this.el.setHeight(this.growMin);
38077 onDestroy : function(){
38078 if(this.textSizeEl){
38079 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38081 Roo.form.TextArea.superclass.onDestroy.call(this);
38085 onKeyUp : function(e){
38086 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38092 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38093 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38095 autoSize : function(){
38096 if(!this.grow || !this.textSizeEl){
38100 var v = el.dom.value;
38101 var ts = this.textSizeEl;
38104 ts.appendChild(document.createTextNode(v));
38107 Roo.fly(ts).setWidth(this.el.getWidth());
38109 v = "  ";
38112 v = v.replace(/\n/g, '<p> </p>');
38114 v += " \n ";
38117 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38118 if(h != this.lastHeight){
38119 this.lastHeight = h;
38120 this.el.setHeight(h);
38121 this.fireEvent("autosize", this, h);
38126 * Ext JS Library 1.1.1
38127 * Copyright(c) 2006-2007, Ext JS, LLC.
38129 * Originally Released Under LGPL - original licence link has changed is not relivant.
38132 * <script type="text/javascript">
38137 * @class Roo.form.NumberField
38138 * @extends Roo.form.TextField
38139 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38141 * Creates a new NumberField
38142 * @param {Object} config Configuration options
38144 Roo.form.NumberField = function(config){
38145 Roo.form.NumberField.superclass.constructor.call(this, config);
38148 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38150 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38152 fieldClass: "x-form-field x-form-num-field",
38154 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38156 allowDecimals : true,
38158 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38160 decimalSeparator : ".",
38162 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38164 decimalPrecision : 2,
38166 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38168 allowNegative : true,
38170 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38172 minValue : Number.NEGATIVE_INFINITY,
38174 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38176 maxValue : Number.MAX_VALUE,
38178 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38180 minText : "The minimum value for this field is {0}",
38182 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38184 maxText : "The maximum value for this field is {0}",
38186 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38187 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38189 nanText : "{0} is not a valid number",
38192 initEvents : function(){
38193 Roo.form.NumberField.superclass.initEvents.call(this);
38194 var allowed = "0123456789";
38195 if(this.allowDecimals){
38196 allowed += this.decimalSeparator;
38198 if(this.allowNegative){
38201 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38202 var keyPress = function(e){
38203 var k = e.getKey();
38204 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38207 var c = e.getCharCode();
38208 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38212 this.el.on("keypress", keyPress, this);
38216 validateValue : function(value){
38217 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38220 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38223 var num = this.parseValue(value);
38225 this.markInvalid(String.format(this.nanText, value));
38228 if(num < this.minValue){
38229 this.markInvalid(String.format(this.minText, this.minValue));
38232 if(num > this.maxValue){
38233 this.markInvalid(String.format(this.maxText, this.maxValue));
38239 getValue : function(){
38240 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38244 parseValue : function(value){
38245 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38246 return isNaN(value) ? '' : value;
38250 fixPrecision : function(value){
38251 var nan = isNaN(value);
38252 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38253 return nan ? '' : value;
38255 return parseFloat(value).toFixed(this.decimalPrecision);
38258 setValue : function(v){
38259 v = this.fixPrecision(v);
38260 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38264 decimalPrecisionFcn : function(v){
38265 return Math.floor(v);
38268 beforeBlur : function(){
38269 var v = this.parseValue(this.getRawValue());
38276 * Ext JS Library 1.1.1
38277 * Copyright(c) 2006-2007, Ext JS, LLC.
38279 * Originally Released Under LGPL - original licence link has changed is not relivant.
38282 * <script type="text/javascript">
38286 * @class Roo.form.DateField
38287 * @extends Roo.form.TriggerField
38288 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38290 * Create a new DateField
38291 * @param {Object} config
38293 Roo.form.DateField = function(config){
38294 Roo.form.DateField.superclass.constructor.call(this, config);
38300 * Fires when a date is selected
38301 * @param {Roo.form.DateField} combo This combo box
38302 * @param {Date} date The date selected
38309 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38310 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38311 this.ddMatch = null;
38312 if(this.disabledDates){
38313 var dd = this.disabledDates;
38315 for(var i = 0; i < dd.length; i++){
38317 if(i != dd.length-1) re += "|";
38319 this.ddMatch = new RegExp(re + ")");
38323 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38325 * @cfg {String} format
38326 * The default date format string which can be overriden for localization support. The format must be
38327 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38331 * @cfg {String} altFormats
38332 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38333 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38335 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38337 * @cfg {Array} disabledDays
38338 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38340 disabledDays : null,
38342 * @cfg {String} disabledDaysText
38343 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38345 disabledDaysText : "Disabled",
38347 * @cfg {Array} disabledDates
38348 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38349 * expression so they are very powerful. Some examples:
38351 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38352 * <li>["03/08", "09/16"] would disable those days for every year</li>
38353 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38354 * <li>["03/../2006"] would disable every day in March 2006</li>
38355 * <li>["^03"] would disable every day in every March</li>
38357 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38358 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38360 disabledDates : null,
38362 * @cfg {String} disabledDatesText
38363 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38365 disabledDatesText : "Disabled",
38367 * @cfg {Date/String} minValue
38368 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38369 * valid format (defaults to null).
38373 * @cfg {Date/String} maxValue
38374 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38375 * valid format (defaults to null).
38379 * @cfg {String} minText
38380 * The error text to display when the date in the cell is before minValue (defaults to
38381 * 'The date in this field must be after {minValue}').
38383 minText : "The date in this field must be equal to or after {0}",
38385 * @cfg {String} maxText
38386 * The error text to display when the date in the cell is after maxValue (defaults to
38387 * 'The date in this field must be before {maxValue}').
38389 maxText : "The date in this field must be equal to or before {0}",
38391 * @cfg {String} invalidText
38392 * The error text to display when the date in the field is invalid (defaults to
38393 * '{value} is not a valid date - it must be in the format {format}').
38395 invalidText : "{0} is not a valid date - it must be in the format {1}",
38397 * @cfg {String} triggerClass
38398 * An additional CSS class used to style the trigger button. The trigger will always get the
38399 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38400 * which displays a calendar icon).
38402 triggerClass : 'x-form-date-trigger',
38406 * @cfg {Boolean} useIso
38407 * if enabled, then the date field will use a hidden field to store the
38408 * real value as iso formated date. default (false)
38412 * @cfg {String/Object} autoCreate
38413 * A DomHelper element spec, or true for a default element spec (defaults to
38414 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38417 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38420 hiddenField: false,
38422 onRender : function(ct, position)
38424 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38426 //this.el.dom.removeAttribute('name');
38427 Roo.log("Changing name?");
38428 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38429 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38431 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38432 // prevent input submission
38433 this.hiddenName = this.name;
38440 validateValue : function(value)
38442 value = this.formatDate(value);
38443 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38444 Roo.log('super failed');
38447 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38450 var svalue = value;
38451 value = this.parseDate(value);
38453 Roo.log('parse date failed' + svalue);
38454 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38457 var time = value.getTime();
38458 if(this.minValue && time < this.minValue.getTime()){
38459 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38462 if(this.maxValue && time > this.maxValue.getTime()){
38463 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38466 if(this.disabledDays){
38467 var day = value.getDay();
38468 for(var i = 0; i < this.disabledDays.length; i++) {
38469 if(day === this.disabledDays[i]){
38470 this.markInvalid(this.disabledDaysText);
38475 var fvalue = this.formatDate(value);
38476 if(this.ddMatch && this.ddMatch.test(fvalue)){
38477 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38484 // Provides logic to override the default TriggerField.validateBlur which just returns true
38485 validateBlur : function(){
38486 return !this.menu || !this.menu.isVisible();
38489 getName: function()
38491 // returns hidden if it's set..
38492 if (!this.rendered) {return ''};
38493 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38498 * Returns the current date value of the date field.
38499 * @return {Date} The date value
38501 getValue : function(){
38503 return this.hiddenField ?
38504 this.hiddenField.value :
38505 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38509 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38510 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38511 * (the default format used is "m/d/y").
38514 //All of these calls set the same date value (May 4, 2006)
38516 //Pass a date object:
38517 var dt = new Date('5/4/06');
38518 dateField.setValue(dt);
38520 //Pass a date string (default format):
38521 dateField.setValue('5/4/06');
38523 //Pass a date string (custom format):
38524 dateField.format = 'Y-m-d';
38525 dateField.setValue('2006-5-4');
38527 * @param {String/Date} date The date or valid date string
38529 setValue : function(date){
38530 if (this.hiddenField) {
38531 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38533 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38534 // make sure the value field is always stored as a date..
38535 this.value = this.parseDate(date);
38541 parseDate : function(value){
38542 if(!value || value instanceof Date){
38545 var v = Date.parseDate(value, this.format);
38546 if (!v && this.useIso) {
38547 v = Date.parseDate(value, 'Y-m-d');
38549 if(!v && this.altFormats){
38550 if(!this.altFormatsArray){
38551 this.altFormatsArray = this.altFormats.split("|");
38553 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38554 v = Date.parseDate(value, this.altFormatsArray[i]);
38561 formatDate : function(date, fmt){
38562 return (!date || !(date instanceof Date)) ?
38563 date : date.dateFormat(fmt || this.format);
38568 select: function(m, d){
38571 this.fireEvent('select', this, d);
38573 show : function(){ // retain focus styling
38577 this.focus.defer(10, this);
38578 var ml = this.menuListeners;
38579 this.menu.un("select", ml.select, this);
38580 this.menu.un("show", ml.show, this);
38581 this.menu.un("hide", ml.hide, this);
38586 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38587 onTriggerClick : function(){
38591 if(this.menu == null){
38592 this.menu = new Roo.menu.DateMenu();
38594 Roo.apply(this.menu.picker, {
38595 showClear: this.allowBlank,
38596 minDate : this.minValue,
38597 maxDate : this.maxValue,
38598 disabledDatesRE : this.ddMatch,
38599 disabledDatesText : this.disabledDatesText,
38600 disabledDays : this.disabledDays,
38601 disabledDaysText : this.disabledDaysText,
38602 format : this.useIso ? 'Y-m-d' : this.format,
38603 minText : String.format(this.minText, this.formatDate(this.minValue)),
38604 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38606 this.menu.on(Roo.apply({}, this.menuListeners, {
38609 this.menu.picker.setValue(this.getValue() || new Date());
38610 this.menu.show(this.el, "tl-bl?");
38613 beforeBlur : function(){
38614 var v = this.parseDate(this.getRawValue());
38624 isDirty : function() {
38625 if(this.disabled) {
38629 if(typeof(this.startValue) === 'undefined'){
38633 return String(this.getValue()) !== String(this.startValue);
38638 * Ext JS Library 1.1.1
38639 * Copyright(c) 2006-2007, Ext JS, LLC.
38641 * Originally Released Under LGPL - original licence link has changed is not relivant.
38644 * <script type="text/javascript">
38648 * @class Roo.form.MonthField
38649 * @extends Roo.form.TriggerField
38650 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38652 * Create a new MonthField
38653 * @param {Object} config
38655 Roo.form.MonthField = function(config){
38657 Roo.form.MonthField.superclass.constructor.call(this, config);
38663 * Fires when a date is selected
38664 * @param {Roo.form.MonthFieeld} combo This combo box
38665 * @param {Date} date The date selected
38672 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38673 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38674 this.ddMatch = null;
38675 if(this.disabledDates){
38676 var dd = this.disabledDates;
38678 for(var i = 0; i < dd.length; i++){
38680 if(i != dd.length-1) re += "|";
38682 this.ddMatch = new RegExp(re + ")");
38686 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38688 * @cfg {String} format
38689 * The default date format string which can be overriden for localization support. The format must be
38690 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38694 * @cfg {String} altFormats
38695 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38696 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38698 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38700 * @cfg {Array} disabledDays
38701 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38703 disabledDays : [0,1,2,3,4,5,6],
38705 * @cfg {String} disabledDaysText
38706 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38708 disabledDaysText : "Disabled",
38710 * @cfg {Array} disabledDates
38711 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38712 * expression so they are very powerful. Some examples:
38714 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38715 * <li>["03/08", "09/16"] would disable those days for every year</li>
38716 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38717 * <li>["03/../2006"] would disable every day in March 2006</li>
38718 * <li>["^03"] would disable every day in every March</li>
38720 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38721 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38723 disabledDates : null,
38725 * @cfg {String} disabledDatesText
38726 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38728 disabledDatesText : "Disabled",
38730 * @cfg {Date/String} minValue
38731 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38732 * valid format (defaults to null).
38736 * @cfg {Date/String} maxValue
38737 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38738 * valid format (defaults to null).
38742 * @cfg {String} minText
38743 * The error text to display when the date in the cell is before minValue (defaults to
38744 * 'The date in this field must be after {minValue}').
38746 minText : "The date in this field must be equal to or after {0}",
38748 * @cfg {String} maxTextf
38749 * The error text to display when the date in the cell is after maxValue (defaults to
38750 * 'The date in this field must be before {maxValue}').
38752 maxText : "The date in this field must be equal to or before {0}",
38754 * @cfg {String} invalidText
38755 * The error text to display when the date in the field is invalid (defaults to
38756 * '{value} is not a valid date - it must be in the format {format}').
38758 invalidText : "{0} is not a valid date - it must be in the format {1}",
38760 * @cfg {String} triggerClass
38761 * An additional CSS class used to style the trigger button. The trigger will always get the
38762 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38763 * which displays a calendar icon).
38765 triggerClass : 'x-form-date-trigger',
38769 * @cfg {Boolean} useIso
38770 * if enabled, then the date field will use a hidden field to store the
38771 * real value as iso formated date. default (true)
38775 * @cfg {String/Object} autoCreate
38776 * A DomHelper element spec, or true for a default element spec (defaults to
38777 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38780 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38783 hiddenField: false,
38785 hideMonthPicker : false,
38787 onRender : function(ct, position)
38789 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38791 this.el.dom.removeAttribute('name');
38792 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38794 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38795 // prevent input submission
38796 this.hiddenName = this.name;
38803 validateValue : function(value)
38805 value = this.formatDate(value);
38806 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38809 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38812 var svalue = value;
38813 value = this.parseDate(value);
38815 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38818 var time = value.getTime();
38819 if(this.minValue && time < this.minValue.getTime()){
38820 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38823 if(this.maxValue && time > this.maxValue.getTime()){
38824 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38827 /*if(this.disabledDays){
38828 var day = value.getDay();
38829 for(var i = 0; i < this.disabledDays.length; i++) {
38830 if(day === this.disabledDays[i]){
38831 this.markInvalid(this.disabledDaysText);
38837 var fvalue = this.formatDate(value);
38838 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38839 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38847 // Provides logic to override the default TriggerField.validateBlur which just returns true
38848 validateBlur : function(){
38849 return !this.menu || !this.menu.isVisible();
38853 * Returns the current date value of the date field.
38854 * @return {Date} The date value
38856 getValue : function(){
38860 return this.hiddenField ?
38861 this.hiddenField.value :
38862 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38866 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38867 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38868 * (the default format used is "m/d/y").
38871 //All of these calls set the same date value (May 4, 2006)
38873 //Pass a date object:
38874 var dt = new Date('5/4/06');
38875 monthField.setValue(dt);
38877 //Pass a date string (default format):
38878 monthField.setValue('5/4/06');
38880 //Pass a date string (custom format):
38881 monthField.format = 'Y-m-d';
38882 monthField.setValue('2006-5-4');
38884 * @param {String/Date} date The date or valid date string
38886 setValue : function(date){
38887 Roo.log('month setValue' + date);
38888 // can only be first of month..
38890 var val = this.parseDate(date);
38892 if (this.hiddenField) {
38893 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38895 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38896 this.value = this.parseDate(date);
38900 parseDate : function(value){
38901 if(!value || value instanceof Date){
38902 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38905 var v = Date.parseDate(value, this.format);
38906 if (!v && this.useIso) {
38907 v = Date.parseDate(value, 'Y-m-d');
38911 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38915 if(!v && this.altFormats){
38916 if(!this.altFormatsArray){
38917 this.altFormatsArray = this.altFormats.split("|");
38919 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38920 v = Date.parseDate(value, this.altFormatsArray[i]);
38927 formatDate : function(date, fmt){
38928 return (!date || !(date instanceof Date)) ?
38929 date : date.dateFormat(fmt || this.format);
38934 select: function(m, d){
38936 this.fireEvent('select', this, d);
38938 show : function(){ // retain focus styling
38942 this.focus.defer(10, this);
38943 var ml = this.menuListeners;
38944 this.menu.un("select", ml.select, this);
38945 this.menu.un("show", ml.show, this);
38946 this.menu.un("hide", ml.hide, this);
38950 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38951 onTriggerClick : function(){
38955 if(this.menu == null){
38956 this.menu = new Roo.menu.DateMenu();
38960 Roo.apply(this.menu.picker, {
38962 showClear: this.allowBlank,
38963 minDate : this.minValue,
38964 maxDate : this.maxValue,
38965 disabledDatesRE : this.ddMatch,
38966 disabledDatesText : this.disabledDatesText,
38968 format : this.useIso ? 'Y-m-d' : this.format,
38969 minText : String.format(this.minText, this.formatDate(this.minValue)),
38970 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38973 this.menu.on(Roo.apply({}, this.menuListeners, {
38981 // hide month picker get's called when we called by 'before hide';
38983 var ignorehide = true;
38984 p.hideMonthPicker = function(disableAnim){
38988 if(this.monthPicker){
38989 Roo.log("hideMonthPicker called");
38990 if(disableAnim === true){
38991 this.monthPicker.hide();
38993 this.monthPicker.slideOut('t', {duration:.2});
38994 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38995 p.fireEvent("select", this, this.value);
39001 Roo.log('picker set value');
39002 Roo.log(this.getValue());
39003 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39004 m.show(this.el, 'tl-bl?');
39005 ignorehide = false;
39006 // this will trigger hideMonthPicker..
39009 // hidden the day picker
39010 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39016 p.showMonthPicker.defer(100, p);
39022 beforeBlur : function(){
39023 var v = this.parseDate(this.getRawValue());
39029 /** @cfg {Boolean} grow @hide */
39030 /** @cfg {Number} growMin @hide */
39031 /** @cfg {Number} growMax @hide */
39038 * Ext JS Library 1.1.1
39039 * Copyright(c) 2006-2007, Ext JS, LLC.
39041 * Originally Released Under LGPL - original licence link has changed is not relivant.
39044 * <script type="text/javascript">
39049 * @class Roo.form.ComboBox
39050 * @extends Roo.form.TriggerField
39051 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39053 * Create a new ComboBox.
39054 * @param {Object} config Configuration options
39056 Roo.form.ComboBox = function(config){
39057 Roo.form.ComboBox.superclass.constructor.call(this, config);
39061 * Fires when the dropdown list is expanded
39062 * @param {Roo.form.ComboBox} combo This combo box
39067 * Fires when the dropdown list is collapsed
39068 * @param {Roo.form.ComboBox} combo This combo box
39072 * @event beforeselect
39073 * Fires before a list item is selected. Return false to cancel the selection.
39074 * @param {Roo.form.ComboBox} combo This combo box
39075 * @param {Roo.data.Record} record The data record returned from the underlying store
39076 * @param {Number} index The index of the selected item in the dropdown list
39078 'beforeselect' : true,
39081 * Fires when a list item is selected
39082 * @param {Roo.form.ComboBox} combo This combo box
39083 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39084 * @param {Number} index The index of the selected item in the dropdown list
39088 * @event beforequery
39089 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39090 * The event object passed has these properties:
39091 * @param {Roo.form.ComboBox} combo This combo box
39092 * @param {String} query The query
39093 * @param {Boolean} forceAll true to force "all" query
39094 * @param {Boolean} cancel true to cancel the query
39095 * @param {Object} e The query event object
39097 'beforequery': true,
39100 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39101 * @param {Roo.form.ComboBox} combo This combo box
39106 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39107 * @param {Roo.form.ComboBox} combo This combo box
39108 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39114 if(this.transform){
39115 this.allowDomMove = false;
39116 var s = Roo.getDom(this.transform);
39117 if(!this.hiddenName){
39118 this.hiddenName = s.name;
39121 this.mode = 'local';
39122 var d = [], opts = s.options;
39123 for(var i = 0, len = opts.length;i < len; i++){
39125 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39127 this.value = value;
39129 d.push([value, o.text]);
39131 this.store = new Roo.data.SimpleStore({
39133 fields: ['value', 'text'],
39136 this.valueField = 'value';
39137 this.displayField = 'text';
39139 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39140 if(!this.lazyRender){
39141 this.target = true;
39142 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39143 s.parentNode.removeChild(s); // remove it
39144 this.render(this.el.parentNode);
39146 s.parentNode.removeChild(s); // remove it
39151 this.store = Roo.factory(this.store, Roo.data);
39154 this.selectedIndex = -1;
39155 if(this.mode == 'local'){
39156 if(config.queryDelay === undefined){
39157 this.queryDelay = 10;
39159 if(config.minChars === undefined){
39165 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39167 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39170 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39171 * rendering into an Roo.Editor, defaults to false)
39174 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39175 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39178 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39181 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39182 * the dropdown list (defaults to undefined, with no header element)
39186 * @cfg {String/Roo.Template} tpl The template to use to render the output
39190 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39192 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39194 listWidth: undefined,
39196 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39197 * mode = 'remote' or 'text' if mode = 'local')
39199 displayField: undefined,
39201 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39202 * mode = 'remote' or 'value' if mode = 'local').
39203 * Note: use of a valueField requires the user make a selection
39204 * in order for a value to be mapped.
39206 valueField: undefined,
39210 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39211 * field's data value (defaults to the underlying DOM element's name)
39213 hiddenName: undefined,
39215 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39219 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39221 selectedClass: 'x-combo-selected',
39223 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39224 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39225 * which displays a downward arrow icon).
39227 triggerClass : 'x-form-arrow-trigger',
39229 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39233 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39234 * anchor positions (defaults to 'tl-bl')
39236 listAlign: 'tl-bl?',
39238 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39242 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39243 * query specified by the allQuery config option (defaults to 'query')
39245 triggerAction: 'query',
39247 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39248 * (defaults to 4, does not apply if editable = false)
39252 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39253 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39257 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39258 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39262 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39263 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39267 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39268 * when editable = true (defaults to false)
39270 selectOnFocus:false,
39272 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39274 queryParam: 'query',
39276 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39277 * when mode = 'remote' (defaults to 'Loading...')
39279 loadingText: 'Loading...',
39281 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39285 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39289 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39290 * traditional select (defaults to true)
39294 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39298 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39302 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39303 * listWidth has a higher value)
39307 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39308 * allow the user to set arbitrary text into the field (defaults to false)
39310 forceSelection:false,
39312 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39313 * if typeAhead = true (defaults to 250)
39315 typeAheadDelay : 250,
39317 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39318 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39320 valueNotFoundText : undefined,
39322 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39324 blockFocus : false,
39327 * @cfg {Boolean} disableClear Disable showing of clear button.
39329 disableClear : false,
39331 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39333 alwaysQuery : false,
39339 // element that contains real text value.. (when hidden is used..)
39342 onRender : function(ct, position){
39343 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39344 if(this.hiddenName){
39345 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39347 this.hiddenField.value =
39348 this.hiddenValue !== undefined ? this.hiddenValue :
39349 this.value !== undefined ? this.value : '';
39351 // prevent input submission
39352 this.el.dom.removeAttribute('name');
39357 this.el.dom.setAttribute('autocomplete', 'off');
39360 var cls = 'x-combo-list';
39362 this.list = new Roo.Layer({
39363 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39366 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39367 this.list.setWidth(lw);
39368 this.list.swallowEvent('mousewheel');
39369 this.assetHeight = 0;
39372 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39373 this.assetHeight += this.header.getHeight();
39376 this.innerList = this.list.createChild({cls:cls+'-inner'});
39377 this.innerList.on('mouseover', this.onViewOver, this);
39378 this.innerList.on('mousemove', this.onViewMove, this);
39379 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39381 if(this.allowBlank && !this.pageSize && !this.disableClear){
39382 this.footer = this.list.createChild({cls:cls+'-ft'});
39383 this.pageTb = new Roo.Toolbar(this.footer);
39387 this.footer = this.list.createChild({cls:cls+'-ft'});
39388 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39389 {pageSize: this.pageSize});
39393 if (this.pageTb && this.allowBlank && !this.disableClear) {
39395 this.pageTb.add(new Roo.Toolbar.Fill(), {
39396 cls: 'x-btn-icon x-btn-clear',
39398 handler: function()
39401 _this.clearValue();
39402 _this.onSelect(false, -1);
39407 this.assetHeight += this.footer.getHeight();
39412 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39415 this.view = new Roo.View(this.innerList, this.tpl, {
39416 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39419 this.view.on('click', this.onViewClick, this);
39421 this.store.on('beforeload', this.onBeforeLoad, this);
39422 this.store.on('load', this.onLoad, this);
39423 this.store.on('loadexception', this.onLoadException, this);
39425 if(this.resizable){
39426 this.resizer = new Roo.Resizable(this.list, {
39427 pinned:true, handles:'se'
39429 this.resizer.on('resize', function(r, w, h){
39430 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39431 this.listWidth = w;
39432 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39433 this.restrictHeight();
39435 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39437 if(!this.editable){
39438 this.editable = true;
39439 this.setEditable(false);
39443 if (typeof(this.events.add.listeners) != 'undefined') {
39445 this.addicon = this.wrap.createChild(
39446 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39448 this.addicon.on('click', function(e) {
39449 this.fireEvent('add', this);
39452 if (typeof(this.events.edit.listeners) != 'undefined') {
39454 this.editicon = this.wrap.createChild(
39455 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39456 if (this.addicon) {
39457 this.editicon.setStyle('margin-left', '40px');
39459 this.editicon.on('click', function(e) {
39461 // we fire even if inothing is selected..
39462 this.fireEvent('edit', this, this.lastData );
39472 initEvents : function(){
39473 Roo.form.ComboBox.superclass.initEvents.call(this);
39475 this.keyNav = new Roo.KeyNav(this.el, {
39476 "up" : function(e){
39477 this.inKeyMode = true;
39481 "down" : function(e){
39482 if(!this.isExpanded()){
39483 this.onTriggerClick();
39485 this.inKeyMode = true;
39490 "enter" : function(e){
39491 this.onViewClick();
39495 "esc" : function(e){
39499 "tab" : function(e){
39500 this.onViewClick(false);
39501 this.fireEvent("specialkey", this, e);
39507 doRelay : function(foo, bar, hname){
39508 if(hname == 'down' || this.scope.isExpanded()){
39509 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39516 this.queryDelay = Math.max(this.queryDelay || 10,
39517 this.mode == 'local' ? 10 : 250);
39518 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39519 if(this.typeAhead){
39520 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39522 if(this.editable !== false){
39523 this.el.on("keyup", this.onKeyUp, this);
39525 if(this.forceSelection){
39526 this.on('blur', this.doForce, this);
39530 onDestroy : function(){
39532 this.view.setStore(null);
39533 this.view.el.removeAllListeners();
39534 this.view.el.remove();
39535 this.view.purgeListeners();
39538 this.list.destroy();
39541 this.store.un('beforeload', this.onBeforeLoad, this);
39542 this.store.un('load', this.onLoad, this);
39543 this.store.un('loadexception', this.onLoadException, this);
39545 Roo.form.ComboBox.superclass.onDestroy.call(this);
39549 fireKey : function(e){
39550 if(e.isNavKeyPress() && !this.list.isVisible()){
39551 this.fireEvent("specialkey", this, e);
39556 onResize: function(w, h){
39557 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39559 if(typeof w != 'number'){
39560 // we do not handle it!?!?
39563 var tw = this.trigger.getWidth();
39564 tw += this.addicon ? this.addicon.getWidth() : 0;
39565 tw += this.editicon ? this.editicon.getWidth() : 0;
39567 this.el.setWidth( this.adjustWidth('input', x));
39569 this.trigger.setStyle('left', x+'px');
39571 if(this.list && this.listWidth === undefined){
39572 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39573 this.list.setWidth(lw);
39574 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39582 * Allow or prevent the user from directly editing the field text. If false is passed,
39583 * the user will only be able to select from the items defined in the dropdown list. This method
39584 * is the runtime equivalent of setting the 'editable' config option at config time.
39585 * @param {Boolean} value True to allow the user to directly edit the field text
39587 setEditable : function(value){
39588 if(value == this.editable){
39591 this.editable = value;
39593 this.el.dom.setAttribute('readOnly', true);
39594 this.el.on('mousedown', this.onTriggerClick, this);
39595 this.el.addClass('x-combo-noedit');
39597 this.el.dom.setAttribute('readOnly', false);
39598 this.el.un('mousedown', this.onTriggerClick, this);
39599 this.el.removeClass('x-combo-noedit');
39604 onBeforeLoad : function(){
39605 if(!this.hasFocus){
39608 this.innerList.update(this.loadingText ?
39609 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39610 this.restrictHeight();
39611 this.selectedIndex = -1;
39615 onLoad : function(){
39616 if(!this.hasFocus){
39619 if(this.store.getCount() > 0){
39621 this.restrictHeight();
39622 if(this.lastQuery == this.allQuery){
39624 this.el.dom.select();
39626 if(!this.selectByValue(this.value, true)){
39627 this.select(0, true);
39631 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39632 this.taTask.delay(this.typeAheadDelay);
39636 this.onEmptyResults();
39641 onLoadException : function()
39644 Roo.log(this.store.reader.jsonData);
39645 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39646 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39652 onTypeAhead : function(){
39653 if(this.store.getCount() > 0){
39654 var r = this.store.getAt(0);
39655 var newValue = r.data[this.displayField];
39656 var len = newValue.length;
39657 var selStart = this.getRawValue().length;
39658 if(selStart != len){
39659 this.setRawValue(newValue);
39660 this.selectText(selStart, newValue.length);
39666 onSelect : function(record, index){
39667 if(this.fireEvent('beforeselect', this, record, index) !== false){
39668 this.setFromData(index > -1 ? record.data : false);
39670 this.fireEvent('select', this, record, index);
39675 * Returns the currently selected field value or empty string if no value is set.
39676 * @return {String} value The selected value
39678 getValue : function(){
39679 if(this.valueField){
39680 return typeof this.value != 'undefined' ? this.value : '';
39682 return Roo.form.ComboBox.superclass.getValue.call(this);
39687 * Clears any text/value currently set in the field
39689 clearValue : function(){
39690 if(this.hiddenField){
39691 this.hiddenField.value = '';
39694 this.setRawValue('');
39695 this.lastSelectionText = '';
39700 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39701 * will be displayed in the field. If the value does not match the data value of an existing item,
39702 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39703 * Otherwise the field will be blank (although the value will still be set).
39704 * @param {String} value The value to match
39706 setValue : function(v){
39708 if(this.valueField){
39709 var r = this.findRecord(this.valueField, v);
39711 text = r.data[this.displayField];
39712 }else if(this.valueNotFoundText !== undefined){
39713 text = this.valueNotFoundText;
39716 this.lastSelectionText = text;
39717 if(this.hiddenField){
39718 this.hiddenField.value = v;
39720 Roo.form.ComboBox.superclass.setValue.call(this, text);
39724 * @property {Object} the last set data for the element
39729 * Sets the value of the field based on a object which is related to the record format for the store.
39730 * @param {Object} value the value to set as. or false on reset?
39732 setFromData : function(o){
39733 var dv = ''; // display value
39734 var vv = ''; // value value..
39736 if (this.displayField) {
39737 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39739 // this is an error condition!!!
39740 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39743 if(this.valueField){
39744 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39746 if(this.hiddenField){
39747 this.hiddenField.value = vv;
39749 this.lastSelectionText = dv;
39750 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39754 // no hidden field.. - we store the value in 'value', but still display
39755 // display field!!!!
39756 this.lastSelectionText = dv;
39757 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39763 reset : function(){
39764 // overridden so that last data is reset..
39765 this.setValue(this.resetValue);
39766 this.clearInvalid();
39767 this.lastData = false;
39769 this.view.clearSelections();
39773 findRecord : function(prop, value){
39775 if(this.store.getCount() > 0){
39776 this.store.each(function(r){
39777 if(r.data[prop] == value){
39787 getName: function()
39789 // returns hidden if it's set..
39790 if (!this.rendered) {return ''};
39791 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39795 onViewMove : function(e, t){
39796 this.inKeyMode = false;
39800 onViewOver : function(e, t){
39801 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39804 var item = this.view.findItemFromChild(t);
39806 var index = this.view.indexOf(item);
39807 this.select(index, false);
39812 onViewClick : function(doFocus)
39814 var index = this.view.getSelectedIndexes()[0];
39815 var r = this.store.getAt(index);
39817 this.onSelect(r, index);
39819 if(doFocus !== false && !this.blockFocus){
39825 restrictHeight : function(){
39826 this.innerList.dom.style.height = '';
39827 var inner = this.innerList.dom;
39828 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39829 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39830 this.list.beginUpdate();
39831 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39832 this.list.alignTo(this.el, this.listAlign);
39833 this.list.endUpdate();
39837 onEmptyResults : function(){
39842 * Returns true if the dropdown list is expanded, else false.
39844 isExpanded : function(){
39845 return this.list.isVisible();
39849 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39850 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39851 * @param {String} value The data value of the item to select
39852 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39853 * selected item if it is not currently in view (defaults to true)
39854 * @return {Boolean} True if the value matched an item in the list, else false
39856 selectByValue : function(v, scrollIntoView){
39857 if(v !== undefined && v !== null){
39858 var r = this.findRecord(this.valueField || this.displayField, v);
39860 this.select(this.store.indexOf(r), scrollIntoView);
39868 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39869 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39870 * @param {Number} index The zero-based index of the list item to select
39871 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39872 * selected item if it is not currently in view (defaults to true)
39874 select : function(index, scrollIntoView){
39875 this.selectedIndex = index;
39876 this.view.select(index);
39877 if(scrollIntoView !== false){
39878 var el = this.view.getNode(index);
39880 this.innerList.scrollChildIntoView(el, false);
39886 selectNext : function(){
39887 var ct = this.store.getCount();
39889 if(this.selectedIndex == -1){
39891 }else if(this.selectedIndex < ct-1){
39892 this.select(this.selectedIndex+1);
39898 selectPrev : function(){
39899 var ct = this.store.getCount();
39901 if(this.selectedIndex == -1){
39903 }else if(this.selectedIndex != 0){
39904 this.select(this.selectedIndex-1);
39910 onKeyUp : function(e){
39911 if(this.editable !== false && !e.isSpecialKey()){
39912 this.lastKey = e.getKey();
39913 this.dqTask.delay(this.queryDelay);
39918 validateBlur : function(){
39919 return !this.list || !this.list.isVisible();
39923 initQuery : function(){
39924 this.doQuery(this.getRawValue());
39928 doForce : function(){
39929 if(this.el.dom.value.length > 0){
39930 this.el.dom.value =
39931 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39937 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39938 * query allowing the query action to be canceled if needed.
39939 * @param {String} query The SQL query to execute
39940 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39941 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39942 * saved in the current store (defaults to false)
39944 doQuery : function(q, forceAll){
39945 if(q === undefined || q === null){
39950 forceAll: forceAll,
39954 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39958 forceAll = qe.forceAll;
39959 if(forceAll === true || (q.length >= this.minChars)){
39960 if(this.lastQuery != q || this.alwaysQuery){
39961 this.lastQuery = q;
39962 if(this.mode == 'local'){
39963 this.selectedIndex = -1;
39965 this.store.clearFilter();
39967 this.store.filter(this.displayField, q);
39971 this.store.baseParams[this.queryParam] = q;
39973 params: this.getParams(q)
39978 this.selectedIndex = -1;
39985 getParams : function(q){
39987 //p[this.queryParam] = q;
39990 p.limit = this.pageSize;
39996 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39998 collapse : function(){
39999 if(!this.isExpanded()){
40003 Roo.get(document).un('mousedown', this.collapseIf, this);
40004 Roo.get(document).un('mousewheel', this.collapseIf, this);
40005 if (!this.editable) {
40006 Roo.get(document).un('keydown', this.listKeyPress, this);
40008 this.fireEvent('collapse', this);
40012 collapseIf : function(e){
40013 if(!e.within(this.wrap) && !e.within(this.list)){
40019 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40021 expand : function(){
40022 if(this.isExpanded() || !this.hasFocus){
40025 this.list.alignTo(this.el, this.listAlign);
40027 Roo.get(document).on('mousedown', this.collapseIf, this);
40028 Roo.get(document).on('mousewheel', this.collapseIf, this);
40029 if (!this.editable) {
40030 Roo.get(document).on('keydown', this.listKeyPress, this);
40033 this.fireEvent('expand', this);
40037 // Implements the default empty TriggerField.onTriggerClick function
40038 onTriggerClick : function(){
40042 if(this.isExpanded()){
40044 if (!this.blockFocus) {
40049 this.hasFocus = true;
40050 if(this.triggerAction == 'all') {
40051 this.doQuery(this.allQuery, true);
40053 this.doQuery(this.getRawValue());
40055 if (!this.blockFocus) {
40060 listKeyPress : function(e)
40062 //Roo.log('listkeypress');
40063 // scroll to first matching element based on key pres..
40064 if (e.isSpecialKey()) {
40067 var k = String.fromCharCode(e.getKey()).toUpperCase();
40070 var csel = this.view.getSelectedNodes();
40071 var cselitem = false;
40073 var ix = this.view.indexOf(csel[0]);
40074 cselitem = this.store.getAt(ix);
40075 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40081 this.store.each(function(v) {
40083 // start at existing selection.
40084 if (cselitem.id == v.id) {
40090 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40091 match = this.store.indexOf(v);
40096 if (match === false) {
40097 return true; // no more action?
40100 this.view.select(match);
40101 var sn = Roo.get(this.view.getSelectedNodes()[0])
40102 sn.scrollIntoView(sn.dom.parentNode, false);
40106 * @cfg {Boolean} grow
40110 * @cfg {Number} growMin
40114 * @cfg {Number} growMax
40122 * Copyright(c) 2010-2012, Roo J Solutions Limited
40129 * @class Roo.form.ComboBoxArray
40130 * @extends Roo.form.TextField
40131 * A facebook style adder... for lists of email / people / countries etc...
40132 * pick multiple items from a combo box, and shows each one.
40134 * Fred [x] Brian [x] [Pick another |v]
40137 * For this to work: it needs various extra information
40138 * - normal combo problay has
40140 * + displayField, valueField
40142 * For our purpose...
40145 * If we change from 'extends' to wrapping...
40152 * Create a new ComboBoxArray.
40153 * @param {Object} config Configuration options
40157 Roo.form.ComboBoxArray = function(config)
40160 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40162 this.items = new Roo.util.MixedCollection(false);
40164 // construct the child combo...
40174 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40177 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40182 // behavies liek a hiddne field
40183 inputType: 'hidden',
40185 * @cfg {Number} width The width of the box that displays the selected element
40192 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40196 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40198 hiddenName : false,
40201 // private the array of items that are displayed..
40203 // private - the hidden field el.
40205 // private - the filed el..
40208 //validateValue : function() { return true; }, // all values are ok!
40209 //onAddClick: function() { },
40211 onRender : function(ct, position)
40214 // create the standard hidden element
40215 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40218 // give fake names to child combo;
40219 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40220 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40222 this.combo = Roo.factory(this.combo, Roo.form);
40223 this.combo.onRender(ct, position);
40224 if (typeof(this.combo.width) != 'undefined') {
40225 this.combo.onResize(this.combo.width,0);
40228 this.combo.initEvents();
40230 // assigned so form know we need to do this..
40231 this.store = this.combo.store;
40232 this.valueField = this.combo.valueField;
40233 this.displayField = this.combo.displayField ;
40236 this.combo.wrap.addClass('x-cbarray-grp');
40238 var cbwrap = this.combo.wrap.createChild(
40239 {tag: 'div', cls: 'x-cbarray-cb'},
40244 this.hiddenEl = this.combo.wrap.createChild({
40245 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40247 this.el = this.combo.wrap.createChild({
40248 tag: 'input', type:'hidden' , name: this.name, value : ''
40250 // this.el.dom.removeAttribute("name");
40253 this.outerWrap = this.combo.wrap;
40254 this.wrap = cbwrap;
40256 this.outerWrap.setWidth(this.width);
40257 this.outerWrap.dom.removeChild(this.el.dom);
40259 this.wrap.dom.appendChild(this.el.dom);
40260 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40261 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40263 this.combo.trigger.setStyle('position','relative');
40264 this.combo.trigger.setStyle('left', '0px');
40265 this.combo.trigger.setStyle('top', '2px');
40267 this.combo.el.setStyle('vertical-align', 'text-bottom');
40269 //this.trigger.setStyle('vertical-align', 'top');
40271 // this should use the code from combo really... on('add' ....)
40275 this.adder = this.outerWrap.createChild(
40276 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40278 this.adder.on('click', function(e) {
40279 _t.fireEvent('adderclick', this, e);
40283 //this.adder.on('click', this.onAddClick, _t);
40286 this.combo.on('select', function(cb, rec, ix) {
40287 this.addItem(rec.data);
40290 cb.el.dom.value = '';
40291 //cb.lastData = rec.data;
40300 getName: function()
40302 // returns hidden if it's set..
40303 if (!this.rendered) {return ''};
40304 return this.hiddenName ? this.hiddenName : this.name;
40309 onResize: function(w, h){
40312 // not sure if this is needed..
40313 //this.combo.onResize(w,h);
40315 if(typeof w != 'number'){
40316 // we do not handle it!?!?
40319 var tw = this.combo.trigger.getWidth();
40320 tw += this.addicon ? this.addicon.getWidth() : 0;
40321 tw += this.editicon ? this.editicon.getWidth() : 0;
40323 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40325 this.combo.trigger.setStyle('left', '0px');
40327 if(this.list && this.listWidth === undefined){
40328 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40329 this.list.setWidth(lw);
40330 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40337 addItem: function(rec)
40339 var valueField = this.combo.valueField;
40340 var displayField = this.combo.displayField;
40341 if (this.items.indexOfKey(rec[valueField]) > -1) {
40342 //console.log("GOT " + rec.data.id);
40346 var x = new Roo.form.ComboBoxArray.Item({
40347 //id : rec[this.idField],
40349 displayField : displayField ,
40350 tipField : displayField ,
40354 this.items.add(rec[valueField],x);
40355 // add it before the element..
40356 this.updateHiddenEl();
40357 x.render(this.outerWrap, this.wrap.dom);
40358 // add the image handler..
40361 updateHiddenEl : function()
40364 if (!this.hiddenEl) {
40368 var idField = this.combo.valueField;
40370 this.items.each(function(f) {
40371 ar.push(f.data[idField]);
40374 this.hiddenEl.dom.value = ar.join(',');
40380 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40381 this.items.each(function(f) {
40384 this.el.dom.value = '';
40385 if (this.hiddenEl) {
40386 this.hiddenEl.dom.value = '';
40390 getValue: function()
40392 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40394 setValue: function(v) // not a valid action - must use addItems..
40401 if (this.store.isLocal && (typeof(v) == 'string')) {
40402 // then we can use the store to find the values..
40403 // comma seperated at present.. this needs to allow JSON based encoding..
40404 this.hiddenEl.value = v;
40406 Roo.each(v.split(','), function(k) {
40407 Roo.log("CHECK " + this.valueField + ',' + k);
40408 var li = this.store.query(this.valueField, k);
40413 add[this.valueField] = k;
40414 add[this.displayField] = li.item(0).data[this.displayField];
40420 if (typeof(v) == 'object') {
40421 // then let's assume it's an array of objects..
40422 Roo.each(v, function(l) {
40430 setFromData: function(v)
40432 // this recieves an object, if setValues is called.
40434 this.el.dom.value = v[this.displayField];
40435 this.hiddenEl.dom.value = v[this.valueField];
40436 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40439 var kv = v[this.valueField];
40440 var dv = v[this.displayField];
40441 kv = typeof(kv) != 'string' ? '' : kv;
40442 dv = typeof(dv) != 'string' ? '' : dv;
40445 var keys = kv.split(',');
40446 var display = dv.split(',');
40447 for (var i = 0 ; i < keys.length; i++) {
40450 add[this.valueField] = keys[i];
40451 add[this.displayField] = display[i];
40459 * Validates the combox array value
40460 * @return {Boolean} True if the value is valid, else false
40462 validate : function(){
40463 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40464 this.clearInvalid();
40470 validateValue : function(value){
40471 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40479 isDirty : function() {
40480 if(this.disabled) {
40485 var d = Roo.decode(String(this.originalValue));
40487 return String(this.getValue()) !== String(this.originalValue);
40490 var originalValue = [];
40492 for (var i = 0; i < d.length; i++){
40493 originalValue.push(d[i][this.valueField]);
40496 return String(this.getValue()) !== String(originalValue.join(','));
40505 * @class Roo.form.ComboBoxArray.Item
40506 * @extends Roo.BoxComponent
40507 * A selected item in the list
40508 * Fred [x] Brian [x] [Pick another |v]
40511 * Create a new item.
40512 * @param {Object} config Configuration options
40515 Roo.form.ComboBoxArray.Item = function(config) {
40516 config.id = Roo.id();
40517 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40520 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40523 displayField : false,
40527 defaultAutoCreate : {
40529 cls: 'x-cbarray-item',
40536 src : Roo.BLANK_IMAGE_URL ,
40544 onRender : function(ct, position)
40546 Roo.form.Field.superclass.onRender.call(this, ct, position);
40549 var cfg = this.getAutoCreate();
40550 this.el = ct.createChild(cfg, position);
40553 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40555 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40556 this.cb.renderer(this.data) :
40557 String.format('{0}',this.data[this.displayField]);
40560 this.el.child('div').dom.setAttribute('qtip',
40561 String.format('{0}',this.data[this.tipField])
40564 this.el.child('img').on('click', this.remove, this);
40568 remove : function()
40571 this.cb.items.remove(this);
40572 this.el.child('img').un('click', this.remove, this);
40574 this.cb.updateHiddenEl();
40578 * Ext JS Library 1.1.1
40579 * Copyright(c) 2006-2007, Ext JS, LLC.
40581 * Originally Released Under LGPL - original licence link has changed is not relivant.
40584 * <script type="text/javascript">
40587 * @class Roo.form.Checkbox
40588 * @extends Roo.form.Field
40589 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40591 * Creates a new Checkbox
40592 * @param {Object} config Configuration options
40594 Roo.form.Checkbox = function(config){
40595 Roo.form.Checkbox.superclass.constructor.call(this, config);
40599 * Fires when the checkbox is checked or unchecked.
40600 * @param {Roo.form.Checkbox} this This checkbox
40601 * @param {Boolean} checked The new checked value
40607 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40609 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40611 focusClass : undefined,
40613 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40615 fieldClass: "x-form-field",
40617 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40621 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40622 * {tag: "input", type: "checkbox", autocomplete: "off"})
40624 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40626 * @cfg {String} boxLabel The text that appears beside the checkbox
40630 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40634 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40636 valueOff: '0', // value when not checked..
40638 actionMode : 'viewEl',
40641 itemCls : 'x-menu-check-item x-form-item',
40642 groupClass : 'x-menu-group-item',
40643 inputType : 'hidden',
40646 inSetChecked: false, // check that we are not calling self...
40648 inputElement: false, // real input element?
40649 basedOn: false, // ????
40651 isFormField: true, // not sure where this is needed!!!!
40653 onResize : function(){
40654 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40655 if(!this.boxLabel){
40656 this.el.alignTo(this.wrap, 'c-c');
40660 initEvents : function(){
40661 Roo.form.Checkbox.superclass.initEvents.call(this);
40662 this.el.on("click", this.onClick, this);
40663 this.el.on("change", this.onClick, this);
40667 getResizeEl : function(){
40671 getPositionEl : function(){
40676 onRender : function(ct, position){
40677 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40679 if(this.inputValue !== undefined){
40680 this.el.dom.value = this.inputValue;
40683 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40684 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40685 var viewEl = this.wrap.createChild({
40686 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40687 this.viewEl = viewEl;
40688 this.wrap.on('click', this.onClick, this);
40690 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40691 this.el.on('propertychange', this.setFromHidden, this); //ie
40696 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40697 // viewEl.on('click', this.onClick, this);
40699 //if(this.checked){
40700 this.setChecked(this.checked);
40702 //this.checked = this.el.dom;
40708 initValue : Roo.emptyFn,
40711 * Returns the checked state of the checkbox.
40712 * @return {Boolean} True if checked, else false
40714 getValue : function(){
40716 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40718 return this.valueOff;
40723 onClick : function(){
40724 this.setChecked(!this.checked);
40726 //if(this.el.dom.checked != this.checked){
40727 // this.setValue(this.el.dom.checked);
40732 * Sets the checked state of the checkbox.
40733 * On is always based on a string comparison between inputValue and the param.
40734 * @param {Boolean/String} value - the value to set
40735 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40737 setValue : function(v,suppressEvent){
40740 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40741 //if(this.el && this.el.dom){
40742 // this.el.dom.checked = this.checked;
40743 // this.el.dom.defaultChecked = this.checked;
40745 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40746 //this.fireEvent("check", this, this.checked);
40749 setChecked : function(state,suppressEvent)
40751 if (this.inSetChecked) {
40752 this.checked = state;
40758 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40760 this.checked = state;
40761 if(suppressEvent !== true){
40762 this.fireEvent('check', this, state);
40764 this.inSetChecked = true;
40765 this.el.dom.value = state ? this.inputValue : this.valueOff;
40766 this.inSetChecked = false;
40769 // handle setting of hidden value by some other method!!?!?
40770 setFromHidden: function()
40775 //console.log("SET FROM HIDDEN");
40776 //alert('setFrom hidden');
40777 this.setValue(this.el.dom.value);
40780 onDestroy : function()
40783 Roo.get(this.viewEl).remove();
40786 Roo.form.Checkbox.superclass.onDestroy.call(this);
40791 * Ext JS Library 1.1.1
40792 * Copyright(c) 2006-2007, Ext JS, LLC.
40794 * Originally Released Under LGPL - original licence link has changed is not relivant.
40797 * <script type="text/javascript">
40801 * @class Roo.form.Radio
40802 * @extends Roo.form.Checkbox
40803 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40804 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40806 * Creates a new Radio
40807 * @param {Object} config Configuration options
40809 Roo.form.Radio = function(){
40810 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40812 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40813 inputType: 'radio',
40816 * If this radio is part of a group, it will return the selected value
40819 getGroupValue : function(){
40820 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40824 onRender : function(ct, position){
40825 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40827 if(this.inputValue !== undefined){
40828 this.el.dom.value = this.inputValue;
40831 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40832 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40833 //var viewEl = this.wrap.createChild({
40834 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40835 //this.viewEl = viewEl;
40836 //this.wrap.on('click', this.onClick, this);
40838 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40839 //this.el.on('propertychange', this.setFromHidden, this); //ie
40844 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40845 // viewEl.on('click', this.onClick, this);
40848 this.el.dom.checked = 'checked' ;
40854 });//<script type="text/javascript">
40857 * Based Ext JS Library 1.1.1
40858 * Copyright(c) 2006-2007, Ext JS, LLC.
40864 * @class Roo.HtmlEditorCore
40865 * @extends Roo.Component
40866 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40868 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40871 Roo.HtmlEditorCore = function(config){
40874 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40877 * @event initialize
40878 * Fires when the editor is fully initialized (including the iframe)
40879 * @param {Roo.HtmlEditorCore} this
40884 * Fires when the editor is first receives the focus. Any insertion must wait
40885 * until after this event.
40886 * @param {Roo.HtmlEditorCore} this
40890 * @event beforesync
40891 * Fires before the textarea is updated with content from the editor iframe. Return false
40892 * to cancel the sync.
40893 * @param {Roo.HtmlEditorCore} this
40894 * @param {String} html
40898 * @event beforepush
40899 * Fires before the iframe editor is updated with content from the textarea. Return false
40900 * to cancel the push.
40901 * @param {Roo.HtmlEditorCore} this
40902 * @param {String} html
40907 * Fires when the textarea is updated with content from the editor iframe.
40908 * @param {Roo.HtmlEditorCore} this
40909 * @param {String} html
40914 * Fires when the iframe editor is updated with content from the textarea.
40915 * @param {Roo.HtmlEditorCore} this
40916 * @param {String} html
40921 * @event editorevent
40922 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40923 * @param {Roo.HtmlEditorCore} this
40931 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
40935 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
40941 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40946 * @cfg {Number} height (in pixels)
40950 * @cfg {Number} width (in pixels)
40955 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40958 stylesheets: false,
40963 // private properties
40964 validationEvent : false,
40966 initialized : false,
40968 sourceEditMode : false,
40969 onFocus : Roo.emptyFn,
40971 hideMode:'offsets',
40977 * Protected method that will not generally be called directly. It
40978 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40979 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40981 getDocMarkup : function(){
40984 Roo.log(this.stylesheets);
40986 // inherit styels from page...??
40987 if (this.stylesheets === false) {
40989 Roo.get(document.head).select('style').each(function(node) {
40990 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40993 Roo.get(document.head).select('link').each(function(node) {
40994 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40997 } else if (!this.stylesheets.length) {
40999 st = '<style type="text/css">' +
41000 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41003 Roo.each(this.stylesheets, function(s) {
41004 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41009 st += '<style type="text/css">' +
41010 'IMG { cursor: pointer } ' +
41014 return '<html><head>' + st +
41015 //<style type="text/css">' +
41016 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41018 ' </head><body class="roo-htmleditor-body"></body></html>';
41022 onRender : function(ct, position)
41025 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41026 this.el = this.owner.el;
41029 this.el.dom.style.border = '0 none';
41030 this.el.dom.setAttribute('tabIndex', -1);
41031 this.el.addClass('x-hidden');
41035 if(Roo.isIE){ // fix IE 1px bogus margin
41036 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41040 this.frameId = Roo.id();
41044 var iframe = this.owner.wrap.createChild({
41047 name: this.frameId,
41048 frameBorder : 'no',
41049 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41054 this.iframe = iframe.dom;
41056 this.assignDocWin();
41058 this.doc.designMode = 'on';
41061 this.doc.write(this.getDocMarkup());
41065 var task = { // must defer to wait for browser to be ready
41067 //console.log("run task?" + this.doc.readyState);
41068 this.assignDocWin();
41069 if(this.doc.body || this.doc.readyState == 'complete'){
41071 this.doc.designMode="on";
41075 Roo.TaskMgr.stop(task);
41076 this.initEditor.defer(10, this);
41083 Roo.TaskMgr.start(task);
41090 onResize : function(w, h)
41092 //Roo.log('resize: ' +w + ',' + h );
41093 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41097 if(typeof w == 'number'){
41099 this.iframe.style.width = w + 'px';
41101 if(typeof h == 'number'){
41103 this.iframe.style.height = h + 'px';
41105 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41112 * Toggles the editor between standard and source edit mode.
41113 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41115 toggleSourceEdit : function(sourceEditMode){
41117 this.sourceEditMode = sourceEditMode === true;
41119 if(this.sourceEditMode){
41121 this.iframe.className = 'x-hidden'; //FIXME - what's the BS styles for these
41125 this.iframe.className = '';
41128 //this.setSize(this.owner.wrap.getSize());
41129 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41136 * Protected method that will not generally be called directly. If you need/want
41137 * custom HTML cleanup, this is the method you should override.
41138 * @param {String} html The HTML to be cleaned
41139 * return {String} The cleaned HTML
41141 cleanHtml : function(html){
41142 html = String(html);
41143 if(html.length > 5){
41144 if(Roo.isSafari){ // strip safari nonsense
41145 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41148 if(html == ' '){
41155 * HTML Editor -> Textarea
41156 * Protected method that will not generally be called directly. Syncs the contents
41157 * of the editor iframe with the textarea.
41159 syncValue : function(){
41160 if(this.initialized){
41161 var bd = (this.doc.body || this.doc.documentElement);
41162 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41163 var html = bd.innerHTML;
41165 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41166 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41168 html = '<div style="'+m[0]+'">' + html + '</div>';
41171 html = this.cleanHtml(html);
41172 // fix up the special chars.. normaly like back quotes in word...
41173 // however we do not want to do this with chinese..
41174 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41175 var cc = b.charCodeAt();
41177 (cc >= 0x4E00 && cc < 0xA000 ) ||
41178 (cc >= 0x3400 && cc < 0x4E00 ) ||
41179 (cc >= 0xf900 && cc < 0xfb00 )
41185 if(this.owner.fireEvent('beforesync', this, html) !== false){
41186 this.el.dom.value = html;
41187 this.owner.fireEvent('sync', this, html);
41193 * Protected method that will not generally be called directly. Pushes the value of the textarea
41194 * into the iframe editor.
41196 pushValue : function(){
41197 if(this.initialized){
41198 var v = this.el.dom.value;
41204 if(this.owner.fireEvent('beforepush', this, v) !== false){
41205 var d = (this.doc.body || this.doc.documentElement);
41207 this.cleanUpPaste();
41208 this.el.dom.value = d.innerHTML;
41209 this.owner.fireEvent('push', this, v);
41215 deferFocus : function(){
41216 this.focus.defer(10, this);
41220 focus : function(){
41221 if(this.win && !this.sourceEditMode){
41228 assignDocWin: function()
41230 var iframe = this.iframe;
41233 this.doc = iframe.contentWindow.document;
41234 this.win = iframe.contentWindow;
41236 if (!Roo.get(this.frameId)) {
41239 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41240 this.win = Roo.get(this.frameId).dom.contentWindow;
41245 initEditor : function(){
41246 //console.log("INIT EDITOR");
41247 this.assignDocWin();
41251 this.doc.designMode="on";
41253 this.doc.write(this.getDocMarkup());
41256 var dbody = (this.doc.body || this.doc.documentElement);
41257 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41258 // this copies styles from the containing element into thsi one..
41259 // not sure why we need all of this..
41260 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41261 ss['background-attachment'] = 'fixed'; // w3c
41262 dbody.bgProperties = 'fixed'; // ie
41263 Roo.DomHelper.applyStyles(dbody, ss);
41264 Roo.EventManager.on(this.doc, {
41265 //'mousedown': this.onEditorEvent,
41266 'mouseup': this.onEditorEvent,
41267 'dblclick': this.onEditorEvent,
41268 'click': this.onEditorEvent,
41269 'keyup': this.onEditorEvent,
41274 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41276 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41277 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41279 this.initialized = true;
41281 this.owner.fireEvent('initialize', this);
41286 onDestroy : function(){
41292 //for (var i =0; i < this.toolbars.length;i++) {
41293 // // fixme - ask toolbars for heights?
41294 // this.toolbars[i].onDestroy();
41297 //this.wrap.dom.innerHTML = '';
41298 //this.wrap.remove();
41303 onFirstFocus : function(){
41305 this.assignDocWin();
41308 this.activated = true;
41311 if(Roo.isGecko){ // prevent silly gecko errors
41313 var s = this.win.getSelection();
41314 if(!s.focusNode || s.focusNode.nodeType != 3){
41315 var r = s.getRangeAt(0);
41316 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41321 this.execCmd('useCSS', true);
41322 this.execCmd('styleWithCSS', false);
41325 this.owner.fireEvent('activate', this);
41329 adjustFont: function(btn){
41330 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41331 //if(Roo.isSafari){ // safari
41334 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41335 if(Roo.isSafari){ // safari
41336 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41337 v = (v < 10) ? 10 : v;
41338 v = (v > 48) ? 48 : v;
41339 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41344 v = Math.max(1, v+adjust);
41346 this.execCmd('FontSize', v );
41349 onEditorEvent : function(e){
41350 this.owner.fireEvent('editorevent', this, e);
41351 // this.updateToolbar();
41352 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41355 insertTag : function(tg)
41357 // could be a bit smarter... -> wrap the current selected tRoo..
41358 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41360 range = this.createRange(this.getSelection());
41361 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41362 wrappingNode.appendChild(range.extractContents());
41363 range.insertNode(wrappingNode);
41370 this.execCmd("formatblock", tg);
41374 insertText : function(txt)
41378 var range = this.createRange();
41379 range.deleteContents();
41380 //alert(Sender.getAttribute('label'));
41382 range.insertNode(this.doc.createTextNode(txt));
41388 * Executes a Midas editor command on the editor document and performs necessary focus and
41389 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41390 * @param {String} cmd The Midas command
41391 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41393 relayCmd : function(cmd, value){
41395 this.execCmd(cmd, value);
41396 this.owner.fireEvent('editorevent', this);
41397 //this.updateToolbar();
41398 this.owner.deferFocus();
41402 * Executes a Midas editor command directly on the editor document.
41403 * For visual commands, you should use {@link #relayCmd} instead.
41404 * <b>This should only be called after the editor is initialized.</b>
41405 * @param {String} cmd The Midas command
41406 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41408 execCmd : function(cmd, value){
41409 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41416 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41418 * @param {String} text | dom node..
41420 insertAtCursor : function(text)
41425 if(!this.activated){
41431 var r = this.doc.selection.createRange();
41442 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41446 // from jquery ui (MIT licenced)
41448 var win = this.win;
41450 if (win.getSelection && win.getSelection().getRangeAt) {
41451 range = win.getSelection().getRangeAt(0);
41452 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41453 range.insertNode(node);
41454 } else if (win.document.selection && win.document.selection.createRange) {
41455 // no firefox support
41456 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41457 win.document.selection.createRange().pasteHTML(txt);
41459 // no firefox support
41460 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41461 this.execCmd('InsertHTML', txt);
41470 mozKeyPress : function(e){
41472 var c = e.getCharCode(), cmd;
41475 c = String.fromCharCode(c).toLowerCase();
41489 this.cleanUpPaste.defer(100, this);
41497 e.preventDefault();
41505 fixKeys : function(){ // load time branching for fastest keydown performance
41507 return function(e){
41508 var k = e.getKey(), r;
41511 r = this.doc.selection.createRange();
41514 r.pasteHTML('    ');
41521 r = this.doc.selection.createRange();
41523 var target = r.parentElement();
41524 if(!target || target.tagName.toLowerCase() != 'li'){
41526 r.pasteHTML('<br />');
41532 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41533 this.cleanUpPaste.defer(100, this);
41539 }else if(Roo.isOpera){
41540 return function(e){
41541 var k = e.getKey();
41545 this.execCmd('InsertHTML','    ');
41548 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41549 this.cleanUpPaste.defer(100, this);
41554 }else if(Roo.isSafari){
41555 return function(e){
41556 var k = e.getKey();
41560 this.execCmd('InsertText','\t');
41564 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41565 this.cleanUpPaste.defer(100, this);
41573 getAllAncestors: function()
41575 var p = this.getSelectedNode();
41578 a.push(p); // push blank onto stack..
41579 p = this.getParentElement();
41583 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41587 a.push(this.doc.body);
41591 lastSelNode : false,
41594 getSelection : function()
41596 this.assignDocWin();
41597 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41600 getSelectedNode: function()
41602 // this may only work on Gecko!!!
41604 // should we cache this!!!!
41609 var range = this.createRange(this.getSelection()).cloneRange();
41612 var parent = range.parentElement();
41614 var testRange = range.duplicate();
41615 testRange.moveToElementText(parent);
41616 if (testRange.inRange(range)) {
41619 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41622 parent = parent.parentElement;
41627 // is ancestor a text element.
41628 var ac = range.commonAncestorContainer;
41629 if (ac.nodeType == 3) {
41630 ac = ac.parentNode;
41633 var ar = ac.childNodes;
41636 var other_nodes = [];
41637 var has_other_nodes = false;
41638 for (var i=0;i<ar.length;i++) {
41639 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41642 // fullly contained node.
41644 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41649 // probably selected..
41650 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41651 other_nodes.push(ar[i]);
41655 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41660 has_other_nodes = true;
41662 if (!nodes.length && other_nodes.length) {
41663 nodes= other_nodes;
41665 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41671 createRange: function(sel)
41673 // this has strange effects when using with
41674 // top toolbar - not sure if it's a great idea.
41675 //this.editor.contentWindow.focus();
41676 if (typeof sel != "undefined") {
41678 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41680 return this.doc.createRange();
41683 return this.doc.createRange();
41686 getParentElement: function()
41689 this.assignDocWin();
41690 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41692 var range = this.createRange(sel);
41695 var p = range.commonAncestorContainer;
41696 while (p.nodeType == 3) { // text node
41707 * Range intersection.. the hard stuff...
41711 * [ -- selected range --- ]
41715 * if end is before start or hits it. fail.
41716 * if start is after end or hits it fail.
41718 * if either hits (but other is outside. - then it's not
41724 // @see http://www.thismuchiknow.co.uk/?p=64.
41725 rangeIntersectsNode : function(range, node)
41727 var nodeRange = node.ownerDocument.createRange();
41729 nodeRange.selectNode(node);
41731 nodeRange.selectNodeContents(node);
41734 var rangeStartRange = range.cloneRange();
41735 rangeStartRange.collapse(true);
41737 var rangeEndRange = range.cloneRange();
41738 rangeEndRange.collapse(false);
41740 var nodeStartRange = nodeRange.cloneRange();
41741 nodeStartRange.collapse(true);
41743 var nodeEndRange = nodeRange.cloneRange();
41744 nodeEndRange.collapse(false);
41746 return rangeStartRange.compareBoundaryPoints(
41747 Range.START_TO_START, nodeEndRange) == -1 &&
41748 rangeEndRange.compareBoundaryPoints(
41749 Range.START_TO_START, nodeStartRange) == 1;
41753 rangeCompareNode : function(range, node)
41755 var nodeRange = node.ownerDocument.createRange();
41757 nodeRange.selectNode(node);
41759 nodeRange.selectNodeContents(node);
41763 range.collapse(true);
41765 nodeRange.collapse(true);
41767 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41768 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41770 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41772 var nodeIsBefore = ss == 1;
41773 var nodeIsAfter = ee == -1;
41775 if (nodeIsBefore && nodeIsAfter)
41777 if (!nodeIsBefore && nodeIsAfter)
41778 return 1; //right trailed.
41780 if (nodeIsBefore && !nodeIsAfter)
41781 return 2; // left trailed.
41786 // private? - in a new class?
41787 cleanUpPaste : function()
41789 // cleans up the whole document..
41790 Roo.log('cleanuppaste');
41791 this.cleanUpChildren(this.doc.body);
41792 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41793 if (clean != this.doc.body.innerHTML) {
41794 this.doc.body.innerHTML = clean;
41799 cleanWordChars : function(input) {// change the chars to hex code
41800 var he = Roo.HtmlEditorCore;
41802 var output = input;
41803 Roo.each(he.swapCodes, function(sw) {
41804 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41806 output = output.replace(swapper, sw[1]);
41813 cleanUpChildren : function (n)
41815 if (!n.childNodes.length) {
41818 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41819 this.cleanUpChild(n.childNodes[i]);
41826 cleanUpChild : function (node)
41829 //console.log(node);
41830 if (node.nodeName == "#text") {
41831 // clean up silly Windows -- stuff?
41834 if (node.nodeName == "#comment") {
41835 node.parentNode.removeChild(node);
41836 // clean up silly Windows -- stuff?
41840 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1) {
41842 node.parentNode.removeChild(node);
41847 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41849 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41850 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41852 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41853 // remove_keep_children = true;
41856 if (remove_keep_children) {
41857 this.cleanUpChildren(node);
41858 // inserts everything just before this node...
41859 while (node.childNodes.length) {
41860 var cn = node.childNodes[0];
41861 node.removeChild(cn);
41862 node.parentNode.insertBefore(cn, node);
41864 node.parentNode.removeChild(node);
41868 if (!node.attributes || !node.attributes.length) {
41869 this.cleanUpChildren(node);
41873 function cleanAttr(n,v)
41876 if (v.match(/^\./) || v.match(/^\//)) {
41879 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41882 if (v.match(/^#/)) {
41885 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41886 node.removeAttribute(n);
41890 function cleanStyle(n,v)
41892 if (v.match(/expression/)) { //XSS?? should we even bother..
41893 node.removeAttribute(n);
41896 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
41897 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
41900 var parts = v.split(/;/);
41903 Roo.each(parts, function(p) {
41904 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41908 var l = p.split(':').shift().replace(/\s+/g,'');
41909 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41912 if ( cblack.indexOf(l) > -1) {
41913 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41914 //node.removeAttribute(n);
41918 // only allow 'c whitelisted system attributes'
41919 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41920 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41921 //node.removeAttribute(n);
41931 if (clean.length) {
41932 node.setAttribute(n, clean.join(';'));
41934 node.removeAttribute(n);
41940 for (var i = node.attributes.length-1; i > -1 ; i--) {
41941 var a = node.attributes[i];
41944 if (a.name.toLowerCase().substr(0,2)=='on') {
41945 node.removeAttribute(a.name);
41948 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
41949 node.removeAttribute(a.name);
41952 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
41953 cleanAttr(a.name,a.value); // fixme..
41956 if (a.name == 'style') {
41957 cleanStyle(a.name,a.value);
41960 /// clean up MS crap..
41961 // tecnically this should be a list of valid class'es..
41964 if (a.name == 'class') {
41965 if (a.value.match(/^Mso/)) {
41966 node.className = '';
41969 if (a.value.match(/body/)) {
41970 node.className = '';
41981 this.cleanUpChildren(node);
41987 // hide stuff that is not compatible
42001 * @event specialkey
42005 * @cfg {String} fieldClass @hide
42008 * @cfg {String} focusClass @hide
42011 * @cfg {String} autoCreate @hide
42014 * @cfg {String} inputType @hide
42017 * @cfg {String} invalidClass @hide
42020 * @cfg {String} invalidText @hide
42023 * @cfg {String} msgFx @hide
42026 * @cfg {String} validateOnBlur @hide
42030 Roo.HtmlEditorCore.white = [
42031 'area', 'br', 'img', 'input', 'hr', 'wbr',
42033 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42034 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42035 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42036 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42037 'table', 'ul', 'xmp',
42039 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42042 'dir', 'menu', 'ol', 'ul', 'dl',
42048 Roo.HtmlEditorCore.black = [
42049 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42051 'base', 'basefont', 'bgsound', 'blink', 'body',
42052 'frame', 'frameset', 'head', 'html', 'ilayer',
42053 'iframe', 'layer', 'link', 'meta', 'object',
42054 'script', 'style' ,'title', 'xml' // clean later..
42056 Roo.HtmlEditorCore.clean = [
42057 'script', 'style', 'title', 'xml'
42059 Roo.HtmlEditorCore.remove = [
42064 Roo.HtmlEditorCore.ablack = [
42068 Roo.HtmlEditorCore.aclean = [
42069 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42073 Roo.HtmlEditorCore.pwhite= [
42074 'http', 'https', 'mailto'
42077 // white listed style attributes.
42078 Roo.HtmlEditorCore.cwhite= [
42079 // 'text-align', /// default is to allow most things..
42085 // black listed style attributes.
42086 Roo.HtmlEditorCore.cblack= [
42087 // 'font-size' -- this can be set by the project
42091 Roo.HtmlEditorCore.swapCodes =[
42102 //<script type="text/javascript">
42105 * Ext JS Library 1.1.1
42106 * Copyright(c) 2006-2007, Ext JS, LLC.
42112 Roo.form.HtmlEditor = function(config){
42116 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42118 if (!this.toolbars) {
42119 this.toolbars = [];
42121 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42127 * @class Roo.form.HtmlEditor
42128 * @extends Roo.form.Field
42129 * Provides a lightweight HTML Editor component.
42131 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42133 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42134 * supported by this editor.</b><br/><br/>
42135 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42136 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42138 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42140 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42145 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42150 * @cfg {Number} height (in pixels)
42154 * @cfg {Number} width (in pixels)
42159 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42162 stylesheets: false,
42167 // private properties
42168 validationEvent : false,
42170 initialized : false,
42173 onFocus : Roo.emptyFn,
42175 hideMode:'offsets',
42177 defaultAutoCreate : { // modified by initCompnoent..
42179 style:"width:500px;height:300px;",
42180 autocomplete: "off"
42184 initComponent : function(){
42187 * @event initialize
42188 * Fires when the editor is fully initialized (including the iframe)
42189 * @param {HtmlEditor} this
42194 * Fires when the editor is first receives the focus. Any insertion must wait
42195 * until after this event.
42196 * @param {HtmlEditor} this
42200 * @event beforesync
42201 * Fires before the textarea is updated with content from the editor iframe. Return false
42202 * to cancel the sync.
42203 * @param {HtmlEditor} this
42204 * @param {String} html
42208 * @event beforepush
42209 * Fires before the iframe editor is updated with content from the textarea. Return false
42210 * to cancel the push.
42211 * @param {HtmlEditor} this
42212 * @param {String} html
42217 * Fires when the textarea is updated with content from the editor iframe.
42218 * @param {HtmlEditor} this
42219 * @param {String} html
42224 * Fires when the iframe editor is updated with content from the textarea.
42225 * @param {HtmlEditor} this
42226 * @param {String} html
42230 * @event editmodechange
42231 * Fires when the editor switches edit modes
42232 * @param {HtmlEditor} this
42233 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42235 editmodechange: true,
42237 * @event editorevent
42238 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42239 * @param {HtmlEditor} this
42243 * @event firstfocus
42244 * Fires when on first focus - needed by toolbars..
42245 * @param {HtmlEditor} this
42250 * Auto save the htmlEditor value as a file into Events
42251 * @param {HtmlEditor} this
42255 * @event savedpreview
42256 * preview the saved version of htmlEditor
42257 * @param {HtmlEditor} this
42261 this.defaultAutoCreate = {
42263 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42264 autocomplete: "off"
42269 * Protected method that will not generally be called directly. It
42270 * is called when the editor creates its toolbar. Override this method if you need to
42271 * add custom toolbar buttons.
42272 * @param {HtmlEditor} editor
42274 createToolbar : function(editor){
42275 Roo.log("create toolbars");
42276 if (!editor.toolbars || !editor.toolbars.length) {
42277 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42280 for (var i =0 ; i < editor.toolbars.length;i++) {
42281 editor.toolbars[i] = Roo.factory(
42282 typeof(editor.toolbars[i]) == 'string' ?
42283 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42284 Roo.form.HtmlEditor);
42285 editor.toolbars[i].init(editor);
42293 onRender : function(ct, position)
42296 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42298 this.wrap = this.el.wrap({
42299 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42302 this.editorcore.onRender(ct, position);
42304 if (this.resizable) {
42305 this.resizeEl = new Roo.Resizable(this.wrap, {
42309 minHeight : this.height,
42310 height: this.height,
42311 handles : this.resizable,
42314 resize : function(r, w, h) {
42315 _t.onResize(w,h); // -something
42321 this.createToolbar(this);
42325 this.setSize(this.wrap.getSize());
42327 if (this.resizeEl) {
42328 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42329 // should trigger onReize..
42332 // if(this.autosave && this.w){
42333 // this.autoSaveFn = setInterval(this.autosave, 1000);
42338 onResize : function(w, h)
42340 //Roo.log('resize: ' +w + ',' + h );
42341 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42346 if(typeof w == 'number'){
42347 var aw = w - this.wrap.getFrameWidth('lr');
42348 this.el.setWidth(this.adjustWidth('textarea', aw));
42351 if(typeof h == 'number'){
42353 for (var i =0; i < this.toolbars.length;i++) {
42354 // fixme - ask toolbars for heights?
42355 tbh += this.toolbars[i].tb.el.getHeight();
42356 if (this.toolbars[i].footer) {
42357 tbh += this.toolbars[i].footer.el.getHeight();
42364 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42365 ah -= 5; // knock a few pixes off for look..
42366 this.el.setHeight(this.adjustWidth('textarea', ah));
42370 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42371 this.editorcore.onResize(ew,eh);
42376 * Toggles the editor between standard and source edit mode.
42377 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42379 toggleSourceEdit : function(sourceEditMode)
42381 this.editorcore.toggleSourceEdit(sourceEditMode);
42383 if(this.editorcore.sourceEditMode){
42384 Roo.log('editor - showing textarea');
42387 // Roo.log(this.syncValue());
42388 this.editorcore.syncValue();
42389 this.el.removeClass('x-hidden');
42390 this.el.dom.removeAttribute('tabIndex');
42393 Roo.log('editor - hiding textarea');
42395 // Roo.log(this.pushValue());
42396 this.editorcore.pushValue();
42398 this.el.addClass('x-hidden');
42399 this.el.dom.setAttribute('tabIndex', -1);
42400 //this.deferFocus();
42403 this.setSize(this.wrap.getSize());
42404 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42407 // private (for BoxComponent)
42408 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42410 // private (for BoxComponent)
42411 getResizeEl : function(){
42415 // private (for BoxComponent)
42416 getPositionEl : function(){
42421 initEvents : function(){
42422 this.originalValue = this.getValue();
42426 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42429 markInvalid : Roo.emptyFn,
42431 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42434 clearInvalid : Roo.emptyFn,
42436 setValue : function(v){
42437 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42438 this.editorcore.pushValue();
42443 deferFocus : function(){
42444 this.focus.defer(10, this);
42448 focus : function(){
42449 this.editorcore.focus();
42455 onDestroy : function(){
42461 for (var i =0; i < this.toolbars.length;i++) {
42462 // fixme - ask toolbars for heights?
42463 this.toolbars[i].onDestroy();
42466 this.wrap.dom.innerHTML = '';
42467 this.wrap.remove();
42472 onFirstFocus : function(){
42473 //Roo.log("onFirstFocus");
42474 this.editorcore.onFirstFocus();
42475 for (var i =0; i < this.toolbars.length;i++) {
42476 this.toolbars[i].onFirstFocus();
42482 syncValue : function()
42484 this.editorcore.syncValue();
42488 // hide stuff that is not compatible
42502 * @event specialkey
42506 * @cfg {String} fieldClass @hide
42509 * @cfg {String} focusClass @hide
42512 * @cfg {String} autoCreate @hide
42515 * @cfg {String} inputType @hide
42518 * @cfg {String} invalidClass @hide
42521 * @cfg {String} invalidText @hide
42524 * @cfg {String} msgFx @hide
42527 * @cfg {String} validateOnBlur @hide
42531 // <script type="text/javascript">
42534 * Ext JS Library 1.1.1
42535 * Copyright(c) 2006-2007, Ext JS, LLC.
42541 * @class Roo.form.HtmlEditorToolbar1
42546 new Roo.form.HtmlEditor({
42549 new Roo.form.HtmlEditorToolbar1({
42550 disable : { fonts: 1 , format: 1, ..., ... , ...],
42556 * @cfg {Object} disable List of elements to disable..
42557 * @cfg {Array} btns List of additional buttons.
42561 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42564 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42567 Roo.apply(this, config);
42569 // default disabled, based on 'good practice'..
42570 this.disable = this.disable || {};
42571 Roo.applyIf(this.disable, {
42574 specialElements : true
42578 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42579 // dont call parent... till later.
42582 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42589 editorcore : false,
42591 * @cfg {Object} disable List of toolbar elements to disable
42598 * @cfg {String} createLinkText The default text for the create link prompt
42600 createLinkText : 'Please enter the URL for the link:',
42602 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42604 defaultLinkValue : 'http:/'+'/',
42608 * @cfg {Array} fontFamilies An array of available font families
42626 // "á" , ?? a acute?
42631 "°" // , // degrees
42633 // "é" , // e ecute
42634 // "ú" , // u ecute?
42637 specialElements : [
42639 text: "Insert Table",
42642 ihtml : '<table><tr><td>Cell</td></tr></table>'
42646 text: "Insert Image",
42649 ihtml : '<img src="about:blank"/>'
42658 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42659 "input:submit", "input:button", "select", "textarea", "label" ],
42662 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42664 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42672 * @cfg {String} defaultFont default font to use.
42674 defaultFont: 'tahoma',
42676 fontSelect : false,
42679 formatCombo : false,
42681 init : function(editor)
42683 this.editor = editor;
42684 this.editorcore = editor.editorcore ? editor.editorcore : editor;
42685 var editorcore = this.editorcore;
42689 var fid = editorcore.frameId;
42691 function btn(id, toggle, handler){
42692 var xid = fid + '-'+ id ;
42696 cls : 'x-btn-icon x-edit-'+id,
42697 enableToggle:toggle !== false,
42698 scope: _t, // was editor...
42699 handler:handler||_t.relayBtnCmd,
42700 clickEvent:'mousedown',
42701 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42708 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42710 // stop form submits
42711 tb.el.on('click', function(e){
42712 e.preventDefault(); // what does this do?
42715 if(!this.disable.font) { // && !Roo.isSafari){
42716 /* why no safari for fonts
42717 editor.fontSelect = tb.el.createChild({
42720 cls:'x-font-select',
42721 html: this.createFontOptions()
42724 editor.fontSelect.on('change', function(){
42725 var font = editor.fontSelect.dom.value;
42726 editor.relayCmd('fontname', font);
42727 editor.deferFocus();
42731 editor.fontSelect.dom,
42737 if(!this.disable.formats){
42738 this.formatCombo = new Roo.form.ComboBox({
42739 store: new Roo.data.SimpleStore({
42742 data : this.formats // from states.js
42746 //autoCreate : {tag: "div", size: "20"},
42747 displayField:'tag',
42751 triggerAction: 'all',
42752 emptyText:'Add tag',
42753 selectOnFocus:true,
42756 'select': function(c, r, i) {
42757 editorcore.insertTag(r.get('tag'));
42763 tb.addField(this.formatCombo);
42767 if(!this.disable.format){
42774 if(!this.disable.fontSize){
42779 btn('increasefontsize', false, editorcore.adjustFont),
42780 btn('decreasefontsize', false, editorcore.adjustFont)
42785 if(!this.disable.colors){
42788 id:editorcore.frameId +'-forecolor',
42789 cls:'x-btn-icon x-edit-forecolor',
42790 clickEvent:'mousedown',
42791 tooltip: this.buttonTips['forecolor'] || undefined,
42793 menu : new Roo.menu.ColorMenu({
42794 allowReselect: true,
42795 focus: Roo.emptyFn,
42798 selectHandler: function(cp, color){
42799 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
42800 editor.deferFocus();
42803 clickEvent:'mousedown'
42806 id:editorcore.frameId +'backcolor',
42807 cls:'x-btn-icon x-edit-backcolor',
42808 clickEvent:'mousedown',
42809 tooltip: this.buttonTips['backcolor'] || undefined,
42811 menu : new Roo.menu.ColorMenu({
42812 focus: Roo.emptyFn,
42815 allowReselect: true,
42816 selectHandler: function(cp, color){
42818 editorcore.execCmd('useCSS', false);
42819 editorcore.execCmd('hilitecolor', color);
42820 editorcore.execCmd('useCSS', true);
42821 editor.deferFocus();
42823 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
42824 Roo.isSafari || Roo.isIE ? '#'+color : color);
42825 editor.deferFocus();
42829 clickEvent:'mousedown'
42834 // now add all the items...
42837 if(!this.disable.alignments){
42840 btn('justifyleft'),
42841 btn('justifycenter'),
42842 btn('justifyright')
42846 //if(!Roo.isSafari){
42847 if(!this.disable.links){
42850 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
42854 if(!this.disable.lists){
42857 btn('insertorderedlist'),
42858 btn('insertunorderedlist')
42861 if(!this.disable.sourceEdit){
42864 btn('sourceedit', true, function(btn){
42866 this.toggleSourceEdit(btn.pressed);
42873 // special menu.. - needs to be tidied up..
42874 if (!this.disable.special) {
42877 cls: 'x-edit-none',
42883 for (var i =0; i < this.specialChars.length; i++) {
42884 smenu.menu.items.push({
42886 html: this.specialChars[i],
42887 handler: function(a,b) {
42888 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
42889 //editor.insertAtCursor(a.html);
42903 if (!this.disable.cleanStyles) {
42905 cls: 'x-btn-icon x-btn-clear',
42911 for (var i =0; i < this.cleanStyles.length; i++) {
42912 cmenu.menu.items.push({
42913 actiontype : this.cleanStyles[i],
42914 html: 'Remove ' + this.cleanStyles[i],
42915 handler: function(a,b) {
42918 var c = Roo.get(editorcore.doc.body);
42919 c.select('[style]').each(function(s) {
42920 s.dom.style.removeProperty(a.actiontype);
42931 if (!this.disable.specialElements) {
42934 cls: 'x-edit-none',
42939 for (var i =0; i < this.specialElements.length; i++) {
42940 semenu.menu.items.push(
42942 handler: function(a,b) {
42943 editor.insertAtCursor(this.ihtml);
42945 }, this.specialElements[i])
42957 for(var i =0; i< this.btns.length;i++) {
42958 var b = Roo.factory(this.btns[i],Roo.form);
42959 b.cls = 'x-edit-none';
42960 b.scope = editorcore;
42968 // disable everything...
42970 this.tb.items.each(function(item){
42971 if(item.id != editorcore.frameId+ '-sourceedit'){
42975 this.rendered = true;
42977 // the all the btns;
42978 editor.on('editorevent', this.updateToolbar, this);
42979 // other toolbars need to implement this..
42980 //editor.on('editmodechange', this.updateToolbar, this);
42984 relayBtnCmd : function(btn) {
42985 this.editorcore.relayCmd(btn.cmd);
42987 // private used internally
42988 createLink : function(){
42989 Roo.log("create link?");
42990 var url = prompt(this.createLinkText, this.defaultLinkValue);
42991 if(url && url != 'http:/'+'/'){
42992 this.editorcore.relayCmd('createlink', url);
42998 * Protected method that will not generally be called directly. It triggers
42999 * a toolbar update by reading the markup state of the current selection in the editor.
43001 updateToolbar: function(){
43003 if(!this.editorcore.activated){
43004 this.editor.onFirstFocus();
43008 var btns = this.tb.items.map,
43009 doc = this.editorcore.doc,
43010 frameId = this.editorcore.frameId;
43012 if(!this.disable.font && !Roo.isSafari){
43014 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43015 if(name != this.fontSelect.dom.value){
43016 this.fontSelect.dom.value = name;
43020 if(!this.disable.format){
43021 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43022 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43023 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43025 if(!this.disable.alignments){
43026 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43027 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43028 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43030 if(!Roo.isSafari && !this.disable.lists){
43031 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43032 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43035 var ans = this.editorcore.getAllAncestors();
43036 if (this.formatCombo) {
43039 var store = this.formatCombo.store;
43040 this.formatCombo.setValue("");
43041 for (var i =0; i < ans.length;i++) {
43042 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43044 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43052 // hides menus... - so this cant be on a menu...
43053 Roo.menu.MenuMgr.hideAll();
43055 //this.editorsyncValue();
43059 createFontOptions : function(){
43060 var buf = [], fs = this.fontFamilies, ff, lc;
43064 for(var i = 0, len = fs.length; i< len; i++){
43066 lc = ff.toLowerCase();
43068 '<option value="',lc,'" style="font-family:',ff,';"',
43069 (this.defaultFont == lc ? ' selected="true">' : '>'),
43074 return buf.join('');
43077 toggleSourceEdit : function(sourceEditMode){
43079 Roo.log("toolbar toogle");
43080 if(sourceEditMode === undefined){
43081 sourceEditMode = !this.sourceEditMode;
43083 this.sourceEditMode = sourceEditMode === true;
43084 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43085 // just toggle the button?
43086 if(btn.pressed !== this.sourceEditMode){
43087 btn.toggle(this.sourceEditMode);
43091 if(sourceEditMode){
43092 Roo.log("disabling buttons");
43093 this.tb.items.each(function(item){
43094 if(item.cmd != 'sourceedit'){
43100 Roo.log("enabling buttons");
43101 if(this.editorcore.initialized){
43102 this.tb.items.each(function(item){
43108 Roo.log("calling toggole on editor");
43109 // tell the editor that it's been pressed..
43110 this.editor.toggleSourceEdit(sourceEditMode);
43114 * Object collection of toolbar tooltips for the buttons in the editor. The key
43115 * is the command id associated with that button and the value is a valid QuickTips object.
43120 title: 'Bold (Ctrl+B)',
43121 text: 'Make the selected text bold.',
43122 cls: 'x-html-editor-tip'
43125 title: 'Italic (Ctrl+I)',
43126 text: 'Make the selected text italic.',
43127 cls: 'x-html-editor-tip'
43135 title: 'Bold (Ctrl+B)',
43136 text: 'Make the selected text bold.',
43137 cls: 'x-html-editor-tip'
43140 title: 'Italic (Ctrl+I)',
43141 text: 'Make the selected text italic.',
43142 cls: 'x-html-editor-tip'
43145 title: 'Underline (Ctrl+U)',
43146 text: 'Underline the selected text.',
43147 cls: 'x-html-editor-tip'
43149 increasefontsize : {
43150 title: 'Grow Text',
43151 text: 'Increase the font size.',
43152 cls: 'x-html-editor-tip'
43154 decreasefontsize : {
43155 title: 'Shrink Text',
43156 text: 'Decrease the font size.',
43157 cls: 'x-html-editor-tip'
43160 title: 'Text Highlight Color',
43161 text: 'Change the background color of the selected text.',
43162 cls: 'x-html-editor-tip'
43165 title: 'Font Color',
43166 text: 'Change the color of the selected text.',
43167 cls: 'x-html-editor-tip'
43170 title: 'Align Text Left',
43171 text: 'Align text to the left.',
43172 cls: 'x-html-editor-tip'
43175 title: 'Center Text',
43176 text: 'Center text in the editor.',
43177 cls: 'x-html-editor-tip'
43180 title: 'Align Text Right',
43181 text: 'Align text to the right.',
43182 cls: 'x-html-editor-tip'
43184 insertunorderedlist : {
43185 title: 'Bullet List',
43186 text: 'Start a bulleted list.',
43187 cls: 'x-html-editor-tip'
43189 insertorderedlist : {
43190 title: 'Numbered List',
43191 text: 'Start a numbered list.',
43192 cls: 'x-html-editor-tip'
43195 title: 'Hyperlink',
43196 text: 'Make the selected text a hyperlink.',
43197 cls: 'x-html-editor-tip'
43200 title: 'Source Edit',
43201 text: 'Switch to source editing mode.',
43202 cls: 'x-html-editor-tip'
43206 onDestroy : function(){
43209 this.tb.items.each(function(item){
43211 item.menu.removeAll();
43213 item.menu.el.destroy();
43221 onFirstFocus: function() {
43222 this.tb.items.each(function(item){
43231 // <script type="text/javascript">
43234 * Ext JS Library 1.1.1
43235 * Copyright(c) 2006-2007, Ext JS, LLC.
43242 * @class Roo.form.HtmlEditor.ToolbarContext
43247 new Roo.form.HtmlEditor({
43250 { xtype: 'ToolbarStandard', styles : {} }
43251 { xtype: 'ToolbarContext', disable : {} }
43257 * @config : {Object} disable List of elements to disable.. (not done yet.)
43258 * @config : {Object} styles Map of styles available.
43262 Roo.form.HtmlEditor.ToolbarContext = function(config)
43265 Roo.apply(this, config);
43266 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43267 // dont call parent... till later.
43268 this.styles = this.styles || {};
43273 Roo.form.HtmlEditor.ToolbarContext.types = {
43285 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43351 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43356 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43366 style : 'fontFamily',
43367 displayField: 'display',
43368 optname : 'font-family',
43417 // should we really allow this??
43418 // should this just be
43429 style : 'fontFamily',
43430 displayField: 'display',
43431 optname : 'font-family',
43438 style : 'fontFamily',
43439 displayField: 'display',
43440 optname : 'font-family',
43447 style : 'fontFamily',
43448 displayField: 'display',
43449 optname : 'font-family',
43460 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43461 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43463 Roo.form.HtmlEditor.ToolbarContext.options = {
43465 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43466 [ 'Courier New', 'Courier New'],
43467 [ 'Tahoma', 'Tahoma'],
43468 [ 'Times New Roman,serif', 'Times'],
43469 [ 'Verdana','Verdana' ]
43473 // fixme - these need to be configurable..
43476 Roo.form.HtmlEditor.ToolbarContext.types
43479 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43486 editorcore : false,
43488 * @cfg {Object} disable List of toolbar elements to disable
43493 * @cfg {Object} styles List of styles
43494 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43496 * These must be defined in the page, so they get rendered correctly..
43507 init : function(editor)
43509 this.editor = editor;
43510 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43511 var editorcore = this.editorcore;
43513 var fid = editorcore.frameId;
43515 function btn(id, toggle, handler){
43516 var xid = fid + '-'+ id ;
43520 cls : 'x-btn-icon x-edit-'+id,
43521 enableToggle:toggle !== false,
43522 scope: editorcore, // was editor...
43523 handler:handler||editorcore.relayBtnCmd,
43524 clickEvent:'mousedown',
43525 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43529 // create a new element.
43530 var wdiv = editor.wrap.createChild({
43532 }, editor.wrap.dom.firstChild.nextSibling, true);
43534 // can we do this more than once??
43536 // stop form submits
43539 // disable everything...
43540 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43541 this.toolbars = {};
43543 for (var i in ty) {
43545 this.toolbars[i] = this.buildToolbar(ty[i],i);
43547 this.tb = this.toolbars.BODY;
43549 this.buildFooter();
43550 this.footer.show();
43551 editor.on('hide', function( ) { this.footer.hide() }, this);
43552 editor.on('show', function( ) { this.footer.show() }, this);
43555 this.rendered = true;
43557 // the all the btns;
43558 editor.on('editorevent', this.updateToolbar, this);
43559 // other toolbars need to implement this..
43560 //editor.on('editmodechange', this.updateToolbar, this);
43566 * Protected method that will not generally be called directly. It triggers
43567 * a toolbar update by reading the markup state of the current selection in the editor.
43569 updateToolbar: function(editor,ev,sel){
43572 // capture mouse up - this is handy for selecting images..
43573 // perhaps should go somewhere else...
43574 if(!this.editorcore.activated){
43575 this.editor.onFirstFocus();
43579 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43580 // selectNode - might want to handle IE?
43582 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43583 ev.target && ev.target.tagName == 'IMG') {
43584 // they have click on an image...
43585 // let's see if we can change the selection...
43588 var nodeRange = sel.ownerDocument.createRange();
43590 nodeRange.selectNode(sel);
43592 nodeRange.selectNodeContents(sel);
43594 //nodeRange.collapse(true);
43595 var s = this.editorcore.win.getSelection();
43596 s.removeAllRanges();
43597 s.addRange(nodeRange);
43601 var updateFooter = sel ? false : true;
43604 var ans = this.editorcore.getAllAncestors();
43607 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43610 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43611 sel = sel ? sel : this.editorcore.doc.body;
43612 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43615 // pick a menu that exists..
43616 var tn = sel.tagName.toUpperCase();
43617 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43619 tn = sel.tagName.toUpperCase();
43621 var lastSel = this.tb.selectedNode
43623 this.tb.selectedNode = sel;
43625 // if current menu does not match..
43626 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43629 ///console.log("show: " + tn);
43630 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43633 this.tb.items.first().el.innerHTML = tn + ': ';
43636 // update attributes
43637 if (this.tb.fields) {
43638 this.tb.fields.each(function(e) {
43640 e.setValue(sel.style[e.stylename]);
43643 e.setValue(sel.getAttribute(e.attrname));
43647 var hasStyles = false;
43648 for(var i in this.styles) {
43655 var st = this.tb.fields.item(0);
43657 st.store.removeAll();
43660 var cn = sel.className.split(/\s+/);
43663 if (this.styles['*']) {
43665 Roo.each(this.styles['*'], function(v) {
43666 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43669 if (this.styles[tn]) {
43670 Roo.each(this.styles[tn], function(v) {
43671 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43675 st.store.loadData(avs);
43679 // flag our selected Node.
43680 this.tb.selectedNode = sel;
43683 Roo.menu.MenuMgr.hideAll();
43687 if (!updateFooter) {
43688 //this.footDisp.dom.innerHTML = '';
43691 // update the footer
43695 this.footerEls = ans.reverse();
43696 Roo.each(this.footerEls, function(a,i) {
43697 if (!a) { return; }
43698 html += html.length ? ' > ' : '';
43700 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43705 var sz = this.footDisp.up('td').getSize();
43706 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43707 this.footDisp.dom.style.marginLeft = '5px';
43709 this.footDisp.dom.style.overflow = 'hidden';
43711 this.footDisp.dom.innerHTML = html;
43713 //this.editorsyncValue();
43720 onDestroy : function(){
43723 this.tb.items.each(function(item){
43725 item.menu.removeAll();
43727 item.menu.el.destroy();
43735 onFirstFocus: function() {
43736 // need to do this for all the toolbars..
43737 this.tb.items.each(function(item){
43741 buildToolbar: function(tlist, nm)
43743 var editor = this.editor;
43744 var editorcore = this.editorcore;
43745 // create a new element.
43746 var wdiv = editor.wrap.createChild({
43748 }, editor.wrap.dom.firstChild.nextSibling, true);
43751 var tb = new Roo.Toolbar(wdiv);
43754 tb.add(nm+ ": ");
43757 for(var i in this.styles) {
43762 if (styles && styles.length) {
43764 // this needs a multi-select checkbox...
43765 tb.addField( new Roo.form.ComboBox({
43766 store: new Roo.data.SimpleStore({
43768 fields: ['val', 'selected'],
43771 name : '-roo-edit-className',
43772 attrname : 'className',
43773 displayField: 'val',
43777 triggerAction: 'all',
43778 emptyText:'Select Style',
43779 selectOnFocus:true,
43782 'select': function(c, r, i) {
43783 // initial support only for on class per el..
43784 tb.selectedNode.className = r ? r.get('val') : '';
43785 editorcore.syncValue();
43792 var tbc = Roo.form.HtmlEditor.ToolbarContext;
43793 var tbops = tbc.options;
43795 for (var i in tlist) {
43797 var item = tlist[i];
43798 tb.add(item.title + ": ");
43801 //optname == used so you can configure the options available..
43802 var opts = item.opts ? item.opts : false;
43803 if (item.optname) {
43804 opts = tbops[item.optname];
43809 // opts == pulldown..
43810 tb.addField( new Roo.form.ComboBox({
43811 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
43813 fields: ['val', 'display'],
43816 name : '-roo-edit-' + i,
43818 stylename : item.style ? item.style : false,
43819 displayField: item.displayField ? item.displayField : 'val',
43820 valueField : 'val',
43822 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
43824 triggerAction: 'all',
43825 emptyText:'Select',
43826 selectOnFocus:true,
43827 width: item.width ? item.width : 130,
43829 'select': function(c, r, i) {
43831 tb.selectedNode.style[c.stylename] = r.get('val');
43834 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
43843 tb.addField( new Roo.form.TextField({
43846 //allowBlank:false,
43851 tb.addField( new Roo.form.TextField({
43852 name: '-roo-edit-' + i,
43859 'change' : function(f, nv, ov) {
43860 tb.selectedNode.setAttribute(f.attrname, nv);
43869 text: 'Remove Tag',
43872 click : function ()
43875 // undo does not work.
43877 var sn = tb.selectedNode;
43879 var pn = sn.parentNode;
43881 var stn = sn.childNodes[0];
43882 var en = sn.childNodes[sn.childNodes.length - 1 ];
43883 while (sn.childNodes.length) {
43884 var node = sn.childNodes[0];
43885 sn.removeChild(node);
43887 pn.insertBefore(node, sn);
43890 pn.removeChild(sn);
43891 var range = editorcore.createRange();
43893 range.setStart(stn,0);
43894 range.setEnd(en,0); //????
43895 //range.selectNode(sel);
43898 var selection = editorcore.getSelection();
43899 selection.removeAllRanges();
43900 selection.addRange(range);
43904 //_this.updateToolbar(null, null, pn);
43905 _this.updateToolbar(null, null, null);
43906 _this.footDisp.dom.innerHTML = '';
43916 tb.el.on('click', function(e){
43917 e.preventDefault(); // what does this do?
43919 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
43922 // dont need to disable them... as they will get hidden
43927 buildFooter : function()
43930 var fel = this.editor.wrap.createChild();
43931 this.footer = new Roo.Toolbar(fel);
43932 // toolbar has scrolly on left / right?
43933 var footDisp= new Roo.Toolbar.Fill();
43939 handler : function() {
43940 _t.footDisp.scrollTo('left',0,true)
43944 this.footer.add( footDisp );
43949 handler : function() {
43951 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
43955 var fel = Roo.get(footDisp.el);
43956 fel.addClass('x-editor-context');
43957 this.footDispWrap = fel;
43958 this.footDispWrap.overflow = 'hidden';
43960 this.footDisp = fel.createChild();
43961 this.footDispWrap.on('click', this.onContextClick, this)
43965 onContextClick : function (ev,dom)
43967 ev.preventDefault();
43968 var cn = dom.className;
43970 if (!cn.match(/x-ed-loc-/)) {
43973 var n = cn.split('-').pop();
43974 var ans = this.footerEls;
43978 var range = this.editorcore.createRange();
43980 range.selectNodeContents(sel);
43981 //range.selectNode(sel);
43984 var selection = this.editorcore.getSelection();
43985 selection.removeAllRanges();
43986 selection.addRange(range);
43990 this.updateToolbar(null, null, sel);
44007 * Ext JS Library 1.1.1
44008 * Copyright(c) 2006-2007, Ext JS, LLC.
44010 * Originally Released Under LGPL - original licence link has changed is not relivant.
44013 * <script type="text/javascript">
44017 * @class Roo.form.BasicForm
44018 * @extends Roo.util.Observable
44019 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44021 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44022 * @param {Object} config Configuration options
44024 Roo.form.BasicForm = function(el, config){
44025 this.allItems = [];
44026 this.childForms = [];
44027 Roo.apply(this, config);
44029 * The Roo.form.Field items in this form.
44030 * @type MixedCollection
44034 this.items = new Roo.util.MixedCollection(false, function(o){
44035 return o.id || (o.id = Roo.id());
44039 * @event beforeaction
44040 * Fires before any action is performed. Return false to cancel the action.
44041 * @param {Form} this
44042 * @param {Action} action The action to be performed
44044 beforeaction: true,
44046 * @event actionfailed
44047 * Fires when an action fails.
44048 * @param {Form} this
44049 * @param {Action} action The action that failed
44051 actionfailed : true,
44053 * @event actioncomplete
44054 * Fires when an action is completed.
44055 * @param {Form} this
44056 * @param {Action} action The action that completed
44058 actioncomplete : true
44063 Roo.form.BasicForm.superclass.constructor.call(this);
44066 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44068 * @cfg {String} method
44069 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44072 * @cfg {DataReader} reader
44073 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44074 * This is optional as there is built-in support for processing JSON.
44077 * @cfg {DataReader} errorReader
44078 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44079 * This is completely optional as there is built-in support for processing JSON.
44082 * @cfg {String} url
44083 * The URL to use for form actions if one isn't supplied in the action options.
44086 * @cfg {Boolean} fileUpload
44087 * Set to true if this form is a file upload.
44091 * @cfg {Object} baseParams
44092 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44097 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44102 activeAction : null,
44105 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44106 * or setValues() data instead of when the form was first created.
44108 trackResetOnLoad : false,
44112 * childForms - used for multi-tab forms
44115 childForms : false,
44118 * allItems - full list of fields.
44124 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44125 * element by passing it or its id or mask the form itself by passing in true.
44128 waitMsgTarget : false,
44131 initEl : function(el){
44132 this.el = Roo.get(el);
44133 this.id = this.el.id || Roo.id();
44134 this.el.on('submit', this.onSubmit, this);
44135 this.el.addClass('x-form');
44139 onSubmit : function(e){
44144 * Returns true if client-side validation on the form is successful.
44147 isValid : function(){
44149 this.items.each(function(f){
44158 * Returns true if any fields in this form have changed since their original load.
44161 isDirty : function(){
44163 this.items.each(function(f){
44173 * Performs a predefined action (submit or load) or custom actions you define on this form.
44174 * @param {String} actionName The name of the action type
44175 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44176 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44177 * accept other config options):
44179 Property Type Description
44180 ---------------- --------------- ----------------------------------------------------------------------------------
44181 url String The url for the action (defaults to the form's url)
44182 method String The form method to use (defaults to the form's method, or POST if not defined)
44183 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44184 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44185 validate the form on the client (defaults to false)
44187 * @return {BasicForm} this
44189 doAction : function(action, options){
44190 if(typeof action == 'string'){
44191 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44193 if(this.fireEvent('beforeaction', this, action) !== false){
44194 this.beforeAction(action);
44195 action.run.defer(100, action);
44201 * Shortcut to do a submit action.
44202 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44203 * @return {BasicForm} this
44205 submit : function(options){
44206 this.doAction('submit', options);
44211 * Shortcut to do a load action.
44212 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44213 * @return {BasicForm} this
44215 load : function(options){
44216 this.doAction('load', options);
44221 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44222 * @param {Record} record The record to edit
44223 * @return {BasicForm} this
44225 updateRecord : function(record){
44226 record.beginEdit();
44227 var fs = record.fields;
44228 fs.each(function(f){
44229 var field = this.findField(f.name);
44231 record.set(f.name, field.getValue());
44239 * Loads an Roo.data.Record into this form.
44240 * @param {Record} record The record to load
44241 * @return {BasicForm} this
44243 loadRecord : function(record){
44244 this.setValues(record.data);
44249 beforeAction : function(action){
44250 var o = action.options;
44253 if(this.waitMsgTarget === true){
44254 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44255 }else if(this.waitMsgTarget){
44256 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44257 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44259 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44265 afterAction : function(action, success){
44266 this.activeAction = null;
44267 var o = action.options;
44269 if(this.waitMsgTarget === true){
44271 }else if(this.waitMsgTarget){
44272 this.waitMsgTarget.unmask();
44274 Roo.MessageBox.updateProgress(1);
44275 Roo.MessageBox.hide();
44282 Roo.callback(o.success, o.scope, [this, action]);
44283 this.fireEvent('actioncomplete', this, action);
44287 // failure condition..
44288 // we have a scenario where updates need confirming.
44289 // eg. if a locking scenario exists..
44290 // we look for { errors : { needs_confirm : true }} in the response.
44292 (typeof(action.result) != 'undefined') &&
44293 (typeof(action.result.errors) != 'undefined') &&
44294 (typeof(action.result.errors.needs_confirm) != 'undefined')
44297 Roo.MessageBox.confirm(
44298 "Change requires confirmation",
44299 action.result.errorMsg,
44304 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44314 Roo.callback(o.failure, o.scope, [this, action]);
44315 // show an error message if no failed handler is set..
44316 if (!this.hasListener('actionfailed')) {
44317 Roo.MessageBox.alert("Error",
44318 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44319 action.result.errorMsg :
44320 "Saving Failed, please check your entries or try again"
44324 this.fireEvent('actionfailed', this, action);
44330 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44331 * @param {String} id The value to search for
44334 findField : function(id){
44335 var field = this.items.get(id);
44337 this.items.each(function(f){
44338 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44344 return field || null;
44348 * Add a secondary form to this one,
44349 * Used to provide tabbed forms. One form is primary, with hidden values
44350 * which mirror the elements from the other forms.
44352 * @param {Roo.form.Form} form to add.
44355 addForm : function(form)
44358 if (this.childForms.indexOf(form) > -1) {
44362 this.childForms.push(form);
44364 Roo.each(form.allItems, function (fe) {
44366 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44367 if (this.findField(n)) { // already added..
44370 var add = new Roo.form.Hidden({
44373 add.render(this.el);
44380 * Mark fields in this form invalid in bulk.
44381 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44382 * @return {BasicForm} this
44384 markInvalid : function(errors){
44385 if(errors instanceof Array){
44386 for(var i = 0, len = errors.length; i < len; i++){
44387 var fieldError = errors[i];
44388 var f = this.findField(fieldError.id);
44390 f.markInvalid(fieldError.msg);
44396 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44397 field.markInvalid(errors[id]);
44401 Roo.each(this.childForms || [], function (f) {
44402 f.markInvalid(errors);
44409 * Set values for fields in this form in bulk.
44410 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44411 * @return {BasicForm} this
44413 setValues : function(values){
44414 if(values instanceof Array){ // array of objects
44415 for(var i = 0, len = values.length; i < len; i++){
44417 var f = this.findField(v.id);
44419 f.setValue(v.value);
44420 if(this.trackResetOnLoad){
44421 f.originalValue = f.getValue();
44425 }else{ // object hash
44428 if(typeof values[id] != 'function' && (field = this.findField(id))){
44430 if (field.setFromData &&
44431 field.valueField &&
44432 field.displayField &&
44433 // combos' with local stores can
44434 // be queried via setValue()
44435 // to set their value..
44436 (field.store && !field.store.isLocal)
44440 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44441 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44442 field.setFromData(sd);
44445 field.setValue(values[id]);
44449 if(this.trackResetOnLoad){
44450 field.originalValue = field.getValue();
44456 Roo.each(this.childForms || [], function (f) {
44457 f.setValues(values);
44464 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44465 * they are returned as an array.
44466 * @param {Boolean} asString
44469 getValues : function(asString){
44470 if (this.childForms) {
44471 // copy values from the child forms
44472 Roo.each(this.childForms, function (f) {
44473 this.setValues(f.getValues());
44479 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44480 if(asString === true){
44483 return Roo.urlDecode(fs);
44487 * Returns the fields in this form as an object with key/value pairs.
44488 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44491 getFieldValues : function(with_hidden)
44493 if (this.childForms) {
44494 // copy values from the child forms
44495 // should this call getFieldValues - probably not as we do not currently copy
44496 // hidden fields when we generate..
44497 Roo.each(this.childForms, function (f) {
44498 this.setValues(f.getValues());
44503 this.items.each(function(f){
44504 if (!f.getName()) {
44507 var v = f.getValue();
44508 if (f.inputType =='radio') {
44509 if (typeof(ret[f.getName()]) == 'undefined') {
44510 ret[f.getName()] = ''; // empty..
44513 if (!f.el.dom.checked) {
44517 v = f.el.dom.value;
44521 // not sure if this supported any more..
44522 if ((typeof(v) == 'object') && f.getRawValue) {
44523 v = f.getRawValue() ; // dates..
44525 // combo boxes where name != hiddenName...
44526 if (f.name != f.getName()) {
44527 ret[f.name] = f.getRawValue();
44529 ret[f.getName()] = v;
44536 * Clears all invalid messages in this form.
44537 * @return {BasicForm} this
44539 clearInvalid : function(){
44540 this.items.each(function(f){
44544 Roo.each(this.childForms || [], function (f) {
44553 * Resets this form.
44554 * @return {BasicForm} this
44556 reset : function(){
44557 this.items.each(function(f){
44561 Roo.each(this.childForms || [], function (f) {
44570 * Add Roo.form components to this form.
44571 * @param {Field} field1
44572 * @param {Field} field2 (optional)
44573 * @param {Field} etc (optional)
44574 * @return {BasicForm} this
44577 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44583 * Removes a field from the items collection (does NOT remove its markup).
44584 * @param {Field} field
44585 * @return {BasicForm} this
44587 remove : function(field){
44588 this.items.remove(field);
44593 * Looks at the fields in this form, checks them for an id attribute,
44594 * and calls applyTo on the existing dom element with that id.
44595 * @return {BasicForm} this
44597 render : function(){
44598 this.items.each(function(f){
44599 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44607 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44608 * @param {Object} values
44609 * @return {BasicForm} this
44611 applyToFields : function(o){
44612 this.items.each(function(f){
44619 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44620 * @param {Object} values
44621 * @return {BasicForm} this
44623 applyIfToFields : function(o){
44624 this.items.each(function(f){
44632 Roo.BasicForm = Roo.form.BasicForm;/*
44634 * Ext JS Library 1.1.1
44635 * Copyright(c) 2006-2007, Ext JS, LLC.
44637 * Originally Released Under LGPL - original licence link has changed is not relivant.
44640 * <script type="text/javascript">
44644 * @class Roo.form.Form
44645 * @extends Roo.form.BasicForm
44646 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44648 * @param {Object} config Configuration options
44650 Roo.form.Form = function(config){
44652 if (config.items) {
44653 xitems = config.items;
44654 delete config.items;
44658 Roo.form.Form.superclass.constructor.call(this, null, config);
44659 this.url = this.url || this.action;
44661 this.root = new Roo.form.Layout(Roo.applyIf({
44665 this.active = this.root;
44667 * Array of all the buttons that have been added to this form via {@link addButton}
44671 this.allItems = [];
44674 * @event clientvalidation
44675 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44676 * @param {Form} this
44677 * @param {Boolean} valid true if the form has passed client-side validation
44679 clientvalidation: true,
44682 * Fires when the form is rendered
44683 * @param {Roo.form.Form} form
44688 if (this.progressUrl) {
44689 // push a hidden field onto the list of fields..
44693 name : 'UPLOAD_IDENTIFIER'
44698 Roo.each(xitems, this.addxtype, this);
44704 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44706 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44709 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44712 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44714 buttonAlign:'center',
44717 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44722 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44723 * This property cascades to child containers if not set.
44728 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
44729 * fires a looping event with that state. This is required to bind buttons to the valid
44730 * state using the config value formBind:true on the button.
44732 monitorValid : false,
44735 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
44740 * @cfg {String} progressUrl - Url to return progress data
44743 progressUrl : false,
44746 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
44747 * fields are added and the column is closed. If no fields are passed the column remains open
44748 * until end() is called.
44749 * @param {Object} config The config to pass to the column
44750 * @param {Field} field1 (optional)
44751 * @param {Field} field2 (optional)
44752 * @param {Field} etc (optional)
44753 * @return Column The column container object
44755 column : function(c){
44756 var col = new Roo.form.Column(c);
44758 if(arguments.length > 1){ // duplicate code required because of Opera
44759 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44766 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
44767 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
44768 * until end() is called.
44769 * @param {Object} config The config to pass to the fieldset
44770 * @param {Field} field1 (optional)
44771 * @param {Field} field2 (optional)
44772 * @param {Field} etc (optional)
44773 * @return FieldSet The fieldset container object
44775 fieldset : function(c){
44776 var fs = new Roo.form.FieldSet(c);
44778 if(arguments.length > 1){ // duplicate code required because of Opera
44779 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44786 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
44787 * fields are added and the container is closed. If no fields are passed the container remains open
44788 * until end() is called.
44789 * @param {Object} config The config to pass to the Layout
44790 * @param {Field} field1 (optional)
44791 * @param {Field} field2 (optional)
44792 * @param {Field} etc (optional)
44793 * @return Layout The container object
44795 container : function(c){
44796 var l = new Roo.form.Layout(c);
44798 if(arguments.length > 1){ // duplicate code required because of Opera
44799 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44806 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
44807 * @param {Object} container A Roo.form.Layout or subclass of Layout
44808 * @return {Form} this
44810 start : function(c){
44811 // cascade label info
44812 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
44813 this.active.stack.push(c);
44814 c.ownerCt = this.active;
44820 * Closes the current open container
44821 * @return {Form} this
44824 if(this.active == this.root){
44827 this.active = this.active.ownerCt;
44832 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
44833 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
44834 * as the label of the field.
44835 * @param {Field} field1
44836 * @param {Field} field2 (optional)
44837 * @param {Field} etc. (optional)
44838 * @return {Form} this
44841 this.active.stack.push.apply(this.active.stack, arguments);
44842 this.allItems.push.apply(this.allItems,arguments);
44844 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
44845 if(a[i].isFormField){
44850 Roo.form.Form.superclass.add.apply(this, r);
44860 * Find any element that has been added to a form, using it's ID or name
44861 * This can include framesets, columns etc. along with regular fields..
44862 * @param {String} id - id or name to find.
44864 * @return {Element} e - or false if nothing found.
44866 findbyId : function(id)
44872 Roo.each(this.allItems, function(f){
44873 if (f.id == id || f.name == id ){
44884 * Render this form into the passed container. This should only be called once!
44885 * @param {String/HTMLElement/Element} container The element this component should be rendered into
44886 * @return {Form} this
44888 render : function(ct)
44894 var o = this.autoCreate || {
44896 method : this.method || 'POST',
44897 id : this.id || Roo.id()
44899 this.initEl(ct.createChild(o));
44901 this.root.render(this.el);
44905 this.items.each(function(f){
44906 f.render('x-form-el-'+f.id);
44909 if(this.buttons.length > 0){
44910 // tables are required to maintain order and for correct IE layout
44911 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
44912 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
44913 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
44915 var tr = tb.getElementsByTagName('tr')[0];
44916 for(var i = 0, len = this.buttons.length; i < len; i++) {
44917 var b = this.buttons[i];
44918 var td = document.createElement('td');
44919 td.className = 'x-form-btn-td';
44920 b.render(tr.appendChild(td));
44923 if(this.monitorValid){ // initialize after render
44924 this.startMonitoring();
44926 this.fireEvent('rendered', this);
44931 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
44932 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
44933 * object or a valid Roo.DomHelper element config
44934 * @param {Function} handler The function called when the button is clicked
44935 * @param {Object} scope (optional) The scope of the handler function
44936 * @return {Roo.Button}
44938 addButton : function(config, handler, scope){
44942 minWidth: this.minButtonWidth,
44945 if(typeof config == "string"){
44948 Roo.apply(bc, config);
44950 var btn = new Roo.Button(null, bc);
44951 this.buttons.push(btn);
44956 * Adds a series of form elements (using the xtype property as the factory method.
44957 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
44958 * @param {Object} config
44961 addxtype : function()
44963 var ar = Array.prototype.slice.call(arguments, 0);
44965 for(var i = 0; i < ar.length; i++) {
44967 continue; // skip -- if this happends something invalid got sent, we
44968 // should ignore it, as basically that interface element will not show up
44969 // and that should be pretty obvious!!
44972 if (Roo.form[ar[i].xtype]) {
44974 var fe = Roo.factory(ar[i], Roo.form);
44980 fe.store.form = this;
44985 this.allItems.push(fe);
44986 if (fe.items && fe.addxtype) {
44987 fe.addxtype.apply(fe, fe.items);
44997 // console.log('adding ' + ar[i].xtype);
44999 if (ar[i].xtype == 'Button') {
45000 //console.log('adding button');
45001 //console.log(ar[i]);
45002 this.addButton(ar[i]);
45003 this.allItems.push(fe);
45007 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45008 alert('end is not supported on xtype any more, use items');
45010 // //console.log('adding end');
45018 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45019 * option "monitorValid"
45021 startMonitoring : function(){
45024 Roo.TaskMgr.start({
45025 run : this.bindHandler,
45026 interval : this.monitorPoll || 200,
45033 * Stops monitoring of the valid state of this form
45035 stopMonitoring : function(){
45036 this.bound = false;
45040 bindHandler : function(){
45042 return false; // stops binding
45045 this.items.each(function(f){
45046 if(!f.isValid(true)){
45051 for(var i = 0, len = this.buttons.length; i < len; i++){
45052 var btn = this.buttons[i];
45053 if(btn.formBind === true && btn.disabled === valid){
45054 btn.setDisabled(!valid);
45057 this.fireEvent('clientvalidation', this, valid);
45071 Roo.Form = Roo.form.Form;
45074 * Ext JS Library 1.1.1
45075 * Copyright(c) 2006-2007, Ext JS, LLC.
45077 * Originally Released Under LGPL - original licence link has changed is not relivant.
45080 * <script type="text/javascript">
45083 // as we use this in bootstrap.
45084 Roo.namespace('Roo.form');
45086 * @class Roo.form.Action
45087 * Internal Class used to handle form actions
45089 * @param {Roo.form.BasicForm} el The form element or its id
45090 * @param {Object} config Configuration options
45095 // define the action interface
45096 Roo.form.Action = function(form, options){
45098 this.options = options || {};
45101 * Client Validation Failed
45104 Roo.form.Action.CLIENT_INVALID = 'client';
45106 * Server Validation Failed
45109 Roo.form.Action.SERVER_INVALID = 'server';
45111 * Connect to Server Failed
45114 Roo.form.Action.CONNECT_FAILURE = 'connect';
45116 * Reading Data from Server Failed
45119 Roo.form.Action.LOAD_FAILURE = 'load';
45121 Roo.form.Action.prototype = {
45123 failureType : undefined,
45124 response : undefined,
45125 result : undefined,
45127 // interface method
45128 run : function(options){
45132 // interface method
45133 success : function(response){
45137 // interface method
45138 handleResponse : function(response){
45142 // default connection failure
45143 failure : function(response){
45145 this.response = response;
45146 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45147 this.form.afterAction(this, false);
45150 processResponse : function(response){
45151 this.response = response;
45152 if(!response.responseText){
45155 this.result = this.handleResponse(response);
45156 return this.result;
45159 // utility functions used internally
45160 getUrl : function(appendParams){
45161 var url = this.options.url || this.form.url || this.form.el.dom.action;
45163 var p = this.getParams();
45165 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45171 getMethod : function(){
45172 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45175 getParams : function(){
45176 var bp = this.form.baseParams;
45177 var p = this.options.params;
45179 if(typeof p == "object"){
45180 p = Roo.urlEncode(Roo.applyIf(p, bp));
45181 }else if(typeof p == 'string' && bp){
45182 p += '&' + Roo.urlEncode(bp);
45185 p = Roo.urlEncode(bp);
45190 createCallback : function(){
45192 success: this.success,
45193 failure: this.failure,
45195 timeout: (this.form.timeout*1000),
45196 upload: this.form.fileUpload ? this.success : undefined
45201 Roo.form.Action.Submit = function(form, options){
45202 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45205 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45208 haveProgress : false,
45209 uploadComplete : false,
45211 // uploadProgress indicator.
45212 uploadProgress : function()
45214 if (!this.form.progressUrl) {
45218 if (!this.haveProgress) {
45219 Roo.MessageBox.progress("Uploading", "Uploading");
45221 if (this.uploadComplete) {
45222 Roo.MessageBox.hide();
45226 this.haveProgress = true;
45228 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45230 var c = new Roo.data.Connection();
45232 url : this.form.progressUrl,
45237 success : function(req){
45238 //console.log(data);
45242 rdata = Roo.decode(req.responseText)
45244 Roo.log("Invalid data from server..");
45248 if (!rdata || !rdata.success) {
45250 Roo.MessageBox.alert(Roo.encode(rdata));
45253 var data = rdata.data;
45255 if (this.uploadComplete) {
45256 Roo.MessageBox.hide();
45261 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45262 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45265 this.uploadProgress.defer(2000,this);
45268 failure: function(data) {
45269 Roo.log('progress url failed ');
45280 // run get Values on the form, so it syncs any secondary forms.
45281 this.form.getValues();
45283 var o = this.options;
45284 var method = this.getMethod();
45285 var isPost = method == 'POST';
45286 if(o.clientValidation === false || this.form.isValid()){
45288 if (this.form.progressUrl) {
45289 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45290 (new Date() * 1) + '' + Math.random());
45295 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45296 form:this.form.el.dom,
45297 url:this.getUrl(!isPost),
45299 params:isPost ? this.getParams() : null,
45300 isUpload: this.form.fileUpload
45303 this.uploadProgress();
45305 }else if (o.clientValidation !== false){ // client validation failed
45306 this.failureType = Roo.form.Action.CLIENT_INVALID;
45307 this.form.afterAction(this, false);
45311 success : function(response)
45313 this.uploadComplete= true;
45314 if (this.haveProgress) {
45315 Roo.MessageBox.hide();
45319 var result = this.processResponse(response);
45320 if(result === true || result.success){
45321 this.form.afterAction(this, true);
45325 this.form.markInvalid(result.errors);
45326 this.failureType = Roo.form.Action.SERVER_INVALID;
45328 this.form.afterAction(this, false);
45330 failure : function(response)
45332 this.uploadComplete= true;
45333 if (this.haveProgress) {
45334 Roo.MessageBox.hide();
45337 this.response = response;
45338 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45339 this.form.afterAction(this, false);
45342 handleResponse : function(response){
45343 if(this.form.errorReader){
45344 var rs = this.form.errorReader.read(response);
45347 for(var i = 0, len = rs.records.length; i < len; i++) {
45348 var r = rs.records[i];
45349 errors[i] = r.data;
45352 if(errors.length < 1){
45356 success : rs.success,
45362 ret = Roo.decode(response.responseText);
45366 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45376 Roo.form.Action.Load = function(form, options){
45377 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45378 this.reader = this.form.reader;
45381 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45386 Roo.Ajax.request(Roo.apply(
45387 this.createCallback(), {
45388 method:this.getMethod(),
45389 url:this.getUrl(false),
45390 params:this.getParams()
45394 success : function(response){
45396 var result = this.processResponse(response);
45397 if(result === true || !result.success || !result.data){
45398 this.failureType = Roo.form.Action.LOAD_FAILURE;
45399 this.form.afterAction(this, false);
45402 this.form.clearInvalid();
45403 this.form.setValues(result.data);
45404 this.form.afterAction(this, true);
45407 handleResponse : function(response){
45408 if(this.form.reader){
45409 var rs = this.form.reader.read(response);
45410 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45412 success : rs.success,
45416 return Roo.decode(response.responseText);
45420 Roo.form.Action.ACTION_TYPES = {
45421 'load' : Roo.form.Action.Load,
45422 'submit' : Roo.form.Action.Submit
45425 * Ext JS Library 1.1.1
45426 * Copyright(c) 2006-2007, Ext JS, LLC.
45428 * Originally Released Under LGPL - original licence link has changed is not relivant.
45431 * <script type="text/javascript">
45435 * @class Roo.form.Layout
45436 * @extends Roo.Component
45437 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45439 * @param {Object} config Configuration options
45441 Roo.form.Layout = function(config){
45443 if (config.items) {
45444 xitems = config.items;
45445 delete config.items;
45447 Roo.form.Layout.superclass.constructor.call(this, config);
45449 Roo.each(xitems, this.addxtype, this);
45453 Roo.extend(Roo.form.Layout, Roo.Component, {
45455 * @cfg {String/Object} autoCreate
45456 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45459 * @cfg {String/Object/Function} style
45460 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45461 * a function which returns such a specification.
45464 * @cfg {String} labelAlign
45465 * Valid values are "left," "top" and "right" (defaults to "left")
45468 * @cfg {Number} labelWidth
45469 * Fixed width in pixels of all field labels (defaults to undefined)
45472 * @cfg {Boolean} clear
45473 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45477 * @cfg {String} labelSeparator
45478 * The separator to use after field labels (defaults to ':')
45480 labelSeparator : ':',
45482 * @cfg {Boolean} hideLabels
45483 * True to suppress the display of field labels in this layout (defaults to false)
45485 hideLabels : false,
45488 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45493 onRender : function(ct, position){
45494 if(this.el){ // from markup
45495 this.el = Roo.get(this.el);
45496 }else { // generate
45497 var cfg = this.getAutoCreate();
45498 this.el = ct.createChild(cfg, position);
45501 this.el.applyStyles(this.style);
45503 if(this.labelAlign){
45504 this.el.addClass('x-form-label-'+this.labelAlign);
45506 if(this.hideLabels){
45507 this.labelStyle = "display:none";
45508 this.elementStyle = "padding-left:0;";
45510 if(typeof this.labelWidth == 'number'){
45511 this.labelStyle = "width:"+this.labelWidth+"px;";
45512 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45514 if(this.labelAlign == 'top'){
45515 this.labelStyle = "width:auto;";
45516 this.elementStyle = "padding-left:0;";
45519 var stack = this.stack;
45520 var slen = stack.length;
45522 if(!this.fieldTpl){
45523 var t = new Roo.Template(
45524 '<div class="x-form-item {5}">',
45525 '<label for="{0}" style="{2}">{1}{4}</label>',
45526 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45528 '</div><div class="x-form-clear-left"></div>'
45530 t.disableFormats = true;
45532 Roo.form.Layout.prototype.fieldTpl = t;
45534 for(var i = 0; i < slen; i++) {
45535 if(stack[i].isFormField){
45536 this.renderField(stack[i]);
45538 this.renderComponent(stack[i]);
45543 this.el.createChild({cls:'x-form-clear'});
45548 renderField : function(f){
45549 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45552 f.labelStyle||this.labelStyle||'', //2
45553 this.elementStyle||'', //3
45554 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45555 f.itemCls||this.itemCls||'' //5
45556 ], true).getPrevSibling());
45560 renderComponent : function(c){
45561 c.render(c.isLayout ? this.el : this.el.createChild());
45564 * Adds a object form elements (using the xtype property as the factory method.)
45565 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45566 * @param {Object} config
45568 addxtype : function(o)
45570 // create the lement.
45571 o.form = this.form;
45572 var fe = Roo.factory(o, Roo.form);
45573 this.form.allItems.push(fe);
45574 this.stack.push(fe);
45576 if (fe.isFormField) {
45577 this.form.items.add(fe);
45585 * @class Roo.form.Column
45586 * @extends Roo.form.Layout
45587 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45589 * @param {Object} config Configuration options
45591 Roo.form.Column = function(config){
45592 Roo.form.Column.superclass.constructor.call(this, config);
45595 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45597 * @cfg {Number/String} width
45598 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45601 * @cfg {String/Object} autoCreate
45602 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45606 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45609 onRender : function(ct, position){
45610 Roo.form.Column.superclass.onRender.call(this, ct, position);
45612 this.el.setWidth(this.width);
45619 * @class Roo.form.Row
45620 * @extends Roo.form.Layout
45621 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45623 * @param {Object} config Configuration options
45627 Roo.form.Row = function(config){
45628 Roo.form.Row.superclass.constructor.call(this, config);
45631 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45633 * @cfg {Number/String} width
45634 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45637 * @cfg {Number/String} height
45638 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45640 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45644 onRender : function(ct, position){
45645 //console.log('row render');
45647 var t = new Roo.Template(
45648 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45649 '<label for="{0}" style="{2}">{1}{4}</label>',
45650 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45654 t.disableFormats = true;
45656 Roo.form.Layout.prototype.rowTpl = t;
45658 this.fieldTpl = this.rowTpl;
45660 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45661 var labelWidth = 100;
45663 if ((this.labelAlign != 'top')) {
45664 if (typeof this.labelWidth == 'number') {
45665 labelWidth = this.labelWidth
45667 this.padWidth = 20 + labelWidth;
45671 Roo.form.Column.superclass.onRender.call(this, ct, position);
45673 this.el.setWidth(this.width);
45676 this.el.setHeight(this.height);
45681 renderField : function(f){
45682 f.fieldEl = this.fieldTpl.append(this.el, [
45683 f.id, f.fieldLabel,
45684 f.labelStyle||this.labelStyle||'',
45685 this.elementStyle||'',
45686 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45687 f.itemCls||this.itemCls||'',
45688 f.width ? f.width + this.padWidth : 160 + this.padWidth
45695 * @class Roo.form.FieldSet
45696 * @extends Roo.form.Layout
45697 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45699 * @param {Object} config Configuration options
45701 Roo.form.FieldSet = function(config){
45702 Roo.form.FieldSet.superclass.constructor.call(this, config);
45705 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45707 * @cfg {String} legend
45708 * The text to display as the legend for the FieldSet (defaults to '')
45711 * @cfg {String/Object} autoCreate
45712 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45716 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45719 onRender : function(ct, position){
45720 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45722 this.setLegend(this.legend);
45727 setLegend : function(text){
45729 this.el.child('legend').update(text);
45734 * Ext JS Library 1.1.1
45735 * Copyright(c) 2006-2007, Ext JS, LLC.
45737 * Originally Released Under LGPL - original licence link has changed is not relivant.
45740 * <script type="text/javascript">
45743 * @class Roo.form.VTypes
45744 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
45747 Roo.form.VTypes = function(){
45748 // closure these in so they are only created once.
45749 var alpha = /^[a-zA-Z_]+$/;
45750 var alphanum = /^[a-zA-Z0-9_]+$/;
45751 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
45752 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
45754 // All these messages and functions are configurable
45757 * The function used to validate email addresses
45758 * @param {String} value The email address
45760 'email' : function(v){
45761 return email.test(v);
45764 * The error text to display when the email validation function returns false
45767 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
45769 * The keystroke filter mask to be applied on email input
45772 'emailMask' : /[a-z0-9_\.\-@]/i,
45775 * The function used to validate URLs
45776 * @param {String} value The URL
45778 'url' : function(v){
45779 return url.test(v);
45782 * The error text to display when the url validation function returns false
45785 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
45788 * The function used to validate alpha values
45789 * @param {String} value The value
45791 'alpha' : function(v){
45792 return alpha.test(v);
45795 * The error text to display when the alpha validation function returns false
45798 'alphaText' : 'This field should only contain letters and _',
45800 * The keystroke filter mask to be applied on alpha input
45803 'alphaMask' : /[a-z_]/i,
45806 * The function used to validate alphanumeric values
45807 * @param {String} value The value
45809 'alphanum' : function(v){
45810 return alphanum.test(v);
45813 * The error text to display when the alphanumeric validation function returns false
45816 'alphanumText' : 'This field should only contain letters, numbers and _',
45818 * The keystroke filter mask to be applied on alphanumeric input
45821 'alphanumMask' : /[a-z0-9_]/i
45823 }();//<script type="text/javascript">
45826 * @class Roo.form.FCKeditor
45827 * @extends Roo.form.TextArea
45828 * Wrapper around the FCKEditor http://www.fckeditor.net
45830 * Creates a new FCKeditor
45831 * @param {Object} config Configuration options
45833 Roo.form.FCKeditor = function(config){
45834 Roo.form.FCKeditor.superclass.constructor.call(this, config);
45837 * @event editorinit
45838 * Fired when the editor is initialized - you can add extra handlers here..
45839 * @param {FCKeditor} this
45840 * @param {Object} the FCK object.
45847 Roo.form.FCKeditor.editors = { };
45848 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
45850 //defaultAutoCreate : {
45851 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
45855 * @cfg {Object} fck options - see fck manual for details.
45860 * @cfg {Object} fck toolbar set (Basic or Default)
45862 toolbarSet : 'Basic',
45864 * @cfg {Object} fck BasePath
45866 basePath : '/fckeditor/',
45874 onRender : function(ct, position)
45877 this.defaultAutoCreate = {
45879 style:"width:300px;height:60px;",
45880 autocomplete: "off"
45883 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
45886 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
45887 if(this.preventScrollbars){
45888 this.el.setStyle("overflow", "hidden");
45890 this.el.setHeight(this.growMin);
45893 //console.log('onrender' + this.getId() );
45894 Roo.form.FCKeditor.editors[this.getId()] = this;
45897 this.replaceTextarea() ;
45901 getEditor : function() {
45902 return this.fckEditor;
45905 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
45906 * @param {Mixed} value The value to set
45910 setValue : function(value)
45912 //console.log('setValue: ' + value);
45914 if(typeof(value) == 'undefined') { // not sure why this is happending...
45917 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45919 //if(!this.el || !this.getEditor()) {
45920 // this.value = value;
45921 //this.setValue.defer(100,this,[value]);
45925 if(!this.getEditor()) {
45929 this.getEditor().SetData(value);
45936 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
45937 * @return {Mixed} value The field value
45939 getValue : function()
45942 if (this.frame && this.frame.dom.style.display == 'none') {
45943 return Roo.form.FCKeditor.superclass.getValue.call(this);
45946 if(!this.el || !this.getEditor()) {
45948 // this.getValue.defer(100,this);
45953 var value=this.getEditor().GetData();
45954 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45955 return Roo.form.FCKeditor.superclass.getValue.call(this);
45961 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
45962 * @return {Mixed} value The field value
45964 getRawValue : function()
45966 if (this.frame && this.frame.dom.style.display == 'none') {
45967 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45970 if(!this.el || !this.getEditor()) {
45971 //this.getRawValue.defer(100,this);
45978 var value=this.getEditor().GetData();
45979 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
45980 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45984 setSize : function(w,h) {
45988 //if (this.frame && this.frame.dom.style.display == 'none') {
45989 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45992 //if(!this.el || !this.getEditor()) {
45993 // this.setSize.defer(100,this, [w,h]);
45999 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46001 this.frame.dom.setAttribute('width', w);
46002 this.frame.dom.setAttribute('height', h);
46003 this.frame.setSize(w,h);
46007 toggleSourceEdit : function(value) {
46011 this.el.dom.style.display = value ? '' : 'none';
46012 this.frame.dom.style.display = value ? 'none' : '';
46017 focus: function(tag)
46019 if (this.frame.dom.style.display == 'none') {
46020 return Roo.form.FCKeditor.superclass.focus.call(this);
46022 if(!this.el || !this.getEditor()) {
46023 this.focus.defer(100,this, [tag]);
46030 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46031 this.getEditor().Focus();
46033 if (!this.getEditor().Selection.GetSelection()) {
46034 this.focus.defer(100,this, [tag]);
46039 var r = this.getEditor().EditorDocument.createRange();
46040 r.setStart(tgs[0],0);
46041 r.setEnd(tgs[0],0);
46042 this.getEditor().Selection.GetSelection().removeAllRanges();
46043 this.getEditor().Selection.GetSelection().addRange(r);
46044 this.getEditor().Focus();
46051 replaceTextarea : function()
46053 if ( document.getElementById( this.getId() + '___Frame' ) )
46055 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46057 // We must check the elements firstly using the Id and then the name.
46058 var oTextarea = document.getElementById( this.getId() );
46060 var colElementsByName = document.getElementsByName( this.getId() ) ;
46062 oTextarea.style.display = 'none' ;
46064 if ( oTextarea.tabIndex ) {
46065 this.TabIndex = oTextarea.tabIndex ;
46068 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46069 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46070 this.frame = Roo.get(this.getId() + '___Frame')
46073 _getConfigHtml : function()
46077 for ( var o in this.fckconfig ) {
46078 sConfig += sConfig.length > 0 ? '&' : '';
46079 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46082 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46086 _getIFrameHtml : function()
46088 var sFile = 'fckeditor.html' ;
46089 /* no idea what this is about..
46092 if ( (/fcksource=true/i).test( window.top.location.search ) )
46093 sFile = 'fckeditor.original.html' ;
46098 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46099 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46102 var html = '<iframe id="' + this.getId() +
46103 '___Frame" src="' + sLink +
46104 '" width="' + this.width +
46105 '" height="' + this.height + '"' +
46106 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46107 ' frameborder="0" scrolling="no"></iframe>' ;
46112 _insertHtmlBefore : function( html, element )
46114 if ( element.insertAdjacentHTML ) {
46116 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46118 var oRange = document.createRange() ;
46119 oRange.setStartBefore( element ) ;
46120 var oFragment = oRange.createContextualFragment( html );
46121 element.parentNode.insertBefore( oFragment, element ) ;
46134 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46136 function FCKeditor_OnComplete(editorInstance){
46137 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46138 f.fckEditor = editorInstance;
46139 //console.log("loaded");
46140 f.fireEvent('editorinit', f, editorInstance);
46160 //<script type="text/javascript">
46162 * @class Roo.form.GridField
46163 * @extends Roo.form.Field
46164 * Embed a grid (or editable grid into a form)
46167 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46169 * xgrid.store = Roo.data.Store
46170 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46171 * xgrid.store.reader = Roo.data.JsonReader
46175 * Creates a new GridField
46176 * @param {Object} config Configuration options
46178 Roo.form.GridField = function(config){
46179 Roo.form.GridField.superclass.constructor.call(this, config);
46183 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46185 * @cfg {Number} width - used to restrict width of grid..
46189 * @cfg {Number} height - used to restrict height of grid..
46193 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46199 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46200 * {tag: "input", type: "checkbox", autocomplete: "off"})
46202 // defaultAutoCreate : { tag: 'div' },
46203 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46205 * @cfg {String} addTitle Text to include for adding a title.
46209 onResize : function(){
46210 Roo.form.Field.superclass.onResize.apply(this, arguments);
46213 initEvents : function(){
46214 // Roo.form.Checkbox.superclass.initEvents.call(this);
46215 // has no events...
46220 getResizeEl : function(){
46224 getPositionEl : function(){
46229 onRender : function(ct, position){
46231 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46232 var style = this.style;
46235 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46236 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46237 this.viewEl = this.wrap.createChild({ tag: 'div' });
46239 this.viewEl.applyStyles(style);
46242 this.viewEl.setWidth(this.width);
46245 this.viewEl.setHeight(this.height);
46247 //if(this.inputValue !== undefined){
46248 //this.setValue(this.value);
46251 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46254 this.grid.render();
46255 this.grid.getDataSource().on('remove', this.refreshValue, this);
46256 this.grid.getDataSource().on('update', this.refreshValue, this);
46257 this.grid.on('afteredit', this.refreshValue, this);
46263 * Sets the value of the item.
46264 * @param {String} either an object or a string..
46266 setValue : function(v){
46268 v = v || []; // empty set..
46269 // this does not seem smart - it really only affects memoryproxy grids..
46270 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46271 var ds = this.grid.getDataSource();
46272 // assumes a json reader..
46274 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46275 ds.loadData( data);
46277 // clear selection so it does not get stale.
46278 if (this.grid.sm) {
46279 this.grid.sm.clearSelections();
46282 Roo.form.GridField.superclass.setValue.call(this, v);
46283 this.refreshValue();
46284 // should load data in the grid really....
46288 refreshValue: function() {
46290 this.grid.getDataSource().each(function(r) {
46293 this.el.dom.value = Roo.encode(val);
46301 * Ext JS Library 1.1.1
46302 * Copyright(c) 2006-2007, Ext JS, LLC.
46304 * Originally Released Under LGPL - original licence link has changed is not relivant.
46307 * <script type="text/javascript">
46310 * @class Roo.form.DisplayField
46311 * @extends Roo.form.Field
46312 * A generic Field to display non-editable data.
46314 * Creates a new Display Field item.
46315 * @param {Object} config Configuration options
46317 Roo.form.DisplayField = function(config){
46318 Roo.form.DisplayField.superclass.constructor.call(this, config);
46322 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46323 inputType: 'hidden',
46329 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46331 focusClass : undefined,
46333 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46335 fieldClass: 'x-form-field',
46338 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46340 valueRenderer: undefined,
46344 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46345 * {tag: "input", type: "checkbox", autocomplete: "off"})
46348 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46350 onResize : function(){
46351 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46355 initEvents : function(){
46356 // Roo.form.Checkbox.superclass.initEvents.call(this);
46357 // has no events...
46362 getResizeEl : function(){
46366 getPositionEl : function(){
46371 onRender : function(ct, position){
46373 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46374 //if(this.inputValue !== undefined){
46375 this.wrap = this.el.wrap();
46377 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46379 if (this.bodyStyle) {
46380 this.viewEl.applyStyles(this.bodyStyle);
46382 //this.viewEl.setStyle('padding', '2px');
46384 this.setValue(this.value);
46389 initValue : Roo.emptyFn,
46394 onClick : function(){
46399 * Sets the checked state of the checkbox.
46400 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46402 setValue : function(v){
46404 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46405 // this might be called before we have a dom element..
46406 if (!this.viewEl) {
46409 this.viewEl.dom.innerHTML = html;
46410 Roo.form.DisplayField.superclass.setValue.call(this, v);
46420 * @class Roo.form.DayPicker
46421 * @extends Roo.form.Field
46422 * A Day picker show [M] [T] [W] ....
46424 * Creates a new Day Picker
46425 * @param {Object} config Configuration options
46427 Roo.form.DayPicker= function(config){
46428 Roo.form.DayPicker.superclass.constructor.call(this, config);
46432 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46434 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46436 focusClass : undefined,
46438 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46440 fieldClass: "x-form-field",
46443 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46444 * {tag: "input", type: "checkbox", autocomplete: "off"})
46446 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46449 actionMode : 'viewEl',
46453 inputType : 'hidden',
46456 inputElement: false, // real input element?
46457 basedOn: false, // ????
46459 isFormField: true, // not sure where this is needed!!!!
46461 onResize : function(){
46462 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46463 if(!this.boxLabel){
46464 this.el.alignTo(this.wrap, 'c-c');
46468 initEvents : function(){
46469 Roo.form.Checkbox.superclass.initEvents.call(this);
46470 this.el.on("click", this.onClick, this);
46471 this.el.on("change", this.onClick, this);
46475 getResizeEl : function(){
46479 getPositionEl : function(){
46485 onRender : function(ct, position){
46486 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46488 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46490 var r1 = '<table><tr>';
46491 var r2 = '<tr class="x-form-daypick-icons">';
46492 for (var i=0; i < 7; i++) {
46493 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46494 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46497 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46498 viewEl.select('img').on('click', this.onClick, this);
46499 this.viewEl = viewEl;
46502 // this will not work on Chrome!!!
46503 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46504 this.el.on('propertychange', this.setFromHidden, this); //ie
46512 initValue : Roo.emptyFn,
46515 * Returns the checked state of the checkbox.
46516 * @return {Boolean} True if checked, else false
46518 getValue : function(){
46519 return this.el.dom.value;
46524 onClick : function(e){
46525 //this.setChecked(!this.checked);
46526 Roo.get(e.target).toggleClass('x-menu-item-checked');
46527 this.refreshValue();
46528 //if(this.el.dom.checked != this.checked){
46529 // this.setValue(this.el.dom.checked);
46534 refreshValue : function()
46537 this.viewEl.select('img',true).each(function(e,i,n) {
46538 val += e.is(".x-menu-item-checked") ? String(n) : '';
46540 this.setValue(val, true);
46544 * Sets the checked state of the checkbox.
46545 * On is always based on a string comparison between inputValue and the param.
46546 * @param {Boolean/String} value - the value to set
46547 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46549 setValue : function(v,suppressEvent){
46550 if (!this.el.dom) {
46553 var old = this.el.dom.value ;
46554 this.el.dom.value = v;
46555 if (suppressEvent) {
46559 // update display..
46560 this.viewEl.select('img',true).each(function(e,i,n) {
46562 var on = e.is(".x-menu-item-checked");
46563 var newv = v.indexOf(String(n)) > -1;
46565 e.toggleClass('x-menu-item-checked');
46571 this.fireEvent('change', this, v, old);
46576 // handle setting of hidden value by some other method!!?!?
46577 setFromHidden: function()
46582 //console.log("SET FROM HIDDEN");
46583 //alert('setFrom hidden');
46584 this.setValue(this.el.dom.value);
46587 onDestroy : function()
46590 Roo.get(this.viewEl).remove();
46593 Roo.form.DayPicker.superclass.onDestroy.call(this);
46597 * RooJS Library 1.1.1
46598 * Copyright(c) 2008-2011 Alan Knowles
46605 * @class Roo.form.ComboCheck
46606 * @extends Roo.form.ComboBox
46607 * A combobox for multiple select items.
46609 * FIXME - could do with a reset button..
46612 * Create a new ComboCheck
46613 * @param {Object} config Configuration options
46615 Roo.form.ComboCheck = function(config){
46616 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46617 // should verify some data...
46619 // hiddenName = required..
46620 // displayField = required
46621 // valudField == required
46622 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46624 Roo.each(req, function(e) {
46625 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46626 throw "Roo.form.ComboCheck : missing value for: " + e;
46633 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46638 selectedClass: 'x-menu-item-checked',
46641 onRender : function(ct, position){
46647 var cls = 'x-combo-list';
46650 this.tpl = new Roo.Template({
46651 html : '<div class="'+cls+'-item x-menu-check-item">' +
46652 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46653 '<span>{' + this.displayField + '}</span>' +
46660 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46661 this.view.singleSelect = false;
46662 this.view.multiSelect = true;
46663 this.view.toggleSelect = true;
46664 this.pageTb.add(new Roo.Toolbar.Fill(), {
46667 handler: function()
46674 onViewOver : function(e, t){
46680 onViewClick : function(doFocus,index){
46684 select: function () {
46685 //Roo.log("SELECT CALLED");
46688 selectByValue : function(xv, scrollIntoView){
46689 var ar = this.getValueArray();
46692 Roo.each(ar, function(v) {
46693 if(v === undefined || v === null){
46696 var r = this.findRecord(this.valueField, v);
46698 sels.push(this.store.indexOf(r))
46702 this.view.select(sels);
46708 onSelect : function(record, index){
46709 // Roo.log("onselect Called");
46710 // this is only called by the clear button now..
46711 this.view.clearSelections();
46712 this.setValue('[]');
46713 if (this.value != this.valueBefore) {
46714 this.fireEvent('change', this, this.value, this.valueBefore);
46715 this.valueBefore = this.value;
46718 getValueArray : function()
46723 //Roo.log(this.value);
46724 if (typeof(this.value) == 'undefined') {
46727 var ar = Roo.decode(this.value);
46728 return ar instanceof Array ? ar : []; //?? valid?
46731 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
46736 expand : function ()
46739 Roo.form.ComboCheck.superclass.expand.call(this);
46740 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
46741 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
46746 collapse : function(){
46747 Roo.form.ComboCheck.superclass.collapse.call(this);
46748 var sl = this.view.getSelectedIndexes();
46749 var st = this.store;
46753 Roo.each(sl, function(i) {
46755 nv.push(r.get(this.valueField));
46757 this.setValue(Roo.encode(nv));
46758 if (this.value != this.valueBefore) {
46760 this.fireEvent('change', this, this.value, this.valueBefore);
46761 this.valueBefore = this.value;
46766 setValue : function(v){
46770 var vals = this.getValueArray();
46772 Roo.each(vals, function(k) {
46773 var r = this.findRecord(this.valueField, k);
46775 tv.push(r.data[this.displayField]);
46776 }else if(this.valueNotFoundText !== undefined){
46777 tv.push( this.valueNotFoundText );
46782 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
46783 this.hiddenField.value = v;
46789 * Ext JS Library 1.1.1
46790 * Copyright(c) 2006-2007, Ext JS, LLC.
46792 * Originally Released Under LGPL - original licence link has changed is not relivant.
46795 * <script type="text/javascript">
46799 * @class Roo.form.Signature
46800 * @extends Roo.form.Field
46804 * @param {Object} config Configuration options
46807 Roo.form.Signature = function(config){
46808 Roo.form.Signature.superclass.constructor.call(this, config);
46810 this.addEvents({// not in used??
46813 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
46814 * @param {Roo.form.Signature} combo This combo box
46819 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
46820 * @param {Roo.form.ComboBox} combo This combo box
46821 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
46827 Roo.extend(Roo.form.Signature, Roo.form.Field, {
46829 * @cfg {Object} labels Label to use when rendering a form.
46833 * confirm : "Confirm"
46838 confirm : "Confirm"
46841 * @cfg {Number} width The signature panel width (defaults to 300)
46845 * @cfg {Number} height The signature panel height (defaults to 100)
46849 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
46851 allowBlank : false,
46854 // {Object} signPanel The signature SVG panel element (defaults to {})
46856 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
46857 isMouseDown : false,
46858 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
46859 isConfirmed : false,
46860 // {String} signatureTmp SVG mapping string (defaults to empty string)
46864 defaultAutoCreate : { // modified by initCompnoent..
46870 onRender : function(ct, position){
46872 Roo.form.Signature.superclass.onRender.call(this, ct, position);
46874 this.wrap = this.el.wrap({
46875 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
46878 this.createToolbar(this);
46879 this.signPanel = this.wrap.createChild({
46881 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
46885 this.svgID = Roo.id();
46886 this.svgEl = this.signPanel.createChild({
46887 xmlns : 'http://www.w3.org/2000/svg',
46889 id : this.svgID + "-svg",
46891 height: this.height,
46892 viewBox: '0 0 '+this.width+' '+this.height,
46896 id: this.svgID + "-svg-r",
46898 height: this.height,
46903 id: this.svgID + "-svg-l",
46905 y1: (this.height*0.8), // start set the line in 80% of height
46906 x2: this.width, // end
46907 y2: (this.height*0.8), // end set the line in 80% of height
46909 'stroke-width': "1",
46910 'stroke-dasharray': "3",
46911 'shape-rendering': "crispEdges",
46912 'pointer-events': "none"
46916 id: this.svgID + "-svg-p",
46918 'stroke-width': "3",
46920 'pointer-events': 'none'
46925 this.svgBox = this.svgEl.dom.getScreenCTM();
46927 createSVG : function(){
46928 var svg = this.signPanel;
46929 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
46932 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
46933 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
46934 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
46935 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
46936 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
46937 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
46938 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
46941 isTouchEvent : function(e){
46942 return e.type.match(/^touch/);
46944 getCoords : function (e) {
46945 var pt = this.svgEl.dom.createSVGPoint();
46948 if (this.isTouchEvent(e)) {
46949 pt.x = e.targetTouches[0].clientX
46950 pt.y = e.targetTouches[0].clientY;
46952 var a = this.svgEl.dom.getScreenCTM();
46953 var b = a.inverse();
46954 var mx = pt.matrixTransform(b);
46955 return mx.x + ',' + mx.y;
46957 //mouse event headler
46958 down : function (e) {
46959 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
46960 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
46962 this.isMouseDown = true;
46964 e.preventDefault();
46966 move : function (e) {
46967 if (this.isMouseDown) {
46968 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
46969 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
46972 e.preventDefault();
46974 up : function (e) {
46975 this.isMouseDown = false;
46976 var sp = this.signatureTmp.split(' ');
46979 if(!sp[sp.length-2].match(/^L/)){
46983 this.signatureTmp = sp.join(" ");
46986 if(this.getValue() != this.signatureTmp){
46987 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46988 this.isConfirmed = false;
46990 e.preventDefault();
46994 * Protected method that will not generally be called directly. It
46995 * is called when the editor creates its toolbar. Override this method if you need to
46996 * add custom toolbar buttons.
46997 * @param {HtmlEditor} editor
46999 createToolbar : function(editor){
47000 function btn(id, toggle, handler){
47001 var xid = fid + '-'+ id ;
47005 cls : 'x-btn-icon x-edit-'+id,
47006 enableToggle:toggle !== false,
47007 scope: editor, // was editor...
47008 handler:handler||editor.relayBtnCmd,
47009 clickEvent:'mousedown',
47010 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47016 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47020 cls : ' x-signature-btn x-signature-'+id,
47021 scope: editor, // was editor...
47022 handler: this.reset,
47023 clickEvent:'mousedown',
47024 text: this.labels.clear
47031 cls : ' x-signature-btn x-signature-'+id,
47032 scope: editor, // was editor...
47033 handler: this.confirmHandler,
47034 clickEvent:'mousedown',
47035 text: this.labels.confirm
47042 * when user is clicked confirm then show this image.....
47044 * @return {String} Image Data URI
47046 getImageDataURI : function(){
47047 var svg = this.svgEl.dom.parentNode.innerHTML;
47048 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47053 * @return {Boolean} this.isConfirmed
47055 getConfirmed : function(){
47056 return this.isConfirmed;
47060 * @return {Number} this.width
47062 getWidth : function(){
47067 * @return {Number} this.height
47069 getHeight : function(){
47070 return this.height;
47073 getSignature : function(){
47074 return this.signatureTmp;
47077 reset : function(){
47078 this.signatureTmp = '';
47079 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47080 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47081 this.isConfirmed = false;
47082 Roo.form.Signature.superclass.reset.call(this);
47084 setSignature : function(s){
47085 this.signatureTmp = s;
47086 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47087 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47089 this.isConfirmed = false;
47090 Roo.form.Signature.superclass.reset.call(this);
47093 // Roo.log(this.signPanel.dom.contentWindow.up())
47096 setConfirmed : function(){
47100 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47103 confirmHandler : function(){
47104 if(!this.getSignature()){
47108 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47109 this.setValue(this.getSignature());
47110 this.isConfirmed = true;
47112 this.fireEvent('confirm', this);
47115 // Subclasses should provide the validation implementation by overriding this
47116 validateValue : function(value){
47117 if(this.allowBlank){
47121 if(this.isConfirmed){
47128 * Ext JS Library 1.1.1
47129 * Copyright(c) 2006-2007, Ext JS, LLC.
47131 * Originally Released Under LGPL - original licence link has changed is not relivant.
47134 * <script type="text/javascript">
47139 * @class Roo.form.ComboBox
47140 * @extends Roo.form.TriggerField
47141 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47143 * Create a new ComboBox.
47144 * @param {Object} config Configuration options
47146 Roo.form.Select = function(config){
47147 Roo.form.Select.superclass.constructor.call(this, config);
47151 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47153 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47156 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47157 * rendering into an Roo.Editor, defaults to false)
47160 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47161 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47164 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47167 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47168 * the dropdown list (defaults to undefined, with no header element)
47172 * @cfg {String/Roo.Template} tpl The template to use to render the output
47176 defaultAutoCreate : {tag: "select" },
47178 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47180 listWidth: undefined,
47182 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47183 * mode = 'remote' or 'text' if mode = 'local')
47185 displayField: undefined,
47187 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47188 * mode = 'remote' or 'value' if mode = 'local').
47189 * Note: use of a valueField requires the user make a selection
47190 * in order for a value to be mapped.
47192 valueField: undefined,
47196 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47197 * field's data value (defaults to the underlying DOM element's name)
47199 hiddenName: undefined,
47201 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47205 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47207 selectedClass: 'x-combo-selected',
47209 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47210 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47211 * which displays a downward arrow icon).
47213 triggerClass : 'x-form-arrow-trigger',
47215 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47219 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47220 * anchor positions (defaults to 'tl-bl')
47222 listAlign: 'tl-bl?',
47224 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47228 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47229 * query specified by the allQuery config option (defaults to 'query')
47231 triggerAction: 'query',
47233 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47234 * (defaults to 4, does not apply if editable = false)
47238 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47239 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47243 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47244 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47248 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47249 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47253 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47254 * when editable = true (defaults to false)
47256 selectOnFocus:false,
47258 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47260 queryParam: 'query',
47262 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47263 * when mode = 'remote' (defaults to 'Loading...')
47265 loadingText: 'Loading...',
47267 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47271 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47275 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47276 * traditional select (defaults to true)
47280 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47284 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47288 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47289 * listWidth has a higher value)
47293 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47294 * allow the user to set arbitrary text into the field (defaults to false)
47296 forceSelection:false,
47298 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47299 * if typeAhead = true (defaults to 250)
47301 typeAheadDelay : 250,
47303 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47304 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47306 valueNotFoundText : undefined,
47309 * @cfg {String} defaultValue The value displayed after loading the store.
47314 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47316 blockFocus : false,
47319 * @cfg {Boolean} disableClear Disable showing of clear button.
47321 disableClear : false,
47323 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47325 alwaysQuery : false,
47331 // element that contains real text value.. (when hidden is used..)
47334 onRender : function(ct, position){
47335 Roo.form.Field.prototype.onRender.call(this, ct, position);
47338 this.store.on('beforeload', this.onBeforeLoad, this);
47339 this.store.on('load', this.onLoad, this);
47340 this.store.on('loadexception', this.onLoadException, this);
47341 this.store.load({});
47349 initEvents : function(){
47350 //Roo.form.ComboBox.superclass.initEvents.call(this);
47354 onDestroy : function(){
47357 this.store.un('beforeload', this.onBeforeLoad, this);
47358 this.store.un('load', this.onLoad, this);
47359 this.store.un('loadexception', this.onLoadException, this);
47361 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47365 fireKey : function(e){
47366 if(e.isNavKeyPress() && !this.list.isVisible()){
47367 this.fireEvent("specialkey", this, e);
47372 onResize: function(w, h){
47380 * Allow or prevent the user from directly editing the field text. If false is passed,
47381 * the user will only be able to select from the items defined in the dropdown list. This method
47382 * is the runtime equivalent of setting the 'editable' config option at config time.
47383 * @param {Boolean} value True to allow the user to directly edit the field text
47385 setEditable : function(value){
47390 onBeforeLoad : function(){
47392 Roo.log("Select before load");
47395 this.innerList.update(this.loadingText ?
47396 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47397 //this.restrictHeight();
47398 this.selectedIndex = -1;
47402 onLoad : function(){
47405 var dom = this.el.dom;
47406 dom.innerHTML = '';
47407 var od = dom.ownerDocument;
47409 if (this.emptyText) {
47410 var op = od.createElement('option');
47411 op.setAttribute('value', '');
47412 op.innerHTML = String.format('{0}', this.emptyText);
47413 dom.appendChild(op);
47415 if(this.store.getCount() > 0){
47417 var vf = this.valueField;
47418 var df = this.displayField;
47419 this.store.data.each(function(r) {
47420 // which colmsn to use... testing - cdoe / title..
47421 var op = od.createElement('option');
47422 op.setAttribute('value', r.data[vf]);
47423 op.innerHTML = String.format('{0}', r.data[df]);
47424 dom.appendChild(op);
47426 if (typeof(this.defaultValue != 'undefined')) {
47427 this.setValue(this.defaultValue);
47432 //this.onEmptyResults();
47437 onLoadException : function()
47439 dom.innerHTML = '';
47441 Roo.log("Select on load exception");
47445 Roo.log(this.store.reader.jsonData);
47446 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47447 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47453 onTypeAhead : function(){
47458 onSelect : function(record, index){
47459 Roo.log('on select?');
47461 if(this.fireEvent('beforeselect', this, record, index) !== false){
47462 this.setFromData(index > -1 ? record.data : false);
47464 this.fireEvent('select', this, record, index);
47469 * Returns the currently selected field value or empty string if no value is set.
47470 * @return {String} value The selected value
47472 getValue : function(){
47473 var dom = this.el.dom;
47474 this.value = dom.options[dom.selectedIndex].value;
47480 * Clears any text/value currently set in the field
47482 clearValue : function(){
47484 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47489 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47490 * will be displayed in the field. If the value does not match the data value of an existing item,
47491 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47492 * Otherwise the field will be blank (although the value will still be set).
47493 * @param {String} value The value to match
47495 setValue : function(v){
47496 var d = this.el.dom;
47497 for (var i =0; i < d.options.length;i++) {
47498 if (v == d.options[i].value) {
47499 d.selectedIndex = i;
47507 * @property {Object} the last set data for the element
47512 * Sets the value of the field based on a object which is related to the record format for the store.
47513 * @param {Object} value the value to set as. or false on reset?
47515 setFromData : function(o){
47516 Roo.log('setfrom data?');
47522 reset : function(){
47526 findRecord : function(prop, value){
47531 if(this.store.getCount() > 0){
47532 this.store.each(function(r){
47533 if(r.data[prop] == value){
47543 getName: function()
47545 // returns hidden if it's set..
47546 if (!this.rendered) {return ''};
47547 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47555 onEmptyResults : function(){
47556 Roo.log('empty results');
47561 * Returns true if the dropdown list is expanded, else false.
47563 isExpanded : function(){
47568 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47569 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47570 * @param {String} value The data value of the item to select
47571 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47572 * selected item if it is not currently in view (defaults to true)
47573 * @return {Boolean} True if the value matched an item in the list, else false
47575 selectByValue : function(v, scrollIntoView){
47576 Roo.log('select By Value');
47579 if(v !== undefined && v !== null){
47580 var r = this.findRecord(this.valueField || this.displayField, v);
47582 this.select(this.store.indexOf(r), scrollIntoView);
47590 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47591 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47592 * @param {Number} index The zero-based index of the list item to select
47593 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47594 * selected item if it is not currently in view (defaults to true)
47596 select : function(index, scrollIntoView){
47597 Roo.log('select ');
47600 this.selectedIndex = index;
47601 this.view.select(index);
47602 if(scrollIntoView !== false){
47603 var el = this.view.getNode(index);
47605 this.innerList.scrollChildIntoView(el, false);
47613 validateBlur : function(){
47620 initQuery : function(){
47621 this.doQuery(this.getRawValue());
47625 doForce : function(){
47626 if(this.el.dom.value.length > 0){
47627 this.el.dom.value =
47628 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47634 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47635 * query allowing the query action to be canceled if needed.
47636 * @param {String} query The SQL query to execute
47637 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47638 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47639 * saved in the current store (defaults to false)
47641 doQuery : function(q, forceAll){
47643 Roo.log('doQuery?');
47644 if(q === undefined || q === null){
47649 forceAll: forceAll,
47653 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47657 forceAll = qe.forceAll;
47658 if(forceAll === true || (q.length >= this.minChars)){
47659 if(this.lastQuery != q || this.alwaysQuery){
47660 this.lastQuery = q;
47661 if(this.mode == 'local'){
47662 this.selectedIndex = -1;
47664 this.store.clearFilter();
47666 this.store.filter(this.displayField, q);
47670 this.store.baseParams[this.queryParam] = q;
47672 params: this.getParams(q)
47677 this.selectedIndex = -1;
47684 getParams : function(q){
47686 //p[this.queryParam] = q;
47689 p.limit = this.pageSize;
47695 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47697 collapse : function(){
47702 collapseIf : function(e){
47707 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47709 expand : function(){
47717 * @cfg {Boolean} grow
47721 * @cfg {Number} growMin
47725 * @cfg {Number} growMax
47733 setWidth : function()
47737 getResizeEl : function(){
47740 });//<script type="text/javasscript">
47744 * @class Roo.DDView
47745 * A DnD enabled version of Roo.View.
47746 * @param {Element/String} container The Element in which to create the View.
47747 * @param {String} tpl The template string used to create the markup for each element of the View
47748 * @param {Object} config The configuration properties. These include all the config options of
47749 * {@link Roo.View} plus some specific to this class.<br>
47751 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
47752 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
47754 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
47755 .x-view-drag-insert-above {
47756 border-top:1px dotted #3366cc;
47758 .x-view-drag-insert-below {
47759 border-bottom:1px dotted #3366cc;
47765 Roo.DDView = function(container, tpl, config) {
47766 Roo.DDView.superclass.constructor.apply(this, arguments);
47767 this.getEl().setStyle("outline", "0px none");
47768 this.getEl().unselectable();
47769 if (this.dragGroup) {
47770 this.setDraggable(this.dragGroup.split(","));
47772 if (this.dropGroup) {
47773 this.setDroppable(this.dropGroup.split(","));
47775 if (this.deletable) {
47776 this.setDeletable();
47778 this.isDirtyFlag = false;
47784 Roo.extend(Roo.DDView, Roo.View, {
47785 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
47786 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
47787 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
47788 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
47792 reset: Roo.emptyFn,
47794 clearInvalid: Roo.form.Field.prototype.clearInvalid,
47796 validate: function() {
47800 destroy: function() {
47801 this.purgeListeners();
47802 this.getEl.removeAllListeners();
47803 this.getEl().remove();
47804 if (this.dragZone) {
47805 if (this.dragZone.destroy) {
47806 this.dragZone.destroy();
47809 if (this.dropZone) {
47810 if (this.dropZone.destroy) {
47811 this.dropZone.destroy();
47816 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
47817 getName: function() {
47821 /** Loads the View from a JSON string representing the Records to put into the Store. */
47822 setValue: function(v) {
47824 throw "DDView.setValue(). DDView must be constructed with a valid Store";
47827 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
47828 this.store.proxy = new Roo.data.MemoryProxy(data);
47832 /** @return {String} a parenthesised list of the ids of the Records in the View. */
47833 getValue: function() {
47835 this.store.each(function(rec) {
47836 result += rec.id + ',';
47838 return result.substr(0, result.length - 1) + ')';
47841 getIds: function() {
47842 var i = 0, result = new Array(this.store.getCount());
47843 this.store.each(function(rec) {
47844 result[i++] = rec.id;
47849 isDirty: function() {
47850 return this.isDirtyFlag;
47854 * Part of the Roo.dd.DropZone interface. If no target node is found, the
47855 * whole Element becomes the target, and this causes the drop gesture to append.
47857 getTargetFromEvent : function(e) {
47858 var target = e.getTarget();
47859 while ((target !== null) && (target.parentNode != this.el.dom)) {
47860 target = target.parentNode;
47863 target = this.el.dom.lastChild || this.el.dom;
47869 * Create the drag data which consists of an object which has the property "ddel" as
47870 * the drag proxy element.
47872 getDragData : function(e) {
47873 var target = this.findItemFromChild(e.getTarget());
47875 this.handleSelection(e);
47876 var selNodes = this.getSelectedNodes();
47879 copy: this.copy || (this.allowCopy && e.ctrlKey),
47883 var selectedIndices = this.getSelectedIndexes();
47884 for (var i = 0; i < selectedIndices.length; i++) {
47885 dragData.records.push(this.store.getAt(selectedIndices[i]));
47887 if (selNodes.length == 1) {
47888 dragData.ddel = target.cloneNode(true); // the div element
47890 var div = document.createElement('div'); // create the multi element drag "ghost"
47891 div.className = 'multi-proxy';
47892 for (var i = 0, len = selNodes.length; i < len; i++) {
47893 div.appendChild(selNodes[i].cloneNode(true));
47895 dragData.ddel = div;
47897 //console.log(dragData)
47898 //console.log(dragData.ddel.innerHTML)
47901 //console.log('nodragData')
47905 /** Specify to which ddGroup items in this DDView may be dragged. */
47906 setDraggable: function(ddGroup) {
47907 if (ddGroup instanceof Array) {
47908 Roo.each(ddGroup, this.setDraggable, this);
47911 if (this.dragZone) {
47912 this.dragZone.addToGroup(ddGroup);
47914 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
47915 containerScroll: true,
47919 // Draggability implies selection. DragZone's mousedown selects the element.
47920 if (!this.multiSelect) { this.singleSelect = true; }
47922 // Wire the DragZone's handlers up to methods in *this*
47923 this.dragZone.getDragData = this.getDragData.createDelegate(this);
47927 /** Specify from which ddGroup this DDView accepts drops. */
47928 setDroppable: function(ddGroup) {
47929 if (ddGroup instanceof Array) {
47930 Roo.each(ddGroup, this.setDroppable, this);
47933 if (this.dropZone) {
47934 this.dropZone.addToGroup(ddGroup);
47936 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
47937 containerScroll: true,
47941 // Wire the DropZone's handlers up to methods in *this*
47942 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
47943 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
47944 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
47945 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
47946 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
47950 /** Decide whether to drop above or below a View node. */
47951 getDropPoint : function(e, n, dd){
47952 if (n == this.el.dom) { return "above"; }
47953 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
47954 var c = t + (b - t) / 2;
47955 var y = Roo.lib.Event.getPageY(e);
47963 onNodeEnter : function(n, dd, e, data){
47967 onNodeOver : function(n, dd, e, data){
47968 var pt = this.getDropPoint(e, n, dd);
47969 // set the insert point style on the target node
47970 var dragElClass = this.dropNotAllowed;
47973 if (pt == "above"){
47974 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
47975 targetElClass = "x-view-drag-insert-above";
47977 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
47978 targetElClass = "x-view-drag-insert-below";
47980 if (this.lastInsertClass != targetElClass){
47981 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
47982 this.lastInsertClass = targetElClass;
47985 return dragElClass;
47988 onNodeOut : function(n, dd, e, data){
47989 this.removeDropIndicators(n);
47992 onNodeDrop : function(n, dd, e, data){
47993 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
47996 var pt = this.getDropPoint(e, n, dd);
47997 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
47998 if (pt == "below") { insertAt++; }
47999 for (var i = 0; i < data.records.length; i++) {
48000 var r = data.records[i];
48001 var dup = this.store.getById(r.id);
48002 if (dup && (dd != this.dragZone)) {
48003 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48006 this.store.insert(insertAt++, r.copy());
48008 data.source.isDirtyFlag = true;
48010 this.store.insert(insertAt++, r);
48012 this.isDirtyFlag = true;
48015 this.dragZone.cachedTarget = null;
48019 removeDropIndicators : function(n){
48021 Roo.fly(n).removeClass([
48022 "x-view-drag-insert-above",
48023 "x-view-drag-insert-below"]);
48024 this.lastInsertClass = "_noclass";
48029 * Utility method. Add a delete option to the DDView's context menu.
48030 * @param {String} imageUrl The URL of the "delete" icon image.
48032 setDeletable: function(imageUrl) {
48033 if (!this.singleSelect && !this.multiSelect) {
48034 this.singleSelect = true;
48036 var c = this.getContextMenu();
48037 this.contextMenu.on("itemclick", function(item) {
48040 this.remove(this.getSelectedIndexes());
48044 this.contextMenu.add({
48051 /** Return the context menu for this DDView. */
48052 getContextMenu: function() {
48053 if (!this.contextMenu) {
48054 // Create the View's context menu
48055 this.contextMenu = new Roo.menu.Menu({
48056 id: this.id + "-contextmenu"
48058 this.el.on("contextmenu", this.showContextMenu, this);
48060 return this.contextMenu;
48063 disableContextMenu: function() {
48064 if (this.contextMenu) {
48065 this.el.un("contextmenu", this.showContextMenu, this);
48069 showContextMenu: function(e, item) {
48070 item = this.findItemFromChild(e.getTarget());
48073 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48074 this.contextMenu.showAt(e.getXY());
48079 * Remove {@link Roo.data.Record}s at the specified indices.
48080 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48082 remove: function(selectedIndices) {
48083 selectedIndices = [].concat(selectedIndices);
48084 for (var i = 0; i < selectedIndices.length; i++) {
48085 var rec = this.store.getAt(selectedIndices[i]);
48086 this.store.remove(rec);
48091 * Double click fires the event, but also, if this is draggable, and there is only one other
48092 * related DropZone, it transfers the selected node.
48094 onDblClick : function(e){
48095 var item = this.findItemFromChild(e.getTarget());
48097 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48100 if (this.dragGroup) {
48101 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48102 while (targets.indexOf(this.dropZone) > -1) {
48103 targets.remove(this.dropZone);
48105 if (targets.length == 1) {
48106 this.dragZone.cachedTarget = null;
48107 var el = Roo.get(targets[0].getEl());
48108 var box = el.getBox(true);
48109 targets[0].onNodeDrop(el.dom, {
48111 xy: [box.x, box.y + box.height - 1]
48112 }, null, this.getDragData(e));
48118 handleSelection: function(e) {
48119 this.dragZone.cachedTarget = null;
48120 var item = this.findItemFromChild(e.getTarget());
48122 this.clearSelections(true);
48125 if (item && (this.multiSelect || this.singleSelect)){
48126 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48127 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48128 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48129 this.unselect(item);
48131 this.select(item, this.multiSelect && e.ctrlKey);
48132 this.lastSelection = item;
48137 onItemClick : function(item, index, e){
48138 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48144 unselect : function(nodeInfo, suppressEvent){
48145 var node = this.getNode(nodeInfo);
48146 if(node && this.isSelected(node)){
48147 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48148 Roo.fly(node).removeClass(this.selectedClass);
48149 this.selections.remove(node);
48150 if(!suppressEvent){
48151 this.fireEvent("selectionchange", this, this.selections);
48159 * Ext JS Library 1.1.1
48160 * Copyright(c) 2006-2007, Ext JS, LLC.
48162 * Originally Released Under LGPL - original licence link has changed is not relivant.
48165 * <script type="text/javascript">
48169 * @class Roo.LayoutManager
48170 * @extends Roo.util.Observable
48171 * Base class for layout managers.
48173 Roo.LayoutManager = function(container, config){
48174 Roo.LayoutManager.superclass.constructor.call(this);
48175 this.el = Roo.get(container);
48176 // ie scrollbar fix
48177 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48178 document.body.scroll = "no";
48179 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48180 this.el.position('relative');
48182 this.id = this.el.id;
48183 this.el.addClass("x-layout-container");
48184 /** false to disable window resize monitoring @type Boolean */
48185 this.monitorWindowResize = true;
48190 * Fires when a layout is performed.
48191 * @param {Roo.LayoutManager} this
48195 * @event regionresized
48196 * Fires when the user resizes a region.
48197 * @param {Roo.LayoutRegion} region The resized region
48198 * @param {Number} newSize The new size (width for east/west, height for north/south)
48200 "regionresized" : true,
48202 * @event regioncollapsed
48203 * Fires when a region is collapsed.
48204 * @param {Roo.LayoutRegion} region The collapsed region
48206 "regioncollapsed" : true,
48208 * @event regionexpanded
48209 * Fires when a region is expanded.
48210 * @param {Roo.LayoutRegion} region The expanded region
48212 "regionexpanded" : true
48214 this.updating = false;
48215 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48218 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48220 * Returns true if this layout is currently being updated
48221 * @return {Boolean}
48223 isUpdating : function(){
48224 return this.updating;
48228 * Suspend the LayoutManager from doing auto-layouts while
48229 * making multiple add or remove calls
48231 beginUpdate : function(){
48232 this.updating = true;
48236 * Restore auto-layouts and optionally disable the manager from performing a layout
48237 * @param {Boolean} noLayout true to disable a layout update
48239 endUpdate : function(noLayout){
48240 this.updating = false;
48246 layout: function(){
48250 onRegionResized : function(region, newSize){
48251 this.fireEvent("regionresized", region, newSize);
48255 onRegionCollapsed : function(region){
48256 this.fireEvent("regioncollapsed", region);
48259 onRegionExpanded : function(region){
48260 this.fireEvent("regionexpanded", region);
48264 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48265 * performs box-model adjustments.
48266 * @return {Object} The size as an object {width: (the width), height: (the height)}
48268 getViewSize : function(){
48270 if(this.el.dom != document.body){
48271 size = this.el.getSize();
48273 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48275 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48276 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48281 * Returns the Element this layout is bound to.
48282 * @return {Roo.Element}
48284 getEl : function(){
48289 * Returns the specified region.
48290 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48291 * @return {Roo.LayoutRegion}
48293 getRegion : function(target){
48294 return this.regions[target.toLowerCase()];
48297 onWindowResize : function(){
48298 if(this.monitorWindowResize){
48304 * Ext JS Library 1.1.1
48305 * Copyright(c) 2006-2007, Ext JS, LLC.
48307 * Originally Released Under LGPL - original licence link has changed is not relivant.
48310 * <script type="text/javascript">
48313 * @class Roo.BorderLayout
48314 * @extends Roo.LayoutManager
48315 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48316 * please see: <br><br>
48317 * <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>
48318 * <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>
48321 var layout = new Roo.BorderLayout(document.body, {
48355 preferredTabWidth: 150
48360 var CP = Roo.ContentPanel;
48362 layout.beginUpdate();
48363 layout.add("north", new CP("north", "North"));
48364 layout.add("south", new CP("south", {title: "South", closable: true}));
48365 layout.add("west", new CP("west", {title: "West"}));
48366 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48367 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48368 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48369 layout.getRegion("center").showPanel("center1");
48370 layout.endUpdate();
48373 <b>The container the layout is rendered into can be either the body element or any other element.
48374 If it is not the body element, the container needs to either be an absolute positioned element,
48375 or you will need to add "position:relative" to the css of the container. You will also need to specify
48376 the container size if it is not the body element.</b>
48379 * Create a new BorderLayout
48380 * @param {String/HTMLElement/Element} container The container this layout is bound to
48381 * @param {Object} config Configuration options
48383 Roo.BorderLayout = function(container, config){
48384 config = config || {};
48385 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48386 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48387 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48388 var target = this.factory.validRegions[i];
48389 if(config[target]){
48390 this.addRegion(target, config[target]);
48395 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48397 * Creates and adds a new region if it doesn't already exist.
48398 * @param {String} target The target region key (north, south, east, west or center).
48399 * @param {Object} config The regions config object
48400 * @return {BorderLayoutRegion} The new region
48402 addRegion : function(target, config){
48403 if(!this.regions[target]){
48404 var r = this.factory.create(target, this, config);
48405 this.bindRegion(target, r);
48407 return this.regions[target];
48411 bindRegion : function(name, r){
48412 this.regions[name] = r;
48413 r.on("visibilitychange", this.layout, this);
48414 r.on("paneladded", this.layout, this);
48415 r.on("panelremoved", this.layout, this);
48416 r.on("invalidated", this.layout, this);
48417 r.on("resized", this.onRegionResized, this);
48418 r.on("collapsed", this.onRegionCollapsed, this);
48419 r.on("expanded", this.onRegionExpanded, this);
48423 * Performs a layout update.
48425 layout : function(){
48426 if(this.updating) return;
48427 var size = this.getViewSize();
48428 var w = size.width;
48429 var h = size.height;
48434 //var x = 0, y = 0;
48436 var rs = this.regions;
48437 var north = rs["north"];
48438 var south = rs["south"];
48439 var west = rs["west"];
48440 var east = rs["east"];
48441 var center = rs["center"];
48442 //if(this.hideOnLayout){ // not supported anymore
48443 //c.el.setStyle("display", "none");
48445 if(north && north.isVisible()){
48446 var b = north.getBox();
48447 var m = north.getMargins();
48448 b.width = w - (m.left+m.right);
48451 centerY = b.height + b.y + m.bottom;
48452 centerH -= centerY;
48453 north.updateBox(this.safeBox(b));
48455 if(south && south.isVisible()){
48456 var b = south.getBox();
48457 var m = south.getMargins();
48458 b.width = w - (m.left+m.right);
48460 var totalHeight = (b.height + m.top + m.bottom);
48461 b.y = h - totalHeight + m.top;
48462 centerH -= totalHeight;
48463 south.updateBox(this.safeBox(b));
48465 if(west && west.isVisible()){
48466 var b = west.getBox();
48467 var m = west.getMargins();
48468 b.height = centerH - (m.top+m.bottom);
48470 b.y = centerY + m.top;
48471 var totalWidth = (b.width + m.left + m.right);
48472 centerX += totalWidth;
48473 centerW -= totalWidth;
48474 west.updateBox(this.safeBox(b));
48476 if(east && east.isVisible()){
48477 var b = east.getBox();
48478 var m = east.getMargins();
48479 b.height = centerH - (m.top+m.bottom);
48480 var totalWidth = (b.width + m.left + m.right);
48481 b.x = w - totalWidth + m.left;
48482 b.y = centerY + m.top;
48483 centerW -= totalWidth;
48484 east.updateBox(this.safeBox(b));
48487 var m = center.getMargins();
48489 x: centerX + m.left,
48490 y: centerY + m.top,
48491 width: centerW - (m.left+m.right),
48492 height: centerH - (m.top+m.bottom)
48494 //if(this.hideOnLayout){
48495 //center.el.setStyle("display", "block");
48497 center.updateBox(this.safeBox(centerBox));
48500 this.fireEvent("layout", this);
48504 safeBox : function(box){
48505 box.width = Math.max(0, box.width);
48506 box.height = Math.max(0, box.height);
48511 * Adds a ContentPanel (or subclass) to this layout.
48512 * @param {String} target The target region key (north, south, east, west or center).
48513 * @param {Roo.ContentPanel} panel The panel to add
48514 * @return {Roo.ContentPanel} The added panel
48516 add : function(target, panel){
48518 target = target.toLowerCase();
48519 return this.regions[target].add(panel);
48523 * Remove a ContentPanel (or subclass) to this layout.
48524 * @param {String} target The target region key (north, south, east, west or center).
48525 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48526 * @return {Roo.ContentPanel} The removed panel
48528 remove : function(target, panel){
48529 target = target.toLowerCase();
48530 return this.regions[target].remove(panel);
48534 * Searches all regions for a panel with the specified id
48535 * @param {String} panelId
48536 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48538 findPanel : function(panelId){
48539 var rs = this.regions;
48540 for(var target in rs){
48541 if(typeof rs[target] != "function"){
48542 var p = rs[target].getPanel(panelId);
48552 * Searches all regions for a panel with the specified id and activates (shows) it.
48553 * @param {String/ContentPanel} panelId The panels id or the panel itself
48554 * @return {Roo.ContentPanel} The shown panel or null
48556 showPanel : function(panelId) {
48557 var rs = this.regions;
48558 for(var target in rs){
48559 var r = rs[target];
48560 if(typeof r != "function"){
48561 if(r.hasPanel(panelId)){
48562 return r.showPanel(panelId);
48570 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48571 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48573 restoreState : function(provider){
48575 provider = Roo.state.Manager;
48577 var sm = new Roo.LayoutStateManager();
48578 sm.init(this, provider);
48582 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48583 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48584 * a valid ContentPanel config object. Example:
48586 // Create the main layout
48587 var layout = new Roo.BorderLayout('main-ct', {
48598 // Create and add multiple ContentPanels at once via configs
48601 id: 'source-files',
48603 title:'Ext Source Files',
48616 * @param {Object} regions An object containing ContentPanel configs by region name
48618 batchAdd : function(regions){
48619 this.beginUpdate();
48620 for(var rname in regions){
48621 var lr = this.regions[rname];
48623 this.addTypedPanels(lr, regions[rname]);
48630 addTypedPanels : function(lr, ps){
48631 if(typeof ps == 'string'){
48632 lr.add(new Roo.ContentPanel(ps));
48634 else if(ps instanceof Array){
48635 for(var i =0, len = ps.length; i < len; i++){
48636 this.addTypedPanels(lr, ps[i]);
48639 else if(!ps.events){ // raw config?
48641 delete ps.el; // prevent conflict
48642 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48644 else { // panel object assumed!
48649 * Adds a xtype elements to the layout.
48653 xtype : 'ContentPanel',
48660 xtype : 'NestedLayoutPanel',
48666 items : [ ... list of content panels or nested layout panels.. ]
48670 * @param {Object} cfg Xtype definition of item to add.
48672 addxtype : function(cfg)
48674 // basically accepts a pannel...
48675 // can accept a layout region..!?!?
48676 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48678 if (!cfg.xtype.match(/Panel$/)) {
48683 if (typeof(cfg.region) == 'undefined') {
48684 Roo.log("Failed to add Panel, region was not set");
48688 var region = cfg.region;
48694 xitems = cfg.items;
48701 case 'ContentPanel': // ContentPanel (el, cfg)
48702 case 'ScrollPanel': // ContentPanel (el, cfg)
48704 if(cfg.autoCreate) {
48705 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48707 var el = this.el.createChild();
48708 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48711 this.add(region, ret);
48715 case 'TreePanel': // our new panel!
48716 cfg.el = this.el.createChild();
48717 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48718 this.add(region, ret);
48721 case 'NestedLayoutPanel':
48722 // create a new Layout (which is a Border Layout...
48723 var el = this.el.createChild();
48724 var clayout = cfg.layout;
48726 clayout.items = clayout.items || [];
48727 // replace this exitems with the clayout ones..
48728 xitems = clayout.items;
48731 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
48732 cfg.background = false;
48734 var layout = new Roo.BorderLayout(el, clayout);
48736 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
48737 //console.log('adding nested layout panel ' + cfg.toSource());
48738 this.add(region, ret);
48739 nb = {}; /// find first...
48744 // needs grid and region
48746 //var el = this.getRegion(region).el.createChild();
48747 var el = this.el.createChild();
48748 // create the grid first...
48750 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
48752 if (region == 'center' && this.active ) {
48753 cfg.background = false;
48755 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
48757 this.add(region, ret);
48758 if (cfg.background) {
48759 ret.on('activate', function(gp) {
48760 if (!gp.grid.rendered) {
48775 if (typeof(Roo[cfg.xtype]) != 'undefined') {
48777 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48778 this.add(region, ret);
48781 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
48785 // GridPanel (grid, cfg)
48788 this.beginUpdate();
48792 Roo.each(xitems, function(i) {
48793 region = nb && i.region ? i.region : false;
48795 var add = ret.addxtype(i);
48798 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
48799 if (!i.background) {
48800 abn[region] = nb[region] ;
48807 // make the last non-background panel active..
48808 //if (nb) { Roo.log(abn); }
48811 for(var r in abn) {
48812 region = this.getRegion(r);
48814 // tried using nb[r], but it does not work..
48816 region.showPanel(abn[r]);
48827 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
48828 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
48829 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
48830 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
48833 var CP = Roo.ContentPanel;
48835 var layout = Roo.BorderLayout.create({
48839 panels: [new CP("north", "North")]
48848 panels: [new CP("west", {title: "West"})]
48857 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
48866 panels: [new CP("south", {title: "South", closable: true})]
48873 preferredTabWidth: 150,
48875 new CP("center1", {title: "Close Me", closable: true}),
48876 new CP("center2", {title: "Center Panel", closable: false})
48881 layout.getRegion("center").showPanel("center1");
48886 Roo.BorderLayout.create = function(config, targetEl){
48887 var layout = new Roo.BorderLayout(targetEl || document.body, config);
48888 layout.beginUpdate();
48889 var regions = Roo.BorderLayout.RegionFactory.validRegions;
48890 for(var j = 0, jlen = regions.length; j < jlen; j++){
48891 var lr = regions[j];
48892 if(layout.regions[lr] && config[lr].panels){
48893 var r = layout.regions[lr];
48894 var ps = config[lr].panels;
48895 layout.addTypedPanels(r, ps);
48898 layout.endUpdate();
48903 Roo.BorderLayout.RegionFactory = {
48905 validRegions : ["north","south","east","west","center"],
48908 create : function(target, mgr, config){
48909 target = target.toLowerCase();
48910 if(config.lightweight || config.basic){
48911 return new Roo.BasicLayoutRegion(mgr, config, target);
48915 return new Roo.NorthLayoutRegion(mgr, config);
48917 return new Roo.SouthLayoutRegion(mgr, config);
48919 return new Roo.EastLayoutRegion(mgr, config);
48921 return new Roo.WestLayoutRegion(mgr, config);
48923 return new Roo.CenterLayoutRegion(mgr, config);
48925 throw 'Layout region "'+target+'" not supported.';
48929 * Ext JS Library 1.1.1
48930 * Copyright(c) 2006-2007, Ext JS, LLC.
48932 * Originally Released Under LGPL - original licence link has changed is not relivant.
48935 * <script type="text/javascript">
48939 * @class Roo.BasicLayoutRegion
48940 * @extends Roo.util.Observable
48941 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
48942 * and does not have a titlebar, tabs or any other features. All it does is size and position
48943 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
48945 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
48947 this.position = pos;
48950 * @scope Roo.BasicLayoutRegion
48954 * @event beforeremove
48955 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
48956 * @param {Roo.LayoutRegion} this
48957 * @param {Roo.ContentPanel} panel The panel
48958 * @param {Object} e The cancel event object
48960 "beforeremove" : true,
48962 * @event invalidated
48963 * Fires when the layout for this region is changed.
48964 * @param {Roo.LayoutRegion} this
48966 "invalidated" : true,
48968 * @event visibilitychange
48969 * Fires when this region is shown or hidden
48970 * @param {Roo.LayoutRegion} this
48971 * @param {Boolean} visibility true or false
48973 "visibilitychange" : true,
48975 * @event paneladded
48976 * Fires when a panel is added.
48977 * @param {Roo.LayoutRegion} this
48978 * @param {Roo.ContentPanel} panel The panel
48980 "paneladded" : true,
48982 * @event panelremoved
48983 * Fires when a panel is removed.
48984 * @param {Roo.LayoutRegion} this
48985 * @param {Roo.ContentPanel} panel The panel
48987 "panelremoved" : true,
48990 * Fires when this region is collapsed.
48991 * @param {Roo.LayoutRegion} this
48993 "collapsed" : true,
48996 * Fires when this region is expanded.
48997 * @param {Roo.LayoutRegion} this
49002 * Fires when this region is slid into view.
49003 * @param {Roo.LayoutRegion} this
49005 "slideshow" : true,
49008 * Fires when this region slides out of view.
49009 * @param {Roo.LayoutRegion} this
49011 "slidehide" : true,
49013 * @event panelactivated
49014 * Fires when a panel is activated.
49015 * @param {Roo.LayoutRegion} this
49016 * @param {Roo.ContentPanel} panel The activated panel
49018 "panelactivated" : true,
49021 * Fires when the user resizes this region.
49022 * @param {Roo.LayoutRegion} this
49023 * @param {Number} newSize The new size (width for east/west, height for north/south)
49027 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49028 this.panels = new Roo.util.MixedCollection();
49029 this.panels.getKey = this.getPanelId.createDelegate(this);
49031 this.activePanel = null;
49032 // ensure listeners are added...
49034 if (config.listeners || config.events) {
49035 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49036 listeners : config.listeners || {},
49037 events : config.events || {}
49041 if(skipConfig !== true){
49042 this.applyConfig(config);
49046 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49047 getPanelId : function(p){
49051 applyConfig : function(config){
49052 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49053 this.config = config;
49058 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49059 * the width, for horizontal (north, south) the height.
49060 * @param {Number} newSize The new width or height
49062 resizeTo : function(newSize){
49063 var el = this.el ? this.el :
49064 (this.activePanel ? this.activePanel.getEl() : null);
49066 switch(this.position){
49069 el.setWidth(newSize);
49070 this.fireEvent("resized", this, newSize);
49074 el.setHeight(newSize);
49075 this.fireEvent("resized", this, newSize);
49081 getBox : function(){
49082 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49085 getMargins : function(){
49086 return this.margins;
49089 updateBox : function(box){
49091 var el = this.activePanel.getEl();
49092 el.dom.style.left = box.x + "px";
49093 el.dom.style.top = box.y + "px";
49094 this.activePanel.setSize(box.width, box.height);
49098 * Returns the container element for this region.
49099 * @return {Roo.Element}
49101 getEl : function(){
49102 return this.activePanel;
49106 * Returns true if this region is currently visible.
49107 * @return {Boolean}
49109 isVisible : function(){
49110 return this.activePanel ? true : false;
49113 setActivePanel : function(panel){
49114 panel = this.getPanel(panel);
49115 if(this.activePanel && this.activePanel != panel){
49116 this.activePanel.setActiveState(false);
49117 this.activePanel.getEl().setLeftTop(-10000,-10000);
49119 this.activePanel = panel;
49120 panel.setActiveState(true);
49122 panel.setSize(this.box.width, this.box.height);
49124 this.fireEvent("panelactivated", this, panel);
49125 this.fireEvent("invalidated");
49129 * Show the specified panel.
49130 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49131 * @return {Roo.ContentPanel} The shown panel or null
49133 showPanel : function(panel){
49134 if(panel = this.getPanel(panel)){
49135 this.setActivePanel(panel);
49141 * Get the active panel for this region.
49142 * @return {Roo.ContentPanel} The active panel or null
49144 getActivePanel : function(){
49145 return this.activePanel;
49149 * Add the passed ContentPanel(s)
49150 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49151 * @return {Roo.ContentPanel} The panel added (if only one was added)
49153 add : function(panel){
49154 if(arguments.length > 1){
49155 for(var i = 0, len = arguments.length; i < len; i++) {
49156 this.add(arguments[i]);
49160 if(this.hasPanel(panel)){
49161 this.showPanel(panel);
49164 var el = panel.getEl();
49165 if(el.dom.parentNode != this.mgr.el.dom){
49166 this.mgr.el.dom.appendChild(el.dom);
49168 if(panel.setRegion){
49169 panel.setRegion(this);
49171 this.panels.add(panel);
49172 el.setStyle("position", "absolute");
49173 if(!panel.background){
49174 this.setActivePanel(panel);
49175 if(this.config.initialSize && this.panels.getCount()==1){
49176 this.resizeTo(this.config.initialSize);
49179 this.fireEvent("paneladded", this, panel);
49184 * Returns true if the panel is in this region.
49185 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49186 * @return {Boolean}
49188 hasPanel : function(panel){
49189 if(typeof panel == "object"){ // must be panel obj
49190 panel = panel.getId();
49192 return this.getPanel(panel) ? true : false;
49196 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49197 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49198 * @param {Boolean} preservePanel Overrides the config preservePanel option
49199 * @return {Roo.ContentPanel} The panel that was removed
49201 remove : function(panel, preservePanel){
49202 panel = this.getPanel(panel);
49207 this.fireEvent("beforeremove", this, panel, e);
49208 if(e.cancel === true){
49211 var panelId = panel.getId();
49212 this.panels.removeKey(panelId);
49217 * Returns the panel specified or null if it's not in this region.
49218 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49219 * @return {Roo.ContentPanel}
49221 getPanel : function(id){
49222 if(typeof id == "object"){ // must be panel obj
49225 return this.panels.get(id);
49229 * Returns this regions position (north/south/east/west/center).
49232 getPosition: function(){
49233 return this.position;
49237 * Ext JS Library 1.1.1
49238 * Copyright(c) 2006-2007, Ext JS, LLC.
49240 * Originally Released Under LGPL - original licence link has changed is not relivant.
49243 * <script type="text/javascript">
49247 * @class Roo.LayoutRegion
49248 * @extends Roo.BasicLayoutRegion
49249 * This class represents a region in a layout manager.
49250 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49251 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49252 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49253 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49254 * @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})
49255 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49256 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49257 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49258 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49259 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49260 * @cfg {String} title The title for the region (overrides panel titles)
49261 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49262 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49263 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49264 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49265 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49266 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49267 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49268 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49269 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49270 * @cfg {Boolean} showPin True to show a pin button
49271 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49272 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49273 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49274 * @cfg {Number} width For East/West panels
49275 * @cfg {Number} height For North/South panels
49276 * @cfg {Boolean} split To show the splitter
49277 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49279 Roo.LayoutRegion = function(mgr, config, pos){
49280 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49281 var dh = Roo.DomHelper;
49282 /** This region's container element
49283 * @type Roo.Element */
49284 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49285 /** This region's title element
49286 * @type Roo.Element */
49288 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49289 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49290 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49292 this.titleEl.enableDisplayMode();
49293 /** This region's title text element
49294 * @type HTMLElement */
49295 this.titleTextEl = this.titleEl.dom.firstChild;
49296 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49297 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49298 this.closeBtn.enableDisplayMode();
49299 this.closeBtn.on("click", this.closeClicked, this);
49300 this.closeBtn.hide();
49302 this.createBody(config);
49303 this.visible = true;
49304 this.collapsed = false;
49306 if(config.hideWhenEmpty){
49308 this.on("paneladded", this.validateVisibility, this);
49309 this.on("panelremoved", this.validateVisibility, this);
49311 this.applyConfig(config);
49314 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49316 createBody : function(){
49317 /** This region's body element
49318 * @type Roo.Element */
49319 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49322 applyConfig : function(c){
49323 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49324 var dh = Roo.DomHelper;
49325 if(c.titlebar !== false){
49326 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49327 this.collapseBtn.on("click", this.collapse, this);
49328 this.collapseBtn.enableDisplayMode();
49330 if(c.showPin === true || this.showPin){
49331 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49332 this.stickBtn.enableDisplayMode();
49333 this.stickBtn.on("click", this.expand, this);
49334 this.stickBtn.hide();
49337 /** This region's collapsed element
49338 * @type Roo.Element */
49339 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49340 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49342 if(c.floatable !== false){
49343 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49344 this.collapsedEl.on("click", this.collapseClick, this);
49347 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49348 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49349 id: "message", unselectable: "on", style:{"float":"left"}});
49350 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49352 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49353 this.expandBtn.on("click", this.expand, this);
49355 if(this.collapseBtn){
49356 this.collapseBtn.setVisible(c.collapsible == true);
49358 this.cmargins = c.cmargins || this.cmargins ||
49359 (this.position == "west" || this.position == "east" ?
49360 {top: 0, left: 2, right:2, bottom: 0} :
49361 {top: 2, left: 0, right:0, bottom: 2});
49362 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49363 this.bottomTabs = c.tabPosition != "top";
49364 this.autoScroll = c.autoScroll || false;
49365 if(this.autoScroll){
49366 this.bodyEl.setStyle("overflow", "auto");
49368 this.bodyEl.setStyle("overflow", "hidden");
49370 //if(c.titlebar !== false){
49371 if((!c.titlebar && !c.title) || c.titlebar === false){
49372 this.titleEl.hide();
49374 this.titleEl.show();
49376 this.titleTextEl.innerHTML = c.title;
49380 this.duration = c.duration || .30;
49381 this.slideDuration = c.slideDuration || .45;
49384 this.collapse(true);
49391 * Returns true if this region is currently visible.
49392 * @return {Boolean}
49394 isVisible : function(){
49395 return this.visible;
49399 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49400 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49402 setCollapsedTitle : function(title){
49403 title = title || " ";
49404 if(this.collapsedTitleTextEl){
49405 this.collapsedTitleTextEl.innerHTML = title;
49409 getBox : function(){
49411 if(!this.collapsed){
49412 b = this.el.getBox(false, true);
49414 b = this.collapsedEl.getBox(false, true);
49419 getMargins : function(){
49420 return this.collapsed ? this.cmargins : this.margins;
49423 highlight : function(){
49424 this.el.addClass("x-layout-panel-dragover");
49427 unhighlight : function(){
49428 this.el.removeClass("x-layout-panel-dragover");
49431 updateBox : function(box){
49433 if(!this.collapsed){
49434 this.el.dom.style.left = box.x + "px";
49435 this.el.dom.style.top = box.y + "px";
49436 this.updateBody(box.width, box.height);
49438 this.collapsedEl.dom.style.left = box.x + "px";
49439 this.collapsedEl.dom.style.top = box.y + "px";
49440 this.collapsedEl.setSize(box.width, box.height);
49443 this.tabs.autoSizeTabs();
49447 updateBody : function(w, h){
49449 this.el.setWidth(w);
49450 w -= this.el.getBorderWidth("rl");
49451 if(this.config.adjustments){
49452 w += this.config.adjustments[0];
49456 this.el.setHeight(h);
49457 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49458 h -= this.el.getBorderWidth("tb");
49459 if(this.config.adjustments){
49460 h += this.config.adjustments[1];
49462 this.bodyEl.setHeight(h);
49464 h = this.tabs.syncHeight(h);
49467 if(this.panelSize){
49468 w = w !== null ? w : this.panelSize.width;
49469 h = h !== null ? h : this.panelSize.height;
49471 if(this.activePanel){
49472 var el = this.activePanel.getEl();
49473 w = w !== null ? w : el.getWidth();
49474 h = h !== null ? h : el.getHeight();
49475 this.panelSize = {width: w, height: h};
49476 this.activePanel.setSize(w, h);
49478 if(Roo.isIE && this.tabs){
49479 this.tabs.el.repaint();
49484 * Returns the container element for this region.
49485 * @return {Roo.Element}
49487 getEl : function(){
49492 * Hides this region.
49495 if(!this.collapsed){
49496 this.el.dom.style.left = "-2000px";
49499 this.collapsedEl.dom.style.left = "-2000px";
49500 this.collapsedEl.hide();
49502 this.visible = false;
49503 this.fireEvent("visibilitychange", this, false);
49507 * Shows this region if it was previously hidden.
49510 if(!this.collapsed){
49513 this.collapsedEl.show();
49515 this.visible = true;
49516 this.fireEvent("visibilitychange", this, true);
49519 closeClicked : function(){
49520 if(this.activePanel){
49521 this.remove(this.activePanel);
49525 collapseClick : function(e){
49527 e.stopPropagation();
49530 e.stopPropagation();
49536 * Collapses this region.
49537 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49539 collapse : function(skipAnim){
49540 if(this.collapsed) return;
49541 this.collapsed = true;
49543 this.split.el.hide();
49545 if(this.config.animate && skipAnim !== true){
49546 this.fireEvent("invalidated", this);
49547 this.animateCollapse();
49549 this.el.setLocation(-20000,-20000);
49551 this.collapsedEl.show();
49552 this.fireEvent("collapsed", this);
49553 this.fireEvent("invalidated", this);
49557 animateCollapse : function(){
49562 * Expands this region if it was previously collapsed.
49563 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49564 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49566 expand : function(e, skipAnim){
49567 if(e) e.stopPropagation();
49568 if(!this.collapsed || this.el.hasActiveFx()) return;
49570 this.afterSlideIn();
49573 this.collapsed = false;
49574 if(this.config.animate && skipAnim !== true){
49575 this.animateExpand();
49579 this.split.el.show();
49581 this.collapsedEl.setLocation(-2000,-2000);
49582 this.collapsedEl.hide();
49583 this.fireEvent("invalidated", this);
49584 this.fireEvent("expanded", this);
49588 animateExpand : function(){
49592 initTabs : function()
49594 this.bodyEl.setStyle("overflow", "hidden");
49595 var ts = new Roo.TabPanel(
49598 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49599 disableTooltips: this.config.disableTabTips,
49600 toolbar : this.config.toolbar
49603 if(this.config.hideTabs){
49604 ts.stripWrap.setDisplayed(false);
49607 ts.resizeTabs = this.config.resizeTabs === true;
49608 ts.minTabWidth = this.config.minTabWidth || 40;
49609 ts.maxTabWidth = this.config.maxTabWidth || 250;
49610 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49611 ts.monitorResize = false;
49612 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49613 ts.bodyEl.addClass('x-layout-tabs-body');
49614 this.panels.each(this.initPanelAsTab, this);
49617 initPanelAsTab : function(panel){
49618 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49619 this.config.closeOnTab && panel.isClosable());
49620 if(panel.tabTip !== undefined){
49621 ti.setTooltip(panel.tabTip);
49623 ti.on("activate", function(){
49624 this.setActivePanel(panel);
49626 if(this.config.closeOnTab){
49627 ti.on("beforeclose", function(t, e){
49629 this.remove(panel);
49635 updatePanelTitle : function(panel, title){
49636 if(this.activePanel == panel){
49637 this.updateTitle(title);
49640 var ti = this.tabs.getTab(panel.getEl().id);
49642 if(panel.tabTip !== undefined){
49643 ti.setTooltip(panel.tabTip);
49648 updateTitle : function(title){
49649 if(this.titleTextEl && !this.config.title){
49650 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49654 setActivePanel : function(panel){
49655 panel = this.getPanel(panel);
49656 if(this.activePanel && this.activePanel != panel){
49657 this.activePanel.setActiveState(false);
49659 this.activePanel = panel;
49660 panel.setActiveState(true);
49661 if(this.panelSize){
49662 panel.setSize(this.panelSize.width, this.panelSize.height);
49665 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49667 this.updateTitle(panel.getTitle());
49669 this.fireEvent("invalidated", this);
49671 this.fireEvent("panelactivated", this, panel);
49675 * Shows the specified panel.
49676 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49677 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49679 showPanel : function(panel){
49680 if(panel = this.getPanel(panel)){
49682 var tab = this.tabs.getTab(panel.getEl().id);
49683 if(tab.isHidden()){
49684 this.tabs.unhideTab(tab.id);
49688 this.setActivePanel(panel);
49695 * Get the active panel for this region.
49696 * @return {Roo.ContentPanel} The active panel or null
49698 getActivePanel : function(){
49699 return this.activePanel;
49702 validateVisibility : function(){
49703 if(this.panels.getCount() < 1){
49704 this.updateTitle(" ");
49705 this.closeBtn.hide();
49708 if(!this.isVisible()){
49715 * Adds the passed ContentPanel(s) to this region.
49716 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49717 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49719 add : function(panel){
49720 if(arguments.length > 1){
49721 for(var i = 0, len = arguments.length; i < len; i++) {
49722 this.add(arguments[i]);
49726 if(this.hasPanel(panel)){
49727 this.showPanel(panel);
49730 panel.setRegion(this);
49731 this.panels.add(panel);
49732 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
49733 this.bodyEl.dom.appendChild(panel.getEl().dom);
49734 if(panel.background !== true){
49735 this.setActivePanel(panel);
49737 this.fireEvent("paneladded", this, panel);
49743 this.initPanelAsTab(panel);
49745 if(panel.background !== true){
49746 this.tabs.activate(panel.getEl().id);
49748 this.fireEvent("paneladded", this, panel);
49753 * Hides the tab for the specified panel.
49754 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49756 hidePanel : function(panel){
49757 if(this.tabs && (panel = this.getPanel(panel))){
49758 this.tabs.hideTab(panel.getEl().id);
49763 * Unhides the tab for a previously hidden panel.
49764 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49766 unhidePanel : function(panel){
49767 if(this.tabs && (panel = this.getPanel(panel))){
49768 this.tabs.unhideTab(panel.getEl().id);
49772 clearPanels : function(){
49773 while(this.panels.getCount() > 0){
49774 this.remove(this.panels.first());
49779 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49780 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49781 * @param {Boolean} preservePanel Overrides the config preservePanel option
49782 * @return {Roo.ContentPanel} The panel that was removed
49784 remove : function(panel, preservePanel){
49785 panel = this.getPanel(panel);
49790 this.fireEvent("beforeremove", this, panel, e);
49791 if(e.cancel === true){
49794 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
49795 var panelId = panel.getId();
49796 this.panels.removeKey(panelId);
49798 document.body.appendChild(panel.getEl().dom);
49801 this.tabs.removeTab(panel.getEl().id);
49802 }else if (!preservePanel){
49803 this.bodyEl.dom.removeChild(panel.getEl().dom);
49805 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
49806 var p = this.panels.first();
49807 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
49808 tempEl.appendChild(p.getEl().dom);
49809 this.bodyEl.update("");
49810 this.bodyEl.dom.appendChild(p.getEl().dom);
49812 this.updateTitle(p.getTitle());
49814 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49815 this.setActivePanel(p);
49817 panel.setRegion(null);
49818 if(this.activePanel == panel){
49819 this.activePanel = null;
49821 if(this.config.autoDestroy !== false && preservePanel !== true){
49822 try{panel.destroy();}catch(e){}
49824 this.fireEvent("panelremoved", this, panel);
49829 * Returns the TabPanel component used by this region
49830 * @return {Roo.TabPanel}
49832 getTabs : function(){
49836 createTool : function(parentEl, className){
49837 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
49838 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
49839 btn.addClassOnOver("x-layout-tools-button-over");
49844 * Ext JS Library 1.1.1
49845 * Copyright(c) 2006-2007, Ext JS, LLC.
49847 * Originally Released Under LGPL - original licence link has changed is not relivant.
49850 * <script type="text/javascript">
49856 * @class Roo.SplitLayoutRegion
49857 * @extends Roo.LayoutRegion
49858 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
49860 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
49861 this.cursor = cursor;
49862 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
49865 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
49866 splitTip : "Drag to resize.",
49867 collapsibleSplitTip : "Drag to resize. Double click to hide.",
49868 useSplitTips : false,
49870 applyConfig : function(config){
49871 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
49874 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
49875 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
49876 /** The SplitBar for this region
49877 * @type Roo.SplitBar */
49878 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
49879 this.split.on("moved", this.onSplitMove, this);
49880 this.split.useShim = config.useShim === true;
49881 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
49882 if(this.useSplitTips){
49883 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
49885 if(config.collapsible){
49886 this.split.el.on("dblclick", this.collapse, this);
49889 if(typeof config.minSize != "undefined"){
49890 this.split.minSize = config.minSize;
49892 if(typeof config.maxSize != "undefined"){
49893 this.split.maxSize = config.maxSize;
49895 if(config.hideWhenEmpty || config.hidden || config.collapsed){
49896 this.hideSplitter();
49901 getHMaxSize : function(){
49902 var cmax = this.config.maxSize || 10000;
49903 var center = this.mgr.getRegion("center");
49904 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
49907 getVMaxSize : function(){
49908 var cmax = this.config.maxSize || 10000;
49909 var center = this.mgr.getRegion("center");
49910 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
49913 onSplitMove : function(split, newSize){
49914 this.fireEvent("resized", this, newSize);
49918 * Returns the {@link Roo.SplitBar} for this region.
49919 * @return {Roo.SplitBar}
49921 getSplitBar : function(){
49926 this.hideSplitter();
49927 Roo.SplitLayoutRegion.superclass.hide.call(this);
49930 hideSplitter : function(){
49932 this.split.el.setLocation(-2000,-2000);
49933 this.split.el.hide();
49939 this.split.el.show();
49941 Roo.SplitLayoutRegion.superclass.show.call(this);
49944 beforeSlide: function(){
49945 if(Roo.isGecko){// firefox overflow auto bug workaround
49946 this.bodyEl.clip();
49947 if(this.tabs) this.tabs.bodyEl.clip();
49948 if(this.activePanel){
49949 this.activePanel.getEl().clip();
49951 if(this.activePanel.beforeSlide){
49952 this.activePanel.beforeSlide();
49958 afterSlide : function(){
49959 if(Roo.isGecko){// firefox overflow auto bug workaround
49960 this.bodyEl.unclip();
49961 if(this.tabs) this.tabs.bodyEl.unclip();
49962 if(this.activePanel){
49963 this.activePanel.getEl().unclip();
49964 if(this.activePanel.afterSlide){
49965 this.activePanel.afterSlide();
49971 initAutoHide : function(){
49972 if(this.autoHide !== false){
49973 if(!this.autoHideHd){
49974 var st = new Roo.util.DelayedTask(this.slideIn, this);
49975 this.autoHideHd = {
49976 "mouseout": function(e){
49977 if(!e.within(this.el, true)){
49981 "mouseover" : function(e){
49987 this.el.on(this.autoHideHd);
49991 clearAutoHide : function(){
49992 if(this.autoHide !== false){
49993 this.el.un("mouseout", this.autoHideHd.mouseout);
49994 this.el.un("mouseover", this.autoHideHd.mouseover);
49998 clearMonitor : function(){
49999 Roo.get(document).un("click", this.slideInIf, this);
50002 // these names are backwards but not changed for compat
50003 slideOut : function(){
50004 if(this.isSlid || this.el.hasActiveFx()){
50007 this.isSlid = true;
50008 if(this.collapseBtn){
50009 this.collapseBtn.hide();
50011 this.closeBtnState = this.closeBtn.getStyle('display');
50012 this.closeBtn.hide();
50014 this.stickBtn.show();
50017 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50018 this.beforeSlide();
50019 this.el.setStyle("z-index", 10001);
50020 this.el.slideIn(this.getSlideAnchor(), {
50021 callback: function(){
50023 this.initAutoHide();
50024 Roo.get(document).on("click", this.slideInIf, this);
50025 this.fireEvent("slideshow", this);
50032 afterSlideIn : function(){
50033 this.clearAutoHide();
50034 this.isSlid = false;
50035 this.clearMonitor();
50036 this.el.setStyle("z-index", "");
50037 if(this.collapseBtn){
50038 this.collapseBtn.show();
50040 this.closeBtn.setStyle('display', this.closeBtnState);
50042 this.stickBtn.hide();
50044 this.fireEvent("slidehide", this);
50047 slideIn : function(cb){
50048 if(!this.isSlid || this.el.hasActiveFx()){
50052 this.isSlid = false;
50053 this.beforeSlide();
50054 this.el.slideOut(this.getSlideAnchor(), {
50055 callback: function(){
50056 this.el.setLeftTop(-10000, -10000);
50058 this.afterSlideIn();
50066 slideInIf : function(e){
50067 if(!e.within(this.el)){
50072 animateCollapse : function(){
50073 this.beforeSlide();
50074 this.el.setStyle("z-index", 20000);
50075 var anchor = this.getSlideAnchor();
50076 this.el.slideOut(anchor, {
50077 callback : function(){
50078 this.el.setStyle("z-index", "");
50079 this.collapsedEl.slideIn(anchor, {duration:.3});
50081 this.el.setLocation(-10000,-10000);
50083 this.fireEvent("collapsed", this);
50090 animateExpand : function(){
50091 this.beforeSlide();
50092 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50093 this.el.setStyle("z-index", 20000);
50094 this.collapsedEl.hide({
50097 this.el.slideIn(this.getSlideAnchor(), {
50098 callback : function(){
50099 this.el.setStyle("z-index", "");
50102 this.split.el.show();
50104 this.fireEvent("invalidated", this);
50105 this.fireEvent("expanded", this);
50133 getAnchor : function(){
50134 return this.anchors[this.position];
50137 getCollapseAnchor : function(){
50138 return this.canchors[this.position];
50141 getSlideAnchor : function(){
50142 return this.sanchors[this.position];
50145 getAlignAdj : function(){
50146 var cm = this.cmargins;
50147 switch(this.position){
50163 getExpandAdj : function(){
50164 var c = this.collapsedEl, cm = this.cmargins;
50165 switch(this.position){
50167 return [-(cm.right+c.getWidth()+cm.left), 0];
50170 return [cm.right+c.getWidth()+cm.left, 0];
50173 return [0, -(cm.top+cm.bottom+c.getHeight())];
50176 return [0, cm.top+cm.bottom+c.getHeight()];
50182 * Ext JS Library 1.1.1
50183 * Copyright(c) 2006-2007, Ext JS, LLC.
50185 * Originally Released Under LGPL - original licence link has changed is not relivant.
50188 * <script type="text/javascript">
50191 * These classes are private internal classes
50193 Roo.CenterLayoutRegion = function(mgr, config){
50194 Roo.LayoutRegion.call(this, mgr, config, "center");
50195 this.visible = true;
50196 this.minWidth = config.minWidth || 20;
50197 this.minHeight = config.minHeight || 20;
50200 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50202 // center panel can't be hidden
50206 // center panel can't be hidden
50209 getMinWidth: function(){
50210 return this.minWidth;
50213 getMinHeight: function(){
50214 return this.minHeight;
50219 Roo.NorthLayoutRegion = function(mgr, config){
50220 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50222 this.split.placement = Roo.SplitBar.TOP;
50223 this.split.orientation = Roo.SplitBar.VERTICAL;
50224 this.split.el.addClass("x-layout-split-v");
50226 var size = config.initialSize || config.height;
50227 if(typeof size != "undefined"){
50228 this.el.setHeight(size);
50231 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50232 orientation: Roo.SplitBar.VERTICAL,
50233 getBox : function(){
50234 if(this.collapsed){
50235 return this.collapsedEl.getBox();
50237 var box = this.el.getBox();
50239 box.height += this.split.el.getHeight();
50244 updateBox : function(box){
50245 if(this.split && !this.collapsed){
50246 box.height -= this.split.el.getHeight();
50247 this.split.el.setLeft(box.x);
50248 this.split.el.setTop(box.y+box.height);
50249 this.split.el.setWidth(box.width);
50251 if(this.collapsed){
50252 this.updateBody(box.width, null);
50254 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50258 Roo.SouthLayoutRegion = function(mgr, config){
50259 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50261 this.split.placement = Roo.SplitBar.BOTTOM;
50262 this.split.orientation = Roo.SplitBar.VERTICAL;
50263 this.split.el.addClass("x-layout-split-v");
50265 var size = config.initialSize || config.height;
50266 if(typeof size != "undefined"){
50267 this.el.setHeight(size);
50270 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50271 orientation: Roo.SplitBar.VERTICAL,
50272 getBox : function(){
50273 if(this.collapsed){
50274 return this.collapsedEl.getBox();
50276 var box = this.el.getBox();
50278 var sh = this.split.el.getHeight();
50285 updateBox : function(box){
50286 if(this.split && !this.collapsed){
50287 var sh = this.split.el.getHeight();
50290 this.split.el.setLeft(box.x);
50291 this.split.el.setTop(box.y-sh);
50292 this.split.el.setWidth(box.width);
50294 if(this.collapsed){
50295 this.updateBody(box.width, null);
50297 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50301 Roo.EastLayoutRegion = function(mgr, config){
50302 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50304 this.split.placement = Roo.SplitBar.RIGHT;
50305 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50306 this.split.el.addClass("x-layout-split-h");
50308 var size = config.initialSize || config.width;
50309 if(typeof size != "undefined"){
50310 this.el.setWidth(size);
50313 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50314 orientation: Roo.SplitBar.HORIZONTAL,
50315 getBox : function(){
50316 if(this.collapsed){
50317 return this.collapsedEl.getBox();
50319 var box = this.el.getBox();
50321 var sw = this.split.el.getWidth();
50328 updateBox : function(box){
50329 if(this.split && !this.collapsed){
50330 var sw = this.split.el.getWidth();
50332 this.split.el.setLeft(box.x);
50333 this.split.el.setTop(box.y);
50334 this.split.el.setHeight(box.height);
50337 if(this.collapsed){
50338 this.updateBody(null, box.height);
50340 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50344 Roo.WestLayoutRegion = function(mgr, config){
50345 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50347 this.split.placement = Roo.SplitBar.LEFT;
50348 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50349 this.split.el.addClass("x-layout-split-h");
50351 var size = config.initialSize || config.width;
50352 if(typeof size != "undefined"){
50353 this.el.setWidth(size);
50356 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50357 orientation: Roo.SplitBar.HORIZONTAL,
50358 getBox : function(){
50359 if(this.collapsed){
50360 return this.collapsedEl.getBox();
50362 var box = this.el.getBox();
50364 box.width += this.split.el.getWidth();
50369 updateBox : function(box){
50370 if(this.split && !this.collapsed){
50371 var sw = this.split.el.getWidth();
50373 this.split.el.setLeft(box.x+box.width);
50374 this.split.el.setTop(box.y);
50375 this.split.el.setHeight(box.height);
50377 if(this.collapsed){
50378 this.updateBody(null, box.height);
50380 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50385 * Ext JS Library 1.1.1
50386 * Copyright(c) 2006-2007, Ext JS, LLC.
50388 * Originally Released Under LGPL - original licence link has changed is not relivant.
50391 * <script type="text/javascript">
50396 * Private internal class for reading and applying state
50398 Roo.LayoutStateManager = function(layout){
50399 // default empty state
50408 Roo.LayoutStateManager.prototype = {
50409 init : function(layout, provider){
50410 this.provider = provider;
50411 var state = provider.get(layout.id+"-layout-state");
50413 var wasUpdating = layout.isUpdating();
50415 layout.beginUpdate();
50417 for(var key in state){
50418 if(typeof state[key] != "function"){
50419 var rstate = state[key];
50420 var r = layout.getRegion(key);
50423 r.resizeTo(rstate.size);
50425 if(rstate.collapsed == true){
50428 r.expand(null, true);
50434 layout.endUpdate();
50436 this.state = state;
50438 this.layout = layout;
50439 layout.on("regionresized", this.onRegionResized, this);
50440 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50441 layout.on("regionexpanded", this.onRegionExpanded, this);
50444 storeState : function(){
50445 this.provider.set(this.layout.id+"-layout-state", this.state);
50448 onRegionResized : function(region, newSize){
50449 this.state[region.getPosition()].size = newSize;
50453 onRegionCollapsed : function(region){
50454 this.state[region.getPosition()].collapsed = true;
50458 onRegionExpanded : function(region){
50459 this.state[region.getPosition()].collapsed = false;
50464 * Ext JS Library 1.1.1
50465 * Copyright(c) 2006-2007, Ext JS, LLC.
50467 * Originally Released Under LGPL - original licence link has changed is not relivant.
50470 * <script type="text/javascript">
50473 * @class Roo.ContentPanel
50474 * @extends Roo.util.Observable
50475 * A basic ContentPanel element.
50476 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50477 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50478 * @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
50479 * @cfg {Boolean} closable True if the panel can be closed/removed
50480 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50481 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50482 * @cfg {Toolbar} toolbar A toolbar for this panel
50483 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50484 * @cfg {String} title The title for this panel
50485 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50486 * @cfg {String} url Calls {@link #setUrl} with this value
50487 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50488 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50489 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50490 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50493 * Create a new ContentPanel.
50494 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50495 * @param {String/Object} config A string to set only the title or a config object
50496 * @param {String} content (optional) Set the HTML content for this panel
50497 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50499 Roo.ContentPanel = function(el, config, content){
50503 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50507 if (config && config.parentLayout) {
50508 el = config.parentLayout.el.createChild();
50511 if(el.autoCreate){ // xtype is available if this is called from factory
50515 this.el = Roo.get(el);
50516 if(!this.el && config && config.autoCreate){
50517 if(typeof config.autoCreate == "object"){
50518 if(!config.autoCreate.id){
50519 config.autoCreate.id = config.id||el;
50521 this.el = Roo.DomHelper.append(document.body,
50522 config.autoCreate, true);
50524 this.el = Roo.DomHelper.append(document.body,
50525 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50528 this.closable = false;
50529 this.loaded = false;
50530 this.active = false;
50531 if(typeof config == "string"){
50532 this.title = config;
50534 Roo.apply(this, config);
50537 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50538 this.wrapEl = this.el.wrap();
50539 this.toolbar.container = this.el.insertSibling(false, 'before');
50540 this.toolbar = new Roo.Toolbar(this.toolbar);
50543 // xtype created footer. - not sure if will work as we normally have to render first..
50544 if (this.footer && !this.footer.el && this.footer.xtype) {
50545 if (!this.wrapEl) {
50546 this.wrapEl = this.el.wrap();
50549 this.footer.container = this.wrapEl.createChild();
50551 this.footer = Roo.factory(this.footer, Roo);
50556 this.resizeEl = Roo.get(this.resizeEl, true);
50558 this.resizeEl = this.el;
50560 // handle view.xtype
50568 * Fires when this panel is activated.
50569 * @param {Roo.ContentPanel} this
50573 * @event deactivate
50574 * Fires when this panel is activated.
50575 * @param {Roo.ContentPanel} this
50577 "deactivate" : true,
50581 * Fires when this panel is resized if fitToFrame is true.
50582 * @param {Roo.ContentPanel} this
50583 * @param {Number} width The width after any component adjustments
50584 * @param {Number} height The height after any component adjustments
50590 * Fires when this tab is created
50591 * @param {Roo.ContentPanel} this
50602 if(this.autoScroll){
50603 this.resizeEl.setStyle("overflow", "auto");
50605 // fix randome scrolling
50606 this.el.on('scroll', function() {
50607 Roo.log('fix random scolling');
50608 this.scrollTo('top',0);
50611 content = content || this.content;
50613 this.setContent(content);
50615 if(config && config.url){
50616 this.setUrl(this.url, this.params, this.loadOnce);
50621 Roo.ContentPanel.superclass.constructor.call(this);
50623 if (this.view && typeof(this.view.xtype) != 'undefined') {
50624 this.view.el = this.el.appendChild(document.createElement("div"));
50625 this.view = Roo.factory(this.view);
50626 this.view.render && this.view.render(false, '');
50630 this.fireEvent('render', this);
50633 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50635 setRegion : function(region){
50636 this.region = region;
50638 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50640 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50645 * Returns the toolbar for this Panel if one was configured.
50646 * @return {Roo.Toolbar}
50648 getToolbar : function(){
50649 return this.toolbar;
50652 setActiveState : function(active){
50653 this.active = active;
50655 this.fireEvent("deactivate", this);
50657 this.fireEvent("activate", this);
50661 * Updates this panel's element
50662 * @param {String} content The new content
50663 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50665 setContent : function(content, loadScripts){
50666 this.el.update(content, loadScripts);
50669 ignoreResize : function(w, h){
50670 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50673 this.lastSize = {width: w, height: h};
50678 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50679 * @return {Roo.UpdateManager} The UpdateManager
50681 getUpdateManager : function(){
50682 return this.el.getUpdateManager();
50685 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50686 * @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:
50689 url: "your-url.php",
50690 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50691 callback: yourFunction,
50692 scope: yourObject, //(optional scope)
50695 text: "Loading...",
50700 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50701 * 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.
50702 * @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}
50703 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50704 * @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.
50705 * @return {Roo.ContentPanel} this
50708 var um = this.el.getUpdateManager();
50709 um.update.apply(um, arguments);
50715 * 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.
50716 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50717 * @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)
50718 * @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)
50719 * @return {Roo.UpdateManager} The UpdateManager
50721 setUrl : function(url, params, loadOnce){
50722 if(this.refreshDelegate){
50723 this.removeListener("activate", this.refreshDelegate);
50725 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
50726 this.on("activate", this.refreshDelegate);
50727 return this.el.getUpdateManager();
50730 _handleRefresh : function(url, params, loadOnce){
50731 if(!loadOnce || !this.loaded){
50732 var updater = this.el.getUpdateManager();
50733 updater.update(url, params, this._setLoaded.createDelegate(this));
50737 _setLoaded : function(){
50738 this.loaded = true;
50742 * Returns this panel's id
50745 getId : function(){
50750 * Returns this panel's element - used by regiosn to add.
50751 * @return {Roo.Element}
50753 getEl : function(){
50754 return this.wrapEl || this.el;
50757 adjustForComponents : function(width, height)
50759 //Roo.log('adjustForComponents ');
50760 if(this.resizeEl != this.el){
50761 width -= this.el.getFrameWidth('lr');
50762 height -= this.el.getFrameWidth('tb');
50765 var te = this.toolbar.getEl();
50766 height -= te.getHeight();
50767 te.setWidth(width);
50770 var te = this.footer.getEl();
50771 Roo.log("footer:" + te.getHeight());
50773 height -= te.getHeight();
50774 te.setWidth(width);
50778 if(this.adjustments){
50779 width += this.adjustments[0];
50780 height += this.adjustments[1];
50782 return {"width": width, "height": height};
50785 setSize : function(width, height){
50786 if(this.fitToFrame && !this.ignoreResize(width, height)){
50787 if(this.fitContainer && this.resizeEl != this.el){
50788 this.el.setSize(width, height);
50790 var size = this.adjustForComponents(width, height);
50791 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
50792 this.fireEvent('resize', this, size.width, size.height);
50797 * Returns this panel's title
50800 getTitle : function(){
50805 * Set this panel's title
50806 * @param {String} title
50808 setTitle : function(title){
50809 this.title = title;
50811 this.region.updatePanelTitle(this, title);
50816 * Returns true is this panel was configured to be closable
50817 * @return {Boolean}
50819 isClosable : function(){
50820 return this.closable;
50823 beforeSlide : function(){
50825 this.resizeEl.clip();
50828 afterSlide : function(){
50830 this.resizeEl.unclip();
50834 * Force a content refresh from the URL specified in the {@link #setUrl} method.
50835 * Will fail silently if the {@link #setUrl} method has not been called.
50836 * This does not activate the panel, just updates its content.
50838 refresh : function(){
50839 if(this.refreshDelegate){
50840 this.loaded = false;
50841 this.refreshDelegate();
50846 * Destroys this panel
50848 destroy : function(){
50849 this.el.removeAllListeners();
50850 var tempEl = document.createElement("span");
50851 tempEl.appendChild(this.el.dom);
50852 tempEl.innerHTML = "";
50858 * form - if the content panel contains a form - this is a reference to it.
50859 * @type {Roo.form.Form}
50863 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
50864 * This contains a reference to it.
50870 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
50880 * @param {Object} cfg Xtype definition of item to add.
50883 addxtype : function(cfg) {
50885 if (cfg.xtype.match(/^Form$/)) {
50888 //if (this.footer) {
50889 // el = this.footer.container.insertSibling(false, 'before');
50891 el = this.el.createChild();
50894 this.form = new Roo.form.Form(cfg);
50897 if ( this.form.allItems.length) this.form.render(el.dom);
50900 // should only have one of theses..
50901 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
50902 // views.. should not be just added - used named prop 'view''
50904 cfg.el = this.el.appendChild(document.createElement("div"));
50907 var ret = new Roo.factory(cfg);
50909 ret.render && ret.render(false, ''); // render blank..
50918 * @class Roo.GridPanel
50919 * @extends Roo.ContentPanel
50921 * Create a new GridPanel.
50922 * @param {Roo.grid.Grid} grid The grid for this panel
50923 * @param {String/Object} config A string to set only the panel's title, or a config object
50925 Roo.GridPanel = function(grid, config){
50928 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
50929 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
50931 this.wrapper.dom.appendChild(grid.getGridEl().dom);
50933 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
50936 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
50938 // xtype created footer. - not sure if will work as we normally have to render first..
50939 if (this.footer && !this.footer.el && this.footer.xtype) {
50941 this.footer.container = this.grid.getView().getFooterPanel(true);
50942 this.footer.dataSource = this.grid.dataSource;
50943 this.footer = Roo.factory(this.footer, Roo);
50947 grid.monitorWindowResize = false; // turn off autosizing
50948 grid.autoHeight = false;
50949 grid.autoWidth = false;
50951 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
50954 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
50955 getId : function(){
50956 return this.grid.id;
50960 * Returns the grid for this panel
50961 * @return {Roo.grid.Grid}
50963 getGrid : function(){
50967 setSize : function(width, height){
50968 if(!this.ignoreResize(width, height)){
50969 var grid = this.grid;
50970 var size = this.adjustForComponents(width, height);
50971 grid.getGridEl().setSize(size.width, size.height);
50976 beforeSlide : function(){
50977 this.grid.getView().scroller.clip();
50980 afterSlide : function(){
50981 this.grid.getView().scroller.unclip();
50984 destroy : function(){
50985 this.grid.destroy();
50987 Roo.GridPanel.superclass.destroy.call(this);
50993 * @class Roo.NestedLayoutPanel
50994 * @extends Roo.ContentPanel
50996 * Create a new NestedLayoutPanel.
50999 * @param {Roo.BorderLayout} layout The layout for this panel
51000 * @param {String/Object} config A string to set only the title or a config object
51002 Roo.NestedLayoutPanel = function(layout, config)
51004 // construct with only one argument..
51005 /* FIXME - implement nicer consturctors
51006 if (layout.layout) {
51008 layout = config.layout;
51009 delete config.layout;
51011 if (layout.xtype && !layout.getEl) {
51012 // then layout needs constructing..
51013 layout = Roo.factory(layout, Roo);
51018 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51020 layout.monitorWindowResize = false; // turn off autosizing
51021 this.layout = layout;
51022 this.layout.getEl().addClass("x-layout-nested-layout");
51029 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51031 setSize : function(width, height){
51032 if(!this.ignoreResize(width, height)){
51033 var size = this.adjustForComponents(width, height);
51034 var el = this.layout.getEl();
51035 el.setSize(size.width, size.height);
51036 var touch = el.dom.offsetWidth;
51037 this.layout.layout();
51038 // ie requires a double layout on the first pass
51039 if(Roo.isIE && !this.initialized){
51040 this.initialized = true;
51041 this.layout.layout();
51046 // activate all subpanels if not currently active..
51048 setActiveState : function(active){
51049 this.active = active;
51051 this.fireEvent("deactivate", this);
51055 this.fireEvent("activate", this);
51056 // not sure if this should happen before or after..
51057 if (!this.layout) {
51058 return; // should not happen..
51061 for (var r in this.layout.regions) {
51062 reg = this.layout.getRegion(r);
51063 if (reg.getActivePanel()) {
51064 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51065 reg.setActivePanel(reg.getActivePanel());
51068 if (!reg.panels.length) {
51071 reg.showPanel(reg.getPanel(0));
51080 * Returns the nested BorderLayout for this panel
51081 * @return {Roo.BorderLayout}
51083 getLayout : function(){
51084 return this.layout;
51088 * Adds a xtype elements to the layout of the nested panel
51092 xtype : 'ContentPanel',
51099 xtype : 'NestedLayoutPanel',
51105 items : [ ... list of content panels or nested layout panels.. ]
51109 * @param {Object} cfg Xtype definition of item to add.
51111 addxtype : function(cfg) {
51112 return this.layout.addxtype(cfg);
51117 Roo.ScrollPanel = function(el, config, content){
51118 config = config || {};
51119 config.fitToFrame = true;
51120 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51122 this.el.dom.style.overflow = "hidden";
51123 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51124 this.el.removeClass("x-layout-inactive-content");
51125 this.el.on("mousewheel", this.onWheel, this);
51127 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51128 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51129 up.unselectable(); down.unselectable();
51130 up.on("click", this.scrollUp, this);
51131 down.on("click", this.scrollDown, this);
51132 up.addClassOnOver("x-scroller-btn-over");
51133 down.addClassOnOver("x-scroller-btn-over");
51134 up.addClassOnClick("x-scroller-btn-click");
51135 down.addClassOnClick("x-scroller-btn-click");
51136 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51138 this.resizeEl = this.el;
51139 this.el = wrap; this.up = up; this.down = down;
51142 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51144 wheelIncrement : 5,
51145 scrollUp : function(){
51146 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51149 scrollDown : function(){
51150 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51153 afterScroll : function(){
51154 var el = this.resizeEl;
51155 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51156 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51157 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51160 setSize : function(){
51161 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51162 this.afterScroll();
51165 onWheel : function(e){
51166 var d = e.getWheelDelta();
51167 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51168 this.afterScroll();
51172 setContent : function(content, loadScripts){
51173 this.resizeEl.update(content, loadScripts);
51187 * @class Roo.TreePanel
51188 * @extends Roo.ContentPanel
51190 * Create a new TreePanel. - defaults to fit/scoll contents.
51191 * @param {String/Object} config A string to set only the panel's title, or a config object
51192 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51194 Roo.TreePanel = function(config){
51195 var el = config.el;
51196 var tree = config.tree;
51197 delete config.tree;
51198 delete config.el; // hopefull!
51200 // wrapper for IE7 strict & safari scroll issue
51202 var treeEl = el.createChild();
51203 config.resizeEl = treeEl;
51207 Roo.TreePanel.superclass.constructor.call(this, el, config);
51210 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51211 //console.log(tree);
51212 this.on('activate', function()
51214 if (this.tree.rendered) {
51217 //console.log('render tree');
51218 this.tree.render();
51220 // this should not be needed.. - it's actually the 'el' that resizes?
51221 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51223 //this.on('resize', function (cp, w, h) {
51224 // this.tree.innerCt.setWidth(w);
51225 // this.tree.innerCt.setHeight(h);
51226 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51233 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51250 * Ext JS Library 1.1.1
51251 * Copyright(c) 2006-2007, Ext JS, LLC.
51253 * Originally Released Under LGPL - original licence link has changed is not relivant.
51256 * <script type="text/javascript">
51261 * @class Roo.ReaderLayout
51262 * @extends Roo.BorderLayout
51263 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51264 * center region containing two nested regions (a top one for a list view and one for item preview below),
51265 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51266 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51267 * expedites the setup of the overall layout and regions for this common application style.
51270 var reader = new Roo.ReaderLayout();
51271 var CP = Roo.ContentPanel; // shortcut for adding
51273 reader.beginUpdate();
51274 reader.add("north", new CP("north", "North"));
51275 reader.add("west", new CP("west", {title: "West"}));
51276 reader.add("east", new CP("east", {title: "East"}));
51278 reader.regions.listView.add(new CP("listView", "List"));
51279 reader.regions.preview.add(new CP("preview", "Preview"));
51280 reader.endUpdate();
51283 * Create a new ReaderLayout
51284 * @param {Object} config Configuration options
51285 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51286 * document.body if omitted)
51288 Roo.ReaderLayout = function(config, renderTo){
51289 var c = config || {size:{}};
51290 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51291 north: c.north !== false ? Roo.apply({
51295 }, c.north) : false,
51296 west: c.west !== false ? Roo.apply({
51304 margins:{left:5,right:0,bottom:5,top:5},
51305 cmargins:{left:5,right:5,bottom:5,top:5}
51306 }, c.west) : false,
51307 east: c.east !== false ? Roo.apply({
51315 margins:{left:0,right:5,bottom:5,top:5},
51316 cmargins:{left:5,right:5,bottom:5,top:5}
51317 }, c.east) : false,
51318 center: Roo.apply({
51319 tabPosition: 'top',
51323 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51327 this.el.addClass('x-reader');
51329 this.beginUpdate();
51331 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51332 south: c.preview !== false ? Roo.apply({
51339 cmargins:{top:5,left:0, right:0, bottom:0}
51340 }, c.preview) : false,
51341 center: Roo.apply({
51347 this.add('center', new Roo.NestedLayoutPanel(inner,
51348 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51352 this.regions.preview = inner.getRegion('south');
51353 this.regions.listView = inner.getRegion('center');
51356 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51358 * Ext JS Library 1.1.1
51359 * Copyright(c) 2006-2007, Ext JS, LLC.
51361 * Originally Released Under LGPL - original licence link has changed is not relivant.
51364 * <script type="text/javascript">
51368 * @class Roo.grid.Grid
51369 * @extends Roo.util.Observable
51370 * This class represents the primary interface of a component based grid control.
51371 * <br><br>Usage:<pre><code>
51372 var grid = new Roo.grid.Grid("my-container-id", {
51375 selModel: mySelectionModel,
51376 autoSizeColumns: true,
51377 monitorWindowResize: false,
51378 trackMouseOver: true
51383 * <b>Common Problems:</b><br/>
51384 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51385 * element will correct this<br/>
51386 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51387 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51388 * are unpredictable.<br/>
51389 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51390 * grid to calculate dimensions/offsets.<br/>
51392 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51393 * The container MUST have some type of size defined for the grid to fill. The container will be
51394 * automatically set to position relative if it isn't already.
51395 * @param {Object} config A config object that sets properties on this grid.
51397 Roo.grid.Grid = function(container, config){
51398 // initialize the container
51399 this.container = Roo.get(container);
51400 this.container.update("");
51401 this.container.setStyle("overflow", "hidden");
51402 this.container.addClass('x-grid-container');
51404 this.id = this.container.id;
51406 Roo.apply(this, config);
51407 // check and correct shorthanded configs
51409 this.dataSource = this.ds;
51413 this.colModel = this.cm;
51417 this.selModel = this.sm;
51421 if (this.selModel) {
51422 this.selModel = Roo.factory(this.selModel, Roo.grid);
51423 this.sm = this.selModel;
51424 this.sm.xmodule = this.xmodule || false;
51426 if (typeof(this.colModel.config) == 'undefined') {
51427 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51428 this.cm = this.colModel;
51429 this.cm.xmodule = this.xmodule || false;
51431 if (this.dataSource) {
51432 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51433 this.ds = this.dataSource;
51434 this.ds.xmodule = this.xmodule || false;
51441 this.container.setWidth(this.width);
51445 this.container.setHeight(this.height);
51452 * The raw click event for the entire grid.
51453 * @param {Roo.EventObject} e
51458 * The raw dblclick event for the entire grid.
51459 * @param {Roo.EventObject} e
51463 * @event contextmenu
51464 * The raw contextmenu event for the entire grid.
51465 * @param {Roo.EventObject} e
51467 "contextmenu" : true,
51470 * The raw mousedown event for the entire grid.
51471 * @param {Roo.EventObject} e
51473 "mousedown" : true,
51476 * The raw mouseup event for the entire grid.
51477 * @param {Roo.EventObject} e
51482 * The raw mouseover event for the entire grid.
51483 * @param {Roo.EventObject} e
51485 "mouseover" : true,
51488 * The raw mouseout event for the entire grid.
51489 * @param {Roo.EventObject} e
51494 * The raw keypress event for the entire grid.
51495 * @param {Roo.EventObject} e
51500 * The raw keydown event for the entire grid.
51501 * @param {Roo.EventObject} e
51509 * Fires when a cell is clicked
51510 * @param {Grid} this
51511 * @param {Number} rowIndex
51512 * @param {Number} columnIndex
51513 * @param {Roo.EventObject} e
51515 "cellclick" : true,
51517 * @event celldblclick
51518 * Fires when a cell is double clicked
51519 * @param {Grid} this
51520 * @param {Number} rowIndex
51521 * @param {Number} columnIndex
51522 * @param {Roo.EventObject} e
51524 "celldblclick" : true,
51527 * Fires when a row is clicked
51528 * @param {Grid} this
51529 * @param {Number} rowIndex
51530 * @param {Roo.EventObject} e
51534 * @event rowdblclick
51535 * Fires when a row is double clicked
51536 * @param {Grid} this
51537 * @param {Number} rowIndex
51538 * @param {Roo.EventObject} e
51540 "rowdblclick" : true,
51542 * @event headerclick
51543 * Fires when a header is clicked
51544 * @param {Grid} this
51545 * @param {Number} columnIndex
51546 * @param {Roo.EventObject} e
51548 "headerclick" : true,
51550 * @event headerdblclick
51551 * Fires when a header cell is double clicked
51552 * @param {Grid} this
51553 * @param {Number} columnIndex
51554 * @param {Roo.EventObject} e
51556 "headerdblclick" : true,
51558 * @event rowcontextmenu
51559 * Fires when a row is right clicked
51560 * @param {Grid} this
51561 * @param {Number} rowIndex
51562 * @param {Roo.EventObject} e
51564 "rowcontextmenu" : true,
51566 * @event cellcontextmenu
51567 * Fires when a cell is right clicked
51568 * @param {Grid} this
51569 * @param {Number} rowIndex
51570 * @param {Number} cellIndex
51571 * @param {Roo.EventObject} e
51573 "cellcontextmenu" : true,
51575 * @event headercontextmenu
51576 * Fires when a header is right clicked
51577 * @param {Grid} this
51578 * @param {Number} columnIndex
51579 * @param {Roo.EventObject} e
51581 "headercontextmenu" : true,
51583 * @event bodyscroll
51584 * Fires when the body element is scrolled
51585 * @param {Number} scrollLeft
51586 * @param {Number} scrollTop
51588 "bodyscroll" : true,
51590 * @event columnresize
51591 * Fires when the user resizes a column
51592 * @param {Number} columnIndex
51593 * @param {Number} newSize
51595 "columnresize" : true,
51597 * @event columnmove
51598 * Fires when the user moves a column
51599 * @param {Number} oldIndex
51600 * @param {Number} newIndex
51602 "columnmove" : true,
51605 * Fires when row(s) start being dragged
51606 * @param {Grid} this
51607 * @param {Roo.GridDD} dd The drag drop object
51608 * @param {event} e The raw browser event
51610 "startdrag" : true,
51613 * Fires when a drag operation is complete
51614 * @param {Grid} this
51615 * @param {Roo.GridDD} dd The drag drop object
51616 * @param {event} e The raw browser event
51621 * Fires when dragged row(s) are dropped on a valid DD target
51622 * @param {Grid} this
51623 * @param {Roo.GridDD} dd The drag drop object
51624 * @param {String} targetId The target drag drop object
51625 * @param {event} e The raw browser event
51630 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51631 * @param {Grid} this
51632 * @param {Roo.GridDD} dd The drag drop object
51633 * @param {String} targetId The target drag drop object
51634 * @param {event} e The raw browser event
51639 * Fires when the dragged row(s) first cross another DD target while being dragged
51640 * @param {Grid} this
51641 * @param {Roo.GridDD} dd The drag drop object
51642 * @param {String} targetId The target drag drop object
51643 * @param {event} e The raw browser event
51645 "dragenter" : true,
51648 * Fires when the dragged row(s) leave another DD target while being dragged
51649 * @param {Grid} this
51650 * @param {Roo.GridDD} dd The drag drop object
51651 * @param {String} targetId The target drag drop object
51652 * @param {event} e The raw browser event
51657 * Fires when a row is rendered, so you can change add a style to it.
51658 * @param {GridView} gridview The grid view
51659 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51665 * Fires when the grid is rendered
51666 * @param {Grid} grid
51671 Roo.grid.Grid.superclass.constructor.call(this);
51673 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51676 * @cfg {String} ddGroup - drag drop group.
51680 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51682 minColumnWidth : 25,
51685 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51686 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51687 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51689 autoSizeColumns : false,
51692 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51694 autoSizeHeaders : true,
51697 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51699 monitorWindowResize : true,
51702 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51703 * rows measured to get a columns size. Default is 0 (all rows).
51705 maxRowsToMeasure : 0,
51708 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51710 trackMouseOver : true,
51713 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51717 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51719 enableDragDrop : false,
51722 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51724 enableColumnMove : true,
51727 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
51729 enableColumnHide : true,
51732 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
51734 enableRowHeightSync : false,
51737 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
51742 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
51744 autoHeight : false,
51747 * @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.
51749 autoExpandColumn : false,
51752 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
51755 autoExpandMin : 50,
51758 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
51760 autoExpandMax : 1000,
51763 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
51768 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
51772 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
51782 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
51783 * of a fixed width. Default is false.
51786 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
51789 * Called once after all setup has been completed and the grid is ready to be rendered.
51790 * @return {Roo.grid.Grid} this
51792 render : function()
51794 var c = this.container;
51795 // try to detect autoHeight/width mode
51796 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
51797 this.autoHeight = true;
51799 var view = this.getView();
51802 c.on("click", this.onClick, this);
51803 c.on("dblclick", this.onDblClick, this);
51804 c.on("contextmenu", this.onContextMenu, this);
51805 c.on("keydown", this.onKeyDown, this);
51807 c.on("touchstart", this.onTouchStart, this);
51810 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
51812 this.getSelectionModel().init(this);
51817 this.loadMask = new Roo.LoadMask(this.container,
51818 Roo.apply({store:this.dataSource}, this.loadMask));
51822 if (this.toolbar && this.toolbar.xtype) {
51823 this.toolbar.container = this.getView().getHeaderPanel(true);
51824 this.toolbar = new Roo.Toolbar(this.toolbar);
51826 if (this.footer && this.footer.xtype) {
51827 this.footer.dataSource = this.getDataSource();
51828 this.footer.container = this.getView().getFooterPanel(true);
51829 this.footer = Roo.factory(this.footer, Roo);
51831 if (this.dropTarget && this.dropTarget.xtype) {
51832 delete this.dropTarget.xtype;
51833 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
51837 this.rendered = true;
51838 this.fireEvent('render', this);
51843 * Reconfigures the grid to use a different Store and Column Model.
51844 * The View will be bound to the new objects and refreshed.
51845 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
51846 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
51848 reconfigure : function(dataSource, colModel){
51850 this.loadMask.destroy();
51851 this.loadMask = new Roo.LoadMask(this.container,
51852 Roo.apply({store:dataSource}, this.loadMask));
51854 this.view.bind(dataSource, colModel);
51855 this.dataSource = dataSource;
51856 this.colModel = colModel;
51857 this.view.refresh(true);
51861 onKeyDown : function(e){
51862 this.fireEvent("keydown", e);
51866 * Destroy this grid.
51867 * @param {Boolean} removeEl True to remove the element
51869 destroy : function(removeEl, keepListeners){
51871 this.loadMask.destroy();
51873 var c = this.container;
51874 c.removeAllListeners();
51875 this.view.destroy();
51876 this.colModel.purgeListeners();
51877 if(!keepListeners){
51878 this.purgeListeners();
51881 if(removeEl === true){
51887 processEvent : function(name, e){
51888 // does this fire select???
51889 Roo.log('grid:processEvent ' + name);
51891 if (name != 'touchstart' ) {
51892 this.fireEvent(name, e);
51895 var t = e.getTarget();
51897 var header = v.findHeaderIndex(t);
51898 if(header !== false){
51899 var ename = name == 'touchstart' ? 'click' : name;
51901 this.fireEvent("header" + ename, this, header, e);
51903 var row = v.findRowIndex(t);
51904 var cell = v.findCellIndex(t);
51905 if (name == 'touchstart') {
51906 // first touch is always a click.
51907 // hopefull this happens after selection is updated.?
51910 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
51911 var cs = this.selModel.getSelectedCell();
51912 if (row == cs[0] && cell == cs[1]){
51916 if (typeof(this.selModel.getSelections) != 'undefined') {
51917 var cs = this.selModel.getSelections();
51918 var ds = this.dataSource;
51919 if (cs.length == 1 && ds.getAt(row) == cs[0]){
51930 this.fireEvent("row" + name, this, row, e);
51931 if(cell !== false){
51932 this.fireEvent("cell" + name, this, row, cell, e);
51939 onClick : function(e){
51940 this.processEvent("click", e);
51943 onTouchStart : function(e){
51944 this.processEvent("touchstart", e);
51948 onContextMenu : function(e, t){
51949 this.processEvent("contextmenu", e);
51953 onDblClick : function(e){
51954 this.processEvent("dblclick", e);
51958 walkCells : function(row, col, step, fn, scope){
51959 var cm = this.colModel, clen = cm.getColumnCount();
51960 var ds = this.dataSource, rlen = ds.getCount(), first = true;
51972 if(fn.call(scope || this, row, col, cm) === true){
51990 if(fn.call(scope || this, row, col, cm) === true){
52002 getSelections : function(){
52003 return this.selModel.getSelections();
52007 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52008 * but if manual update is required this method will initiate it.
52010 autoSize : function(){
52012 this.view.layout();
52013 if(this.view.adjustForScroll){
52014 this.view.adjustForScroll();
52020 * Returns the grid's underlying element.
52021 * @return {Element} The element
52023 getGridEl : function(){
52024 return this.container;
52027 // private for compatibility, overridden by editor grid
52028 stopEditing : function(){},
52031 * Returns the grid's SelectionModel.
52032 * @return {SelectionModel}
52034 getSelectionModel : function(){
52035 if(!this.selModel){
52036 this.selModel = new Roo.grid.RowSelectionModel();
52038 return this.selModel;
52042 * Returns the grid's DataSource.
52043 * @return {DataSource}
52045 getDataSource : function(){
52046 return this.dataSource;
52050 * Returns the grid's ColumnModel.
52051 * @return {ColumnModel}
52053 getColumnModel : function(){
52054 return this.colModel;
52058 * Returns the grid's GridView object.
52059 * @return {GridView}
52061 getView : function(){
52063 this.view = new Roo.grid.GridView(this.viewConfig);
52068 * Called to get grid's drag proxy text, by default returns this.ddText.
52071 getDragDropText : function(){
52072 var count = this.selModel.getCount();
52073 return String.format(this.ddText, count, count == 1 ? '' : 's');
52077 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52078 * %0 is replaced with the number of selected rows.
52081 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52083 * Ext JS Library 1.1.1
52084 * Copyright(c) 2006-2007, Ext JS, LLC.
52086 * Originally Released Under LGPL - original licence link has changed is not relivant.
52089 * <script type="text/javascript">
52092 Roo.grid.AbstractGridView = function(){
52096 "beforerowremoved" : true,
52097 "beforerowsinserted" : true,
52098 "beforerefresh" : true,
52099 "rowremoved" : true,
52100 "rowsinserted" : true,
52101 "rowupdated" : true,
52104 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52107 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52108 rowClass : "x-grid-row",
52109 cellClass : "x-grid-cell",
52110 tdClass : "x-grid-td",
52111 hdClass : "x-grid-hd",
52112 splitClass : "x-grid-hd-split",
52114 init: function(grid){
52116 var cid = this.grid.getGridEl().id;
52117 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52118 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52119 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52120 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52123 getColumnRenderers : function(){
52124 var renderers = [];
52125 var cm = this.grid.colModel;
52126 var colCount = cm.getColumnCount();
52127 for(var i = 0; i < colCount; i++){
52128 renderers[i] = cm.getRenderer(i);
52133 getColumnIds : function(){
52135 var cm = this.grid.colModel;
52136 var colCount = cm.getColumnCount();
52137 for(var i = 0; i < colCount; i++){
52138 ids[i] = cm.getColumnId(i);
52143 getDataIndexes : function(){
52144 if(!this.indexMap){
52145 this.indexMap = this.buildIndexMap();
52147 return this.indexMap.colToData;
52150 getColumnIndexByDataIndex : function(dataIndex){
52151 if(!this.indexMap){
52152 this.indexMap = this.buildIndexMap();
52154 return this.indexMap.dataToCol[dataIndex];
52158 * Set a css style for a column dynamically.
52159 * @param {Number} colIndex The index of the column
52160 * @param {String} name The css property name
52161 * @param {String} value The css value
52163 setCSSStyle : function(colIndex, name, value){
52164 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52165 Roo.util.CSS.updateRule(selector, name, value);
52168 generateRules : function(cm){
52169 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52170 Roo.util.CSS.removeStyleSheet(rulesId);
52171 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52172 var cid = cm.getColumnId(i);
52173 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52174 this.tdSelector, cid, " {\n}\n",
52175 this.hdSelector, cid, " {\n}\n",
52176 this.splitSelector, cid, " {\n}\n");
52178 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52182 * Ext JS Library 1.1.1
52183 * Copyright(c) 2006-2007, Ext JS, LLC.
52185 * Originally Released Under LGPL - original licence link has changed is not relivant.
52188 * <script type="text/javascript">
52192 // This is a support class used internally by the Grid components
52193 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52195 this.view = grid.getView();
52196 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52197 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52199 this.setHandleElId(Roo.id(hd));
52200 this.setOuterHandleElId(Roo.id(hd2));
52202 this.scroll = false;
52204 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52206 getDragData : function(e){
52207 var t = Roo.lib.Event.getTarget(e);
52208 var h = this.view.findHeaderCell(t);
52210 return {ddel: h.firstChild, header:h};
52215 onInitDrag : function(e){
52216 this.view.headersDisabled = true;
52217 var clone = this.dragData.ddel.cloneNode(true);
52218 clone.id = Roo.id();
52219 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52220 this.proxy.update(clone);
52224 afterValidDrop : function(){
52226 setTimeout(function(){
52227 v.headersDisabled = false;
52231 afterInvalidDrop : function(){
52233 setTimeout(function(){
52234 v.headersDisabled = false;
52240 * Ext JS Library 1.1.1
52241 * Copyright(c) 2006-2007, Ext JS, LLC.
52243 * Originally Released Under LGPL - original licence link has changed is not relivant.
52246 * <script type="text/javascript">
52249 // This is a support class used internally by the Grid components
52250 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52252 this.view = grid.getView();
52253 // split the proxies so they don't interfere with mouse events
52254 this.proxyTop = Roo.DomHelper.append(document.body, {
52255 cls:"col-move-top", html:" "
52257 this.proxyBottom = Roo.DomHelper.append(document.body, {
52258 cls:"col-move-bottom", html:" "
52260 this.proxyTop.hide = this.proxyBottom.hide = function(){
52261 this.setLeftTop(-100,-100);
52262 this.setStyle("visibility", "hidden");
52264 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52265 // temporarily disabled
52266 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52267 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52269 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52270 proxyOffsets : [-4, -9],
52271 fly: Roo.Element.fly,
52273 getTargetFromEvent : function(e){
52274 var t = Roo.lib.Event.getTarget(e);
52275 var cindex = this.view.findCellIndex(t);
52276 if(cindex !== false){
52277 return this.view.getHeaderCell(cindex);
52282 nextVisible : function(h){
52283 var v = this.view, cm = this.grid.colModel;
52286 if(!cm.isHidden(v.getCellIndex(h))){
52294 prevVisible : function(h){
52295 var v = this.view, cm = this.grid.colModel;
52298 if(!cm.isHidden(v.getCellIndex(h))){
52306 positionIndicator : function(h, n, e){
52307 var x = Roo.lib.Event.getPageX(e);
52308 var r = Roo.lib.Dom.getRegion(n.firstChild);
52309 var px, pt, py = r.top + this.proxyOffsets[1];
52310 if((r.right - x) <= (r.right-r.left)/2){
52311 px = r.right+this.view.borderWidth;
52317 var oldIndex = this.view.getCellIndex(h);
52318 var newIndex = this.view.getCellIndex(n);
52320 if(this.grid.colModel.isFixed(newIndex)){
52324 var locked = this.grid.colModel.isLocked(newIndex);
52329 if(oldIndex < newIndex){
52332 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52335 px += this.proxyOffsets[0];
52336 this.proxyTop.setLeftTop(px, py);
52337 this.proxyTop.show();
52338 if(!this.bottomOffset){
52339 this.bottomOffset = this.view.mainHd.getHeight();
52341 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52342 this.proxyBottom.show();
52346 onNodeEnter : function(n, dd, e, data){
52347 if(data.header != n){
52348 this.positionIndicator(data.header, n, e);
52352 onNodeOver : function(n, dd, e, data){
52353 var result = false;
52354 if(data.header != n){
52355 result = this.positionIndicator(data.header, n, e);
52358 this.proxyTop.hide();
52359 this.proxyBottom.hide();
52361 return result ? this.dropAllowed : this.dropNotAllowed;
52364 onNodeOut : function(n, dd, e, data){
52365 this.proxyTop.hide();
52366 this.proxyBottom.hide();
52369 onNodeDrop : function(n, dd, e, data){
52370 var h = data.header;
52372 var cm = this.grid.colModel;
52373 var x = Roo.lib.Event.getPageX(e);
52374 var r = Roo.lib.Dom.getRegion(n.firstChild);
52375 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52376 var oldIndex = this.view.getCellIndex(h);
52377 var newIndex = this.view.getCellIndex(n);
52378 var locked = cm.isLocked(newIndex);
52382 if(oldIndex < newIndex){
52385 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52388 cm.setLocked(oldIndex, locked, true);
52389 cm.moveColumn(oldIndex, newIndex);
52390 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52398 * Ext JS Library 1.1.1
52399 * Copyright(c) 2006-2007, Ext JS, LLC.
52401 * Originally Released Under LGPL - original licence link has changed is not relivant.
52404 * <script type="text/javascript">
52408 * @class Roo.grid.GridView
52409 * @extends Roo.util.Observable
52412 * @param {Object} config
52414 Roo.grid.GridView = function(config){
52415 Roo.grid.GridView.superclass.constructor.call(this);
52418 Roo.apply(this, config);
52421 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52423 unselectable : 'unselectable="on"',
52424 unselectableCls : 'x-unselectable',
52427 rowClass : "x-grid-row",
52429 cellClass : "x-grid-col",
52431 tdClass : "x-grid-td",
52433 hdClass : "x-grid-hd",
52435 splitClass : "x-grid-split",
52437 sortClasses : ["sort-asc", "sort-desc"],
52439 enableMoveAnim : false,
52443 dh : Roo.DomHelper,
52445 fly : Roo.Element.fly,
52447 css : Roo.util.CSS,
52453 scrollIncrement : 22,
52455 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52457 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52459 bind : function(ds, cm){
52461 this.ds.un("load", this.onLoad, this);
52462 this.ds.un("datachanged", this.onDataChange, this);
52463 this.ds.un("add", this.onAdd, this);
52464 this.ds.un("remove", this.onRemove, this);
52465 this.ds.un("update", this.onUpdate, this);
52466 this.ds.un("clear", this.onClear, this);
52469 ds.on("load", this.onLoad, this);
52470 ds.on("datachanged", this.onDataChange, this);
52471 ds.on("add", this.onAdd, this);
52472 ds.on("remove", this.onRemove, this);
52473 ds.on("update", this.onUpdate, this);
52474 ds.on("clear", this.onClear, this);
52479 this.cm.un("widthchange", this.onColWidthChange, this);
52480 this.cm.un("headerchange", this.onHeaderChange, this);
52481 this.cm.un("hiddenchange", this.onHiddenChange, this);
52482 this.cm.un("columnmoved", this.onColumnMove, this);
52483 this.cm.un("columnlockchange", this.onColumnLock, this);
52486 this.generateRules(cm);
52487 cm.on("widthchange", this.onColWidthChange, this);
52488 cm.on("headerchange", this.onHeaderChange, this);
52489 cm.on("hiddenchange", this.onHiddenChange, this);
52490 cm.on("columnmoved", this.onColumnMove, this);
52491 cm.on("columnlockchange", this.onColumnLock, this);
52496 init: function(grid){
52497 Roo.grid.GridView.superclass.init.call(this, grid);
52499 this.bind(grid.dataSource, grid.colModel);
52501 grid.on("headerclick", this.handleHeaderClick, this);
52503 if(grid.trackMouseOver){
52504 grid.on("mouseover", this.onRowOver, this);
52505 grid.on("mouseout", this.onRowOut, this);
52507 grid.cancelTextSelection = function(){};
52508 this.gridId = grid.id;
52510 var tpls = this.templates || {};
52513 tpls.master = new Roo.Template(
52514 '<div class="x-grid" hidefocus="true">',
52515 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52516 '<div class="x-grid-topbar"></div>',
52517 '<div class="x-grid-scroller"><div></div></div>',
52518 '<div class="x-grid-locked">',
52519 '<div class="x-grid-header">{lockedHeader}</div>',
52520 '<div class="x-grid-body">{lockedBody}</div>',
52522 '<div class="x-grid-viewport">',
52523 '<div class="x-grid-header">{header}</div>',
52524 '<div class="x-grid-body">{body}</div>',
52526 '<div class="x-grid-bottombar"></div>',
52528 '<div class="x-grid-resize-proxy"> </div>',
52531 tpls.master.disableformats = true;
52535 tpls.header = new Roo.Template(
52536 '<table border="0" cellspacing="0" cellpadding="0">',
52537 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52540 tpls.header.disableformats = true;
52542 tpls.header.compile();
52545 tpls.hcell = new Roo.Template(
52546 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52547 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52550 tpls.hcell.disableFormats = true;
52552 tpls.hcell.compile();
52555 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52556 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52557 tpls.hsplit.disableFormats = true;
52559 tpls.hsplit.compile();
52562 tpls.body = new Roo.Template(
52563 '<table border="0" cellspacing="0" cellpadding="0">',
52564 "<tbody>{rows}</tbody>",
52567 tpls.body.disableFormats = true;
52569 tpls.body.compile();
52572 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52573 tpls.row.disableFormats = true;
52575 tpls.row.compile();
52578 tpls.cell = new Roo.Template(
52579 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52580 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52581 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52584 tpls.cell.disableFormats = true;
52586 tpls.cell.compile();
52588 this.templates = tpls;
52591 // remap these for backwards compat
52592 onColWidthChange : function(){
52593 this.updateColumns.apply(this, arguments);
52595 onHeaderChange : function(){
52596 this.updateHeaders.apply(this, arguments);
52598 onHiddenChange : function(){
52599 this.handleHiddenChange.apply(this, arguments);
52601 onColumnMove : function(){
52602 this.handleColumnMove.apply(this, arguments);
52604 onColumnLock : function(){
52605 this.handleLockChange.apply(this, arguments);
52608 onDataChange : function(){
52610 this.updateHeaderSortState();
52613 onClear : function(){
52617 onUpdate : function(ds, record){
52618 this.refreshRow(record);
52621 refreshRow : function(record){
52622 var ds = this.ds, index;
52623 if(typeof record == 'number'){
52625 record = ds.getAt(index);
52627 index = ds.indexOf(record);
52629 this.insertRows(ds, index, index, true);
52630 this.onRemove(ds, record, index+1, true);
52631 this.syncRowHeights(index, index);
52633 this.fireEvent("rowupdated", this, index, record);
52636 onAdd : function(ds, records, index){
52637 this.insertRows(ds, index, index + (records.length-1));
52640 onRemove : function(ds, record, index, isUpdate){
52641 if(isUpdate !== true){
52642 this.fireEvent("beforerowremoved", this, index, record);
52644 var bt = this.getBodyTable(), lt = this.getLockedTable();
52645 if(bt.rows[index]){
52646 bt.firstChild.removeChild(bt.rows[index]);
52648 if(lt.rows[index]){
52649 lt.firstChild.removeChild(lt.rows[index]);
52651 if(isUpdate !== true){
52652 this.stripeRows(index);
52653 this.syncRowHeights(index, index);
52655 this.fireEvent("rowremoved", this, index, record);
52659 onLoad : function(){
52660 this.scrollToTop();
52664 * Scrolls the grid to the top
52666 scrollToTop : function(){
52668 this.scroller.dom.scrollTop = 0;
52674 * Gets a panel in the header of the grid that can be used for toolbars etc.
52675 * After modifying the contents of this panel a call to grid.autoSize() may be
52676 * required to register any changes in size.
52677 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52678 * @return Roo.Element
52680 getHeaderPanel : function(doShow){
52682 this.headerPanel.show();
52684 return this.headerPanel;
52688 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52689 * After modifying the contents of this panel a call to grid.autoSize() may be
52690 * required to register any changes in size.
52691 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52692 * @return Roo.Element
52694 getFooterPanel : function(doShow){
52696 this.footerPanel.show();
52698 return this.footerPanel;
52701 initElements : function(){
52702 var E = Roo.Element;
52703 var el = this.grid.getGridEl().dom.firstChild;
52704 var cs = el.childNodes;
52706 this.el = new E(el);
52708 this.focusEl = new E(el.firstChild);
52709 this.focusEl.swallowEvent("click", true);
52711 this.headerPanel = new E(cs[1]);
52712 this.headerPanel.enableDisplayMode("block");
52714 this.scroller = new E(cs[2]);
52715 this.scrollSizer = new E(this.scroller.dom.firstChild);
52717 this.lockedWrap = new E(cs[3]);
52718 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52719 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52721 this.mainWrap = new E(cs[4]);
52722 this.mainHd = new E(this.mainWrap.dom.firstChild);
52723 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
52725 this.footerPanel = new E(cs[5]);
52726 this.footerPanel.enableDisplayMode("block");
52728 this.resizeProxy = new E(cs[6]);
52730 this.headerSelector = String.format(
52731 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
52732 this.lockedHd.id, this.mainHd.id
52735 this.splitterSelector = String.format(
52736 '#{0} div.x-grid-split, #{1} div.x-grid-split',
52737 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
52740 idToCssName : function(s)
52742 return s.replace(/[^a-z0-9]+/ig, '-');
52745 getHeaderCell : function(index){
52746 return Roo.DomQuery.select(this.headerSelector)[index];
52749 getHeaderCellMeasure : function(index){
52750 return this.getHeaderCell(index).firstChild;
52753 getHeaderCellText : function(index){
52754 return this.getHeaderCell(index).firstChild.firstChild;
52757 getLockedTable : function(){
52758 return this.lockedBody.dom.firstChild;
52761 getBodyTable : function(){
52762 return this.mainBody.dom.firstChild;
52765 getLockedRow : function(index){
52766 return this.getLockedTable().rows[index];
52769 getRow : function(index){
52770 return this.getBodyTable().rows[index];
52773 getRowComposite : function(index){
52775 this.rowEl = new Roo.CompositeElementLite();
52777 var els = [], lrow, mrow;
52778 if(lrow = this.getLockedRow(index)){
52781 if(mrow = this.getRow(index)){
52784 this.rowEl.elements = els;
52788 * Gets the 'td' of the cell
52790 * @param {Integer} rowIndex row to select
52791 * @param {Integer} colIndex column to select
52795 getCell : function(rowIndex, colIndex){
52796 var locked = this.cm.getLockedCount();
52798 if(colIndex < locked){
52799 source = this.lockedBody.dom.firstChild;
52801 source = this.mainBody.dom.firstChild;
52802 colIndex -= locked;
52804 return source.rows[rowIndex].childNodes[colIndex];
52807 getCellText : function(rowIndex, colIndex){
52808 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
52811 getCellBox : function(cell){
52812 var b = this.fly(cell).getBox();
52813 if(Roo.isOpera){ // opera fails to report the Y
52814 b.y = cell.offsetTop + this.mainBody.getY();
52819 getCellIndex : function(cell){
52820 var id = String(cell.className).match(this.cellRE);
52822 return parseInt(id[1], 10);
52827 findHeaderIndex : function(n){
52828 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52829 return r ? this.getCellIndex(r) : false;
52832 findHeaderCell : function(n){
52833 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52834 return r ? r : false;
52837 findRowIndex : function(n){
52841 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
52842 return r ? r.rowIndex : false;
52845 findCellIndex : function(node){
52846 var stop = this.el.dom;
52847 while(node && node != stop){
52848 if(this.findRE.test(node.className)){
52849 return this.getCellIndex(node);
52851 node = node.parentNode;
52856 getColumnId : function(index){
52857 return this.cm.getColumnId(index);
52860 getSplitters : function()
52862 if(this.splitterSelector){
52863 return Roo.DomQuery.select(this.splitterSelector);
52869 getSplitter : function(index){
52870 return this.getSplitters()[index];
52873 onRowOver : function(e, t){
52875 if((row = this.findRowIndex(t)) !== false){
52876 this.getRowComposite(row).addClass("x-grid-row-over");
52880 onRowOut : function(e, t){
52882 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
52883 this.getRowComposite(row).removeClass("x-grid-row-over");
52887 renderHeaders : function(){
52889 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
52890 var cb = [], lb = [], sb = [], lsb = [], p = {};
52891 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52892 p.cellId = "x-grid-hd-0-" + i;
52893 p.splitId = "x-grid-csplit-0-" + i;
52894 p.id = cm.getColumnId(i);
52895 p.title = cm.getColumnTooltip(i) || "";
52896 p.value = cm.getColumnHeader(i) || "";
52897 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
52898 if(!cm.isLocked(i)){
52899 cb[cb.length] = ct.apply(p);
52900 sb[sb.length] = st.apply(p);
52902 lb[lb.length] = ct.apply(p);
52903 lsb[lsb.length] = st.apply(p);
52906 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
52907 ht.apply({cells: cb.join(""), splits:sb.join("")})];
52910 updateHeaders : function(){
52911 var html = this.renderHeaders();
52912 this.lockedHd.update(html[0]);
52913 this.mainHd.update(html[1]);
52917 * Focuses the specified row.
52918 * @param {Number} row The row index
52920 focusRow : function(row)
52922 //Roo.log('GridView.focusRow');
52923 var x = this.scroller.dom.scrollLeft;
52924 this.focusCell(row, 0, false);
52925 this.scroller.dom.scrollLeft = x;
52929 * Focuses the specified cell.
52930 * @param {Number} row The row index
52931 * @param {Number} col The column index
52932 * @param {Boolean} hscroll false to disable horizontal scrolling
52934 focusCell : function(row, col, hscroll)
52936 //Roo.log('GridView.focusCell');
52937 var el = this.ensureVisible(row, col, hscroll);
52938 this.focusEl.alignTo(el, "tl-tl");
52940 this.focusEl.focus();
52942 this.focusEl.focus.defer(1, this.focusEl);
52947 * Scrolls the specified cell into view
52948 * @param {Number} row The row index
52949 * @param {Number} col The column index
52950 * @param {Boolean} hscroll false to disable horizontal scrolling
52952 ensureVisible : function(row, col, hscroll)
52954 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
52955 //return null; //disable for testing.
52956 if(typeof row != "number"){
52957 row = row.rowIndex;
52959 if(row < 0 && row >= this.ds.getCount()){
52962 col = (col !== undefined ? col : 0);
52963 var cm = this.grid.colModel;
52964 while(cm.isHidden(col)){
52968 var el = this.getCell(row, col);
52972 var c = this.scroller.dom;
52974 var ctop = parseInt(el.offsetTop, 10);
52975 var cleft = parseInt(el.offsetLeft, 10);
52976 var cbot = ctop + el.offsetHeight;
52977 var cright = cleft + el.offsetWidth;
52979 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
52980 var stop = parseInt(c.scrollTop, 10);
52981 var sleft = parseInt(c.scrollLeft, 10);
52982 var sbot = stop + ch;
52983 var sright = sleft + c.clientWidth;
52985 Roo.log('GridView.ensureVisible:' +
52987 ' c.clientHeight:' + c.clientHeight +
52988 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
52996 c.scrollTop = ctop;
52997 //Roo.log("set scrolltop to ctop DISABLE?");
52998 }else if(cbot > sbot){
52999 //Roo.log("set scrolltop to cbot-ch");
53000 c.scrollTop = cbot-ch;
53003 if(hscroll !== false){
53005 c.scrollLeft = cleft;
53006 }else if(cright > sright){
53007 c.scrollLeft = cright-c.clientWidth;
53014 updateColumns : function(){
53015 this.grid.stopEditing();
53016 var cm = this.grid.colModel, colIds = this.getColumnIds();
53017 //var totalWidth = cm.getTotalWidth();
53019 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53020 //if(cm.isHidden(i)) continue;
53021 var w = cm.getColumnWidth(i);
53022 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53023 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53025 this.updateSplitters();
53028 generateRules : function(cm){
53029 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53030 Roo.util.CSS.removeStyleSheet(rulesId);
53031 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53032 var cid = cm.getColumnId(i);
53034 if(cm.config[i].align){
53035 align = 'text-align:'+cm.config[i].align+';';
53038 if(cm.isHidden(i)){
53039 hidden = 'display:none;';
53041 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53043 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53044 this.hdSelector, cid, " {\n", align, width, "}\n",
53045 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53046 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53048 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53051 updateSplitters : function(){
53052 var cm = this.cm, s = this.getSplitters();
53053 if(s){ // splitters not created yet
53054 var pos = 0, locked = true;
53055 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53056 if(cm.isHidden(i)) continue;
53057 var w = cm.getColumnWidth(i); // make sure it's a number
53058 if(!cm.isLocked(i) && locked){
53063 s[i].style.left = (pos-this.splitOffset) + "px";
53068 handleHiddenChange : function(colModel, colIndex, hidden){
53070 this.hideColumn(colIndex);
53072 this.unhideColumn(colIndex);
53076 hideColumn : function(colIndex){
53077 var cid = this.getColumnId(colIndex);
53078 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53079 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53081 this.updateHeaders();
53083 this.updateSplitters();
53087 unhideColumn : function(colIndex){
53088 var cid = this.getColumnId(colIndex);
53089 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53090 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53093 this.updateHeaders();
53095 this.updateSplitters();
53099 insertRows : function(dm, firstRow, lastRow, isUpdate){
53100 if(firstRow == 0 && lastRow == dm.getCount()-1){
53104 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53106 var s = this.getScrollState();
53107 var markup = this.renderRows(firstRow, lastRow);
53108 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53109 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53110 this.restoreScroll(s);
53112 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53113 this.syncRowHeights(firstRow, lastRow);
53114 this.stripeRows(firstRow);
53120 bufferRows : function(markup, target, index){
53121 var before = null, trows = target.rows, tbody = target.tBodies[0];
53122 if(index < trows.length){
53123 before = trows[index];
53125 var b = document.createElement("div");
53126 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53127 var rows = b.firstChild.rows;
53128 for(var i = 0, len = rows.length; i < len; i++){
53130 tbody.insertBefore(rows[0], before);
53132 tbody.appendChild(rows[0]);
53139 deleteRows : function(dm, firstRow, lastRow){
53140 if(dm.getRowCount()<1){
53141 this.fireEvent("beforerefresh", this);
53142 this.mainBody.update("");
53143 this.lockedBody.update("");
53144 this.fireEvent("refresh", this);
53146 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53147 var bt = this.getBodyTable();
53148 var tbody = bt.firstChild;
53149 var rows = bt.rows;
53150 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53151 tbody.removeChild(rows[firstRow]);
53153 this.stripeRows(firstRow);
53154 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53158 updateRows : function(dataSource, firstRow, lastRow){
53159 var s = this.getScrollState();
53161 this.restoreScroll(s);
53164 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53168 this.updateHeaderSortState();
53171 getScrollState : function(){
53173 var sb = this.scroller.dom;
53174 return {left: sb.scrollLeft, top: sb.scrollTop};
53177 stripeRows : function(startRow){
53178 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53181 startRow = startRow || 0;
53182 var rows = this.getBodyTable().rows;
53183 var lrows = this.getLockedTable().rows;
53184 var cls = ' x-grid-row-alt ';
53185 for(var i = startRow, len = rows.length; i < len; i++){
53186 var row = rows[i], lrow = lrows[i];
53187 var isAlt = ((i+1) % 2 == 0);
53188 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53189 if(isAlt == hasAlt){
53193 row.className += " x-grid-row-alt";
53195 row.className = row.className.replace("x-grid-row-alt", "");
53198 lrow.className = row.className;
53203 restoreScroll : function(state){
53204 //Roo.log('GridView.restoreScroll');
53205 var sb = this.scroller.dom;
53206 sb.scrollLeft = state.left;
53207 sb.scrollTop = state.top;
53211 syncScroll : function(){
53212 //Roo.log('GridView.syncScroll');
53213 var sb = this.scroller.dom;
53214 var sh = this.mainHd.dom;
53215 var bs = this.mainBody.dom;
53216 var lv = this.lockedBody.dom;
53217 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53218 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53221 handleScroll : function(e){
53223 var sb = this.scroller.dom;
53224 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53228 handleWheel : function(e){
53229 var d = e.getWheelDelta();
53230 this.scroller.dom.scrollTop -= d*22;
53231 // set this here to prevent jumpy scrolling on large tables
53232 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53236 renderRows : function(startRow, endRow){
53237 // pull in all the crap needed to render rows
53238 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53239 var colCount = cm.getColumnCount();
53241 if(ds.getCount() < 1){
53245 // build a map for all the columns
53247 for(var i = 0; i < colCount; i++){
53248 var name = cm.getDataIndex(i);
53250 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53251 renderer : cm.getRenderer(i),
53252 id : cm.getColumnId(i),
53253 locked : cm.isLocked(i)
53257 startRow = startRow || 0;
53258 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53260 // records to render
53261 var rs = ds.getRange(startRow, endRow);
53263 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53266 // As much as I hate to duplicate code, this was branched because FireFox really hates
53267 // [].join("") on strings. The performance difference was substantial enough to
53268 // branch this function
53269 doRender : Roo.isGecko ?
53270 function(cs, rs, ds, startRow, colCount, stripe){
53271 var ts = this.templates, ct = ts.cell, rt = ts.row;
53273 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53275 var hasListener = this.grid.hasListener('rowclass');
53277 for(var j = 0, len = rs.length; j < len; j++){
53278 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53279 for(var i = 0; i < colCount; i++){
53281 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53283 p.css = p.attr = "";
53284 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53285 if(p.value == undefined || p.value === "") p.value = " ";
53286 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53287 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53289 var markup = ct.apply(p);
53297 if(stripe && ((rowIndex+1) % 2 == 0)){
53298 alt.push("x-grid-row-alt")
53301 alt.push( " x-grid-dirty-row");
53304 if(this.getRowClass){
53305 alt.push(this.getRowClass(r, rowIndex));
53311 rowIndex : rowIndex,
53314 this.grid.fireEvent('rowclass', this, rowcfg);
53315 alt.push(rowcfg.rowClass);
53317 rp.alt = alt.join(" ");
53318 lbuf+= rt.apply(rp);
53320 buf+= rt.apply(rp);
53322 return [lbuf, buf];
53324 function(cs, rs, ds, startRow, colCount, stripe){
53325 var ts = this.templates, ct = ts.cell, rt = ts.row;
53327 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53328 var hasListener = this.grid.hasListener('rowclass');
53331 for(var j = 0, len = rs.length; j < len; j++){
53332 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53333 for(var i = 0; i < colCount; i++){
53335 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53337 p.css = p.attr = "";
53338 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53339 if(p.value == undefined || p.value === "") p.value = " ";
53340 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53341 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53344 var markup = ct.apply(p);
53346 cb[cb.length] = markup;
53348 lcb[lcb.length] = markup;
53352 if(stripe && ((rowIndex+1) % 2 == 0)){
53353 alt.push( "x-grid-row-alt");
53356 alt.push(" x-grid-dirty-row");
53359 if(this.getRowClass){
53360 alt.push( this.getRowClass(r, rowIndex));
53366 rowIndex : rowIndex,
53369 this.grid.fireEvent('rowclass', this, rowcfg);
53370 alt.push(rowcfg.rowClass);
53372 rp.alt = alt.join(" ");
53373 rp.cells = lcb.join("");
53374 lbuf[lbuf.length] = rt.apply(rp);
53375 rp.cells = cb.join("");
53376 buf[buf.length] = rt.apply(rp);
53378 return [lbuf.join(""), buf.join("")];
53381 renderBody : function(){
53382 var markup = this.renderRows();
53383 var bt = this.templates.body;
53384 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53388 * Refreshes the grid
53389 * @param {Boolean} headersToo
53391 refresh : function(headersToo){
53392 this.fireEvent("beforerefresh", this);
53393 this.grid.stopEditing();
53394 var result = this.renderBody();
53395 this.lockedBody.update(result[0]);
53396 this.mainBody.update(result[1]);
53397 if(headersToo === true){
53398 this.updateHeaders();
53399 this.updateColumns();
53400 this.updateSplitters();
53401 this.updateHeaderSortState();
53403 this.syncRowHeights();
53405 this.fireEvent("refresh", this);
53408 handleColumnMove : function(cm, oldIndex, newIndex){
53409 this.indexMap = null;
53410 var s = this.getScrollState();
53411 this.refresh(true);
53412 this.restoreScroll(s);
53413 this.afterMove(newIndex);
53416 afterMove : function(colIndex){
53417 if(this.enableMoveAnim && Roo.enableFx){
53418 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53420 // if multisort - fix sortOrder, and reload..
53421 if (this.grid.dataSource.multiSort) {
53422 // the we can call sort again..
53423 var dm = this.grid.dataSource;
53424 var cm = this.grid.colModel;
53426 for(var i = 0; i < cm.config.length; i++ ) {
53428 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53429 continue; // dont' bother, it's not in sort list or being set.
53432 so.push(cm.config[i].dataIndex);
53435 dm.load(dm.lastOptions);
53442 updateCell : function(dm, rowIndex, dataIndex){
53443 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53444 if(typeof colIndex == "undefined"){ // not present in grid
53447 var cm = this.grid.colModel;
53448 var cell = this.getCell(rowIndex, colIndex);
53449 var cellText = this.getCellText(rowIndex, colIndex);
53452 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53453 id : cm.getColumnId(colIndex),
53454 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53456 var renderer = cm.getRenderer(colIndex);
53457 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53458 if(typeof val == "undefined" || val === "") val = " ";
53459 cellText.innerHTML = val;
53460 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53461 this.syncRowHeights(rowIndex, rowIndex);
53464 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53466 if(this.grid.autoSizeHeaders){
53467 var h = this.getHeaderCellMeasure(colIndex);
53468 maxWidth = Math.max(maxWidth, h.scrollWidth);
53471 if(this.cm.isLocked(colIndex)){
53472 tb = this.getLockedTable();
53475 tb = this.getBodyTable();
53476 index = colIndex - this.cm.getLockedCount();
53479 var rows = tb.rows;
53480 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53481 for(var i = 0; i < stopIndex; i++){
53482 var cell = rows[i].childNodes[index].firstChild;
53483 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53486 return maxWidth + /*margin for error in IE*/ 5;
53489 * Autofit a column to its content.
53490 * @param {Number} colIndex
53491 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53493 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53494 if(this.cm.isHidden(colIndex)){
53495 return; // can't calc a hidden column
53498 var cid = this.cm.getColumnId(colIndex);
53499 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53500 if(this.grid.autoSizeHeaders){
53501 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53504 var newWidth = this.calcColumnWidth(colIndex);
53505 this.cm.setColumnWidth(colIndex,
53506 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53507 if(!suppressEvent){
53508 this.grid.fireEvent("columnresize", colIndex, newWidth);
53513 * Autofits all columns to their content and then expands to fit any extra space in the grid
53515 autoSizeColumns : function(){
53516 var cm = this.grid.colModel;
53517 var colCount = cm.getColumnCount();
53518 for(var i = 0; i < colCount; i++){
53519 this.autoSizeColumn(i, true, true);
53521 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53524 this.updateColumns();
53530 * Autofits all columns to the grid's width proportionate with their current size
53531 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53533 fitColumns : function(reserveScrollSpace){
53534 var cm = this.grid.colModel;
53535 var colCount = cm.getColumnCount();
53539 for (i = 0; i < colCount; i++){
53540 if(!cm.isHidden(i) && !cm.isFixed(i)){
53541 w = cm.getColumnWidth(i);
53547 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53548 if(reserveScrollSpace){
53551 var frac = (avail - cm.getTotalWidth())/width;
53552 while (cols.length){
53555 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53557 this.updateColumns();
53561 onRowSelect : function(rowIndex){
53562 var row = this.getRowComposite(rowIndex);
53563 row.addClass("x-grid-row-selected");
53566 onRowDeselect : function(rowIndex){
53567 var row = this.getRowComposite(rowIndex);
53568 row.removeClass("x-grid-row-selected");
53571 onCellSelect : function(row, col){
53572 var cell = this.getCell(row, col);
53574 Roo.fly(cell).addClass("x-grid-cell-selected");
53578 onCellDeselect : function(row, col){
53579 var cell = this.getCell(row, col);
53581 Roo.fly(cell).removeClass("x-grid-cell-selected");
53585 updateHeaderSortState : function(){
53587 // sort state can be single { field: xxx, direction : yyy}
53588 // or { xxx=>ASC , yyy : DESC ..... }
53591 if (!this.ds.multiSort) {
53592 var state = this.ds.getSortState();
53596 mstate[state.field] = state.direction;
53597 // FIXME... - this is not used here.. but might be elsewhere..
53598 this.sortState = state;
53601 mstate = this.ds.sortToggle;
53603 //remove existing sort classes..
53605 var sc = this.sortClasses;
53606 var hds = this.el.select(this.headerSelector).removeClass(sc);
53608 for(var f in mstate) {
53610 var sortColumn = this.cm.findColumnIndex(f);
53612 if(sortColumn != -1){
53613 var sortDir = mstate[f];
53614 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53623 handleHeaderClick : function(g, index,e){
53625 Roo.log("header click");
53628 // touch events on header are handled by context
53629 this.handleHdCtx(g,index,e);
53634 if(this.headersDisabled){
53637 var dm = g.dataSource, cm = g.colModel;
53638 if(!cm.isSortable(index)){
53643 if (dm.multiSort) {
53644 // update the sortOrder
53646 for(var i = 0; i < cm.config.length; i++ ) {
53648 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53649 continue; // dont' bother, it's not in sort list or being set.
53652 so.push(cm.config[i].dataIndex);
53658 dm.sort(cm.getDataIndex(index));
53662 destroy : function(){
53664 this.colMenu.removeAll();
53665 Roo.menu.MenuMgr.unregister(this.colMenu);
53666 this.colMenu.getEl().remove();
53667 delete this.colMenu;
53670 this.hmenu.removeAll();
53671 Roo.menu.MenuMgr.unregister(this.hmenu);
53672 this.hmenu.getEl().remove();
53675 if(this.grid.enableColumnMove){
53676 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53678 for(var dd in dds){
53679 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53680 var elid = dds[dd].dragElId;
53682 Roo.get(elid).remove();
53683 } else if(dds[dd].config.isTarget){
53684 dds[dd].proxyTop.remove();
53685 dds[dd].proxyBottom.remove();
53688 if(Roo.dd.DDM.locationCache[dd]){
53689 delete Roo.dd.DDM.locationCache[dd];
53692 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53695 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53696 this.bind(null, null);
53697 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53700 handleLockChange : function(){
53701 this.refresh(true);
53704 onDenyColumnLock : function(){
53708 onDenyColumnHide : function(){
53712 handleHdMenuClick : function(item){
53713 var index = this.hdCtxIndex;
53714 var cm = this.cm, ds = this.ds;
53717 ds.sort(cm.getDataIndex(index), "ASC");
53720 ds.sort(cm.getDataIndex(index), "DESC");
53723 var lc = cm.getLockedCount();
53724 if(cm.getColumnCount(true) <= lc+1){
53725 this.onDenyColumnLock();
53729 cm.setLocked(index, true, true);
53730 cm.moveColumn(index, lc);
53731 this.grid.fireEvent("columnmove", index, lc);
53733 cm.setLocked(index, true);
53737 var lc = cm.getLockedCount();
53738 if((lc-1) != index){
53739 cm.setLocked(index, false, true);
53740 cm.moveColumn(index, lc-1);
53741 this.grid.fireEvent("columnmove", index, lc-1);
53743 cm.setLocked(index, false);
53746 case 'wider': // used to expand cols on touch..
53748 var cw = cm.getColumnWidth(index);
53749 cw += (item.id == 'wider' ? 1 : -1) * 50;
53750 cw = Math.max(0, cw);
53751 cw = Math.min(cw,4000);
53752 cm.setColumnWidth(index, cw);
53756 index = cm.getIndexById(item.id.substr(4));
53758 if(item.checked && cm.getColumnCount(true) <= 1){
53759 this.onDenyColumnHide();
53762 cm.setHidden(index, item.checked);
53768 beforeColMenuShow : function(){
53769 var cm = this.cm, colCount = cm.getColumnCount();
53770 this.colMenu.removeAll();
53771 for(var i = 0; i < colCount; i++){
53772 this.colMenu.add(new Roo.menu.CheckItem({
53773 id: "col-"+cm.getColumnId(i),
53774 text: cm.getColumnHeader(i),
53775 checked: !cm.isHidden(i),
53781 handleHdCtx : function(g, index, e){
53783 var hd = this.getHeaderCell(index);
53784 this.hdCtxIndex = index;
53785 var ms = this.hmenu.items, cm = this.cm;
53786 ms.get("asc").setDisabled(!cm.isSortable(index));
53787 ms.get("desc").setDisabled(!cm.isSortable(index));
53788 if(this.grid.enableColLock !== false){
53789 ms.get("lock").setDisabled(cm.isLocked(index));
53790 ms.get("unlock").setDisabled(!cm.isLocked(index));
53792 this.hmenu.show(hd, "tl-bl");
53795 handleHdOver : function(e){
53796 var hd = this.findHeaderCell(e.getTarget());
53797 if(hd && !this.headersDisabled){
53798 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
53799 this.fly(hd).addClass("x-grid-hd-over");
53804 handleHdOut : function(e){
53805 var hd = this.findHeaderCell(e.getTarget());
53807 this.fly(hd).removeClass("x-grid-hd-over");
53811 handleSplitDblClick : function(e, t){
53812 var i = this.getCellIndex(t);
53813 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
53814 this.autoSizeColumn(i, true);
53819 render : function(){
53822 var colCount = cm.getColumnCount();
53824 if(this.grid.monitorWindowResize === true){
53825 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53827 var header = this.renderHeaders();
53828 var body = this.templates.body.apply({rows:""});
53829 var html = this.templates.master.apply({
53832 lockedHeader: header[0],
53836 //this.updateColumns();
53838 this.grid.getGridEl().dom.innerHTML = html;
53840 this.initElements();
53842 // a kludge to fix the random scolling effect in webkit
53843 this.el.on("scroll", function() {
53844 this.el.dom.scrollTop=0; // hopefully not recursive..
53847 this.scroller.on("scroll", this.handleScroll, this);
53848 this.lockedBody.on("mousewheel", this.handleWheel, this);
53849 this.mainBody.on("mousewheel", this.handleWheel, this);
53851 this.mainHd.on("mouseover", this.handleHdOver, this);
53852 this.mainHd.on("mouseout", this.handleHdOut, this);
53853 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
53854 {delegate: "."+this.splitClass});
53856 this.lockedHd.on("mouseover", this.handleHdOver, this);
53857 this.lockedHd.on("mouseout", this.handleHdOut, this);
53858 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
53859 {delegate: "."+this.splitClass});
53861 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
53862 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53865 this.updateSplitters();
53867 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
53868 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53869 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53872 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
53873 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
53875 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
53876 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
53878 if(this.grid.enableColLock !== false){
53879 this.hmenu.add('-',
53880 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
53881 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
53885 this.hmenu.add('-',
53886 {id:"wider", text: this.columnsWiderText},
53887 {id:"narrow", text: this.columnsNarrowText }
53893 if(this.grid.enableColumnHide !== false){
53895 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
53896 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
53897 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
53899 this.hmenu.add('-',
53900 {id:"columns", text: this.columnsText, menu: this.colMenu}
53903 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
53905 this.grid.on("headercontextmenu", this.handleHdCtx, this);
53908 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
53909 this.dd = new Roo.grid.GridDragZone(this.grid, {
53910 ddGroup : this.grid.ddGroup || 'GridDD'
53916 for(var i = 0; i < colCount; i++){
53917 if(cm.isHidden(i)){
53918 this.hideColumn(i);
53920 if(cm.config[i].align){
53921 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
53922 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
53926 this.updateHeaderSortState();
53928 this.beforeInitialResize();
53931 // two part rendering gives faster view to the user
53932 this.renderPhase2.defer(1, this);
53935 renderPhase2 : function(){
53936 // render the rows now
53938 if(this.grid.autoSizeColumns){
53939 this.autoSizeColumns();
53943 beforeInitialResize : function(){
53947 onColumnSplitterMoved : function(i, w){
53948 this.userResized = true;
53949 var cm = this.grid.colModel;
53950 cm.setColumnWidth(i, w, true);
53951 var cid = cm.getColumnId(i);
53952 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53953 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53954 this.updateSplitters();
53956 this.grid.fireEvent("columnresize", i, w);
53959 syncRowHeights : function(startIndex, endIndex){
53960 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
53961 startIndex = startIndex || 0;
53962 var mrows = this.getBodyTable().rows;
53963 var lrows = this.getLockedTable().rows;
53964 var len = mrows.length-1;
53965 endIndex = Math.min(endIndex || len, len);
53966 for(var i = startIndex; i <= endIndex; i++){
53967 var m = mrows[i], l = lrows[i];
53968 var h = Math.max(m.offsetHeight, l.offsetHeight);
53969 m.style.height = l.style.height = h + "px";
53974 layout : function(initialRender, is2ndPass){
53976 var auto = g.autoHeight;
53977 var scrollOffset = 16;
53978 var c = g.getGridEl(), cm = this.cm,
53979 expandCol = g.autoExpandColumn,
53981 //c.beginMeasure();
53983 if(!c.dom.offsetWidth){ // display:none?
53985 this.lockedWrap.show();
53986 this.mainWrap.show();
53991 var hasLock = this.cm.isLocked(0);
53993 var tbh = this.headerPanel.getHeight();
53994 var bbh = this.footerPanel.getHeight();
53997 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
53998 var newHeight = ch + c.getBorderWidth("tb");
54000 newHeight = Math.min(g.maxHeight, newHeight);
54002 c.setHeight(newHeight);
54006 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54009 var s = this.scroller;
54011 var csize = c.getSize(true);
54013 this.el.setSize(csize.width, csize.height);
54015 this.headerPanel.setWidth(csize.width);
54016 this.footerPanel.setWidth(csize.width);
54018 var hdHeight = this.mainHd.getHeight();
54019 var vw = csize.width;
54020 var vh = csize.height - (tbh + bbh);
54024 var bt = this.getBodyTable();
54025 var ltWidth = hasLock ?
54026 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54028 var scrollHeight = bt.offsetHeight;
54029 var scrollWidth = ltWidth + bt.offsetWidth;
54030 var vscroll = false, hscroll = false;
54032 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54034 var lw = this.lockedWrap, mw = this.mainWrap;
54035 var lb = this.lockedBody, mb = this.mainBody;
54037 setTimeout(function(){
54038 var t = s.dom.offsetTop;
54039 var w = s.dom.clientWidth,
54040 h = s.dom.clientHeight;
54043 lw.setSize(ltWidth, h);
54045 mw.setLeftTop(ltWidth, t);
54046 mw.setSize(w-ltWidth, h);
54048 lb.setHeight(h-hdHeight);
54049 mb.setHeight(h-hdHeight);
54051 if(is2ndPass !== true && !gv.userResized && expandCol){
54052 // high speed resize without full column calculation
54054 var ci = cm.getIndexById(expandCol);
54056 ci = cm.findColumnIndex(expandCol);
54058 ci = Math.max(0, ci); // make sure it's got at least the first col.
54059 var expandId = cm.getColumnId(ci);
54060 var tw = cm.getTotalWidth(false);
54061 var currentWidth = cm.getColumnWidth(ci);
54062 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54063 if(currentWidth != cw){
54064 cm.setColumnWidth(ci, cw, true);
54065 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54066 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54067 gv.updateSplitters();
54068 gv.layout(false, true);
54080 onWindowResize : function(){
54081 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54087 appendFooter : function(parentEl){
54091 sortAscText : "Sort Ascending",
54092 sortDescText : "Sort Descending",
54093 lockText : "Lock Column",
54094 unlockText : "Unlock Column",
54095 columnsText : "Columns",
54097 columnsWiderText : "Wider",
54098 columnsNarrowText : "Thinner"
54102 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54103 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54104 this.proxy.el.addClass('x-grid3-col-dd');
54107 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54108 handleMouseDown : function(e){
54112 callHandleMouseDown : function(e){
54113 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54118 * Ext JS Library 1.1.1
54119 * Copyright(c) 2006-2007, Ext JS, LLC.
54121 * Originally Released Under LGPL - original licence link has changed is not relivant.
54124 * <script type="text/javascript">
54128 // This is a support class used internally by the Grid components
54129 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54131 this.view = grid.getView();
54132 this.proxy = this.view.resizeProxy;
54133 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54134 "gridSplitters" + this.grid.getGridEl().id, {
54135 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54137 this.setHandleElId(Roo.id(hd));
54138 this.setOuterHandleElId(Roo.id(hd2));
54139 this.scroll = false;
54141 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54142 fly: Roo.Element.fly,
54144 b4StartDrag : function(x, y){
54145 this.view.headersDisabled = true;
54146 this.proxy.setHeight(this.view.mainWrap.getHeight());
54147 var w = this.cm.getColumnWidth(this.cellIndex);
54148 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54149 this.resetConstraints();
54150 this.setXConstraint(minw, 1000);
54151 this.setYConstraint(0, 0);
54152 this.minX = x - minw;
54153 this.maxX = x + 1000;
54155 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54159 handleMouseDown : function(e){
54160 ev = Roo.EventObject.setEvent(e);
54161 var t = this.fly(ev.getTarget());
54162 if(t.hasClass("x-grid-split")){
54163 this.cellIndex = this.view.getCellIndex(t.dom);
54164 this.split = t.dom;
54165 this.cm = this.grid.colModel;
54166 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54167 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54172 endDrag : function(e){
54173 this.view.headersDisabled = false;
54174 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54175 var diff = endX - this.startPos;
54176 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54179 autoOffset : function(){
54180 this.setDelta(0,0);
54184 * Ext JS Library 1.1.1
54185 * Copyright(c) 2006-2007, Ext JS, LLC.
54187 * Originally Released Under LGPL - original licence link has changed is not relivant.
54190 * <script type="text/javascript">
54194 // This is a support class used internally by the Grid components
54195 Roo.grid.GridDragZone = function(grid, config){
54196 this.view = grid.getView();
54197 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54198 if(this.view.lockedBody){
54199 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54200 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54202 this.scroll = false;
54204 this.ddel = document.createElement('div');
54205 this.ddel.className = 'x-grid-dd-wrap';
54208 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54209 ddGroup : "GridDD",
54211 getDragData : function(e){
54212 var t = Roo.lib.Event.getTarget(e);
54213 var rowIndex = this.view.findRowIndex(t);
54214 var sm = this.grid.selModel;
54216 //Roo.log(rowIndex);
54218 if (sm.getSelectedCell) {
54219 // cell selection..
54220 if (!sm.getSelectedCell()) {
54223 if (rowIndex != sm.getSelectedCell()[0]) {
54229 if(rowIndex !== false){
54234 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54236 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54239 if (e.hasModifier()){
54240 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54243 Roo.log("getDragData");
54248 rowIndex: rowIndex,
54249 selections:sm.getSelections ? sm.getSelections() : (
54250 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54257 onInitDrag : function(e){
54258 var data = this.dragData;
54259 this.ddel.innerHTML = this.grid.getDragDropText();
54260 this.proxy.update(this.ddel);
54261 // fire start drag?
54264 afterRepair : function(){
54265 this.dragging = false;
54268 getRepairXY : function(e, data){
54272 onEndDrag : function(data, e){
54276 onValidDrop : function(dd, e, id){
54281 beforeInvalidDrop : function(e, id){
54286 * Ext JS Library 1.1.1
54287 * Copyright(c) 2006-2007, Ext JS, LLC.
54289 * Originally Released Under LGPL - original licence link has changed is not relivant.
54292 * <script type="text/javascript">
54297 * @class Roo.grid.ColumnModel
54298 * @extends Roo.util.Observable
54299 * This is the default implementation of a ColumnModel used by the Grid. It defines
54300 * the columns in the grid.
54303 var colModel = new Roo.grid.ColumnModel([
54304 {header: "Ticker", width: 60, sortable: true, locked: true},
54305 {header: "Company Name", width: 150, sortable: true},
54306 {header: "Market Cap.", width: 100, sortable: true},
54307 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54308 {header: "Employees", width: 100, sortable: true, resizable: false}
54313 * The config options listed for this class are options which may appear in each
54314 * individual column definition.
54315 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54317 * @param {Object} config An Array of column config objects. See this class's
54318 * config objects for details.
54320 Roo.grid.ColumnModel = function(config){
54322 * The config passed into the constructor
54324 this.config = config;
54327 // if no id, create one
54328 // if the column does not have a dataIndex mapping,
54329 // map it to the order it is in the config
54330 for(var i = 0, len = config.length; i < len; i++){
54332 if(typeof c.dataIndex == "undefined"){
54335 if(typeof c.renderer == "string"){
54336 c.renderer = Roo.util.Format[c.renderer];
54338 if(typeof c.id == "undefined"){
54341 if(c.editor && c.editor.xtype){
54342 c.editor = Roo.factory(c.editor, Roo.grid);
54344 if(c.editor && c.editor.isFormField){
54345 c.editor = new Roo.grid.GridEditor(c.editor);
54347 this.lookup[c.id] = c;
54351 * The width of columns which have no width specified (defaults to 100)
54354 this.defaultWidth = 100;
54357 * Default sortable of columns which have no sortable specified (defaults to false)
54360 this.defaultSortable = false;
54364 * @event widthchange
54365 * Fires when the width of a column changes.
54366 * @param {ColumnModel} this
54367 * @param {Number} columnIndex The column index
54368 * @param {Number} newWidth The new width
54370 "widthchange": true,
54372 * @event headerchange
54373 * Fires when the text of a header changes.
54374 * @param {ColumnModel} this
54375 * @param {Number} columnIndex The column index
54376 * @param {Number} newText The new header text
54378 "headerchange": true,
54380 * @event hiddenchange
54381 * Fires when a column is hidden or "unhidden".
54382 * @param {ColumnModel} this
54383 * @param {Number} columnIndex The column index
54384 * @param {Boolean} hidden true if hidden, false otherwise
54386 "hiddenchange": true,
54388 * @event columnmoved
54389 * Fires when a column is moved.
54390 * @param {ColumnModel} this
54391 * @param {Number} oldIndex
54392 * @param {Number} newIndex
54394 "columnmoved" : true,
54396 * @event columlockchange
54397 * Fires when a column's locked state is changed
54398 * @param {ColumnModel} this
54399 * @param {Number} colIndex
54400 * @param {Boolean} locked true if locked
54402 "columnlockchange" : true
54404 Roo.grid.ColumnModel.superclass.constructor.call(this);
54406 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54408 * @cfg {String} header The header text to display in the Grid view.
54411 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54412 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54413 * specified, the column's index is used as an index into the Record's data Array.
54416 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54417 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54420 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54421 * Defaults to the value of the {@link #defaultSortable} property.
54422 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54425 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54428 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54431 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54434 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54437 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54438 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54439 * default renderer uses the raw data value.
54442 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54445 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54449 * Returns the id of the column at the specified index.
54450 * @param {Number} index The column index
54451 * @return {String} the id
54453 getColumnId : function(index){
54454 return this.config[index].id;
54458 * Returns the column for a specified id.
54459 * @param {String} id The column id
54460 * @return {Object} the column
54462 getColumnById : function(id){
54463 return this.lookup[id];
54468 * Returns the column for a specified dataIndex.
54469 * @param {String} dataIndex The column dataIndex
54470 * @return {Object|Boolean} the column or false if not found
54472 getColumnByDataIndex: function(dataIndex){
54473 var index = this.findColumnIndex(dataIndex);
54474 return index > -1 ? this.config[index] : false;
54478 * Returns the index for a specified column id.
54479 * @param {String} id The column id
54480 * @return {Number} the index, or -1 if not found
54482 getIndexById : function(id){
54483 for(var i = 0, len = this.config.length; i < len; i++){
54484 if(this.config[i].id == id){
54492 * Returns the index for a specified column dataIndex.
54493 * @param {String} dataIndex The column dataIndex
54494 * @return {Number} the index, or -1 if not found
54497 findColumnIndex : function(dataIndex){
54498 for(var i = 0, len = this.config.length; i < len; i++){
54499 if(this.config[i].dataIndex == dataIndex){
54507 moveColumn : function(oldIndex, newIndex){
54508 var c = this.config[oldIndex];
54509 this.config.splice(oldIndex, 1);
54510 this.config.splice(newIndex, 0, c);
54511 this.dataMap = null;
54512 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54515 isLocked : function(colIndex){
54516 return this.config[colIndex].locked === true;
54519 setLocked : function(colIndex, value, suppressEvent){
54520 if(this.isLocked(colIndex) == value){
54523 this.config[colIndex].locked = value;
54524 if(!suppressEvent){
54525 this.fireEvent("columnlockchange", this, colIndex, value);
54529 getTotalLockedWidth : function(){
54530 var totalWidth = 0;
54531 for(var i = 0; i < this.config.length; i++){
54532 if(this.isLocked(i) && !this.isHidden(i)){
54533 this.totalWidth += this.getColumnWidth(i);
54539 getLockedCount : function(){
54540 for(var i = 0, len = this.config.length; i < len; i++){
54541 if(!this.isLocked(i)){
54548 * Returns the number of columns.
54551 getColumnCount : function(visibleOnly){
54552 if(visibleOnly === true){
54554 for(var i = 0, len = this.config.length; i < len; i++){
54555 if(!this.isHidden(i)){
54561 return this.config.length;
54565 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54566 * @param {Function} fn
54567 * @param {Object} scope (optional)
54568 * @return {Array} result
54570 getColumnsBy : function(fn, scope){
54572 for(var i = 0, len = this.config.length; i < len; i++){
54573 var c = this.config[i];
54574 if(fn.call(scope||this, c, i) === true){
54582 * Returns true if the specified column is sortable.
54583 * @param {Number} col The column index
54584 * @return {Boolean}
54586 isSortable : function(col){
54587 if(typeof this.config[col].sortable == "undefined"){
54588 return this.defaultSortable;
54590 return this.config[col].sortable;
54594 * Returns the rendering (formatting) function defined for the column.
54595 * @param {Number} col The column index.
54596 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54598 getRenderer : function(col){
54599 if(!this.config[col].renderer){
54600 return Roo.grid.ColumnModel.defaultRenderer;
54602 return this.config[col].renderer;
54606 * Sets the rendering (formatting) function for a column.
54607 * @param {Number} col The column index
54608 * @param {Function} fn The function to use to process the cell's raw data
54609 * to return HTML markup for the grid view. The render function is called with
54610 * the following parameters:<ul>
54611 * <li>Data value.</li>
54612 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54613 * <li>css A CSS style string to apply to the table cell.</li>
54614 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54615 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54616 * <li>Row index</li>
54617 * <li>Column index</li>
54618 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54620 setRenderer : function(col, fn){
54621 this.config[col].renderer = fn;
54625 * Returns the width for the specified column.
54626 * @param {Number} col The column index
54629 getColumnWidth : function(col){
54630 return this.config[col].width * 1 || this.defaultWidth;
54634 * Sets the width for a column.
54635 * @param {Number} col The column index
54636 * @param {Number} width The new width
54638 setColumnWidth : function(col, width, suppressEvent){
54639 this.config[col].width = width;
54640 this.totalWidth = null;
54641 if(!suppressEvent){
54642 this.fireEvent("widthchange", this, col, width);
54647 * Returns the total width of all columns.
54648 * @param {Boolean} includeHidden True to include hidden column widths
54651 getTotalWidth : function(includeHidden){
54652 if(!this.totalWidth){
54653 this.totalWidth = 0;
54654 for(var i = 0, len = this.config.length; i < len; i++){
54655 if(includeHidden || !this.isHidden(i)){
54656 this.totalWidth += this.getColumnWidth(i);
54660 return this.totalWidth;
54664 * Returns the header for the specified column.
54665 * @param {Number} col The column index
54668 getColumnHeader : function(col){
54669 return this.config[col].header;
54673 * Sets the header for a column.
54674 * @param {Number} col The column index
54675 * @param {String} header The new header
54677 setColumnHeader : function(col, header){
54678 this.config[col].header = header;
54679 this.fireEvent("headerchange", this, col, header);
54683 * Returns the tooltip for the specified column.
54684 * @param {Number} col The column index
54687 getColumnTooltip : function(col){
54688 return this.config[col].tooltip;
54691 * Sets the tooltip for a column.
54692 * @param {Number} col The column index
54693 * @param {String} tooltip The new tooltip
54695 setColumnTooltip : function(col, tooltip){
54696 this.config[col].tooltip = tooltip;
54700 * Returns the dataIndex for the specified column.
54701 * @param {Number} col The column index
54704 getDataIndex : function(col){
54705 return this.config[col].dataIndex;
54709 * Sets the dataIndex for a column.
54710 * @param {Number} col The column index
54711 * @param {Number} dataIndex The new dataIndex
54713 setDataIndex : function(col, dataIndex){
54714 this.config[col].dataIndex = dataIndex;
54720 * Returns true if the cell is editable.
54721 * @param {Number} colIndex The column index
54722 * @param {Number} rowIndex The row index
54723 * @return {Boolean}
54725 isCellEditable : function(colIndex, rowIndex){
54726 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
54730 * Returns the editor defined for the cell/column.
54731 * return false or null to disable editing.
54732 * @param {Number} colIndex The column index
54733 * @param {Number} rowIndex The row index
54736 getCellEditor : function(colIndex, rowIndex){
54737 return this.config[colIndex].editor;
54741 * Sets if a column is editable.
54742 * @param {Number} col The column index
54743 * @param {Boolean} editable True if the column is editable
54745 setEditable : function(col, editable){
54746 this.config[col].editable = editable;
54751 * Returns true if the column is hidden.
54752 * @param {Number} colIndex The column index
54753 * @return {Boolean}
54755 isHidden : function(colIndex){
54756 return this.config[colIndex].hidden;
54761 * Returns true if the column width cannot be changed
54763 isFixed : function(colIndex){
54764 return this.config[colIndex].fixed;
54768 * Returns true if the column can be resized
54769 * @return {Boolean}
54771 isResizable : function(colIndex){
54772 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
54775 * Sets if a column is hidden.
54776 * @param {Number} colIndex The column index
54777 * @param {Boolean} hidden True if the column is hidden
54779 setHidden : function(colIndex, hidden){
54780 this.config[colIndex].hidden = hidden;
54781 this.totalWidth = null;
54782 this.fireEvent("hiddenchange", this, colIndex, hidden);
54786 * Sets the editor for a column.
54787 * @param {Number} col The column index
54788 * @param {Object} editor The editor object
54790 setEditor : function(col, editor){
54791 this.config[col].editor = editor;
54795 Roo.grid.ColumnModel.defaultRenderer = function(value){
54796 if(typeof value == "string" && value.length < 1){
54802 // Alias for backwards compatibility
54803 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
54806 * Ext JS Library 1.1.1
54807 * Copyright(c) 2006-2007, Ext JS, LLC.
54809 * Originally Released Under LGPL - original licence link has changed is not relivant.
54812 * <script type="text/javascript">
54816 * @class Roo.grid.AbstractSelectionModel
54817 * @extends Roo.util.Observable
54818 * Abstract base class for grid SelectionModels. It provides the interface that should be
54819 * implemented by descendant classes. This class should not be directly instantiated.
54822 Roo.grid.AbstractSelectionModel = function(){
54823 this.locked = false;
54824 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
54827 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
54828 /** @ignore Called by the grid automatically. Do not call directly. */
54829 init : function(grid){
54835 * Locks the selections.
54838 this.locked = true;
54842 * Unlocks the selections.
54844 unlock : function(){
54845 this.locked = false;
54849 * Returns true if the selections are locked.
54850 * @return {Boolean}
54852 isLocked : function(){
54853 return this.locked;
54857 * Ext JS Library 1.1.1
54858 * Copyright(c) 2006-2007, Ext JS, LLC.
54860 * Originally Released Under LGPL - original licence link has changed is not relivant.
54863 * <script type="text/javascript">
54866 * @extends Roo.grid.AbstractSelectionModel
54867 * @class Roo.grid.RowSelectionModel
54868 * The default SelectionModel used by {@link Roo.grid.Grid}.
54869 * It supports multiple selections and keyboard selection/navigation.
54871 * @param {Object} config
54873 Roo.grid.RowSelectionModel = function(config){
54874 Roo.apply(this, config);
54875 this.selections = new Roo.util.MixedCollection(false, function(o){
54880 this.lastActive = false;
54884 * @event selectionchange
54885 * Fires when the selection changes
54886 * @param {SelectionModel} this
54888 "selectionchange" : true,
54890 * @event afterselectionchange
54891 * Fires after the selection changes (eg. by key press or clicking)
54892 * @param {SelectionModel} this
54894 "afterselectionchange" : true,
54896 * @event beforerowselect
54897 * Fires when a row is selected being selected, return false to cancel.
54898 * @param {SelectionModel} this
54899 * @param {Number} rowIndex The selected index
54900 * @param {Boolean} keepExisting False if other selections will be cleared
54902 "beforerowselect" : true,
54905 * Fires when a row is selected.
54906 * @param {SelectionModel} this
54907 * @param {Number} rowIndex The selected index
54908 * @param {Roo.data.Record} r The record
54910 "rowselect" : true,
54912 * @event rowdeselect
54913 * Fires when a row is deselected.
54914 * @param {SelectionModel} this
54915 * @param {Number} rowIndex The selected index
54917 "rowdeselect" : true
54919 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
54920 this.locked = false;
54923 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
54925 * @cfg {Boolean} singleSelect
54926 * True to allow selection of only one row at a time (defaults to false)
54928 singleSelect : false,
54931 initEvents : function(){
54933 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
54934 this.grid.on("mousedown", this.handleMouseDown, this);
54935 }else{ // allow click to work like normal
54936 this.grid.on("rowclick", this.handleDragableRowClick, this);
54939 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
54940 "up" : function(e){
54942 this.selectPrevious(e.shiftKey);
54943 }else if(this.last !== false && this.lastActive !== false){
54944 var last = this.last;
54945 this.selectRange(this.last, this.lastActive-1);
54946 this.grid.getView().focusRow(this.lastActive);
54947 if(last !== false){
54951 this.selectFirstRow();
54953 this.fireEvent("afterselectionchange", this);
54955 "down" : function(e){
54957 this.selectNext(e.shiftKey);
54958 }else if(this.last !== false && this.lastActive !== false){
54959 var last = this.last;
54960 this.selectRange(this.last, this.lastActive+1);
54961 this.grid.getView().focusRow(this.lastActive);
54962 if(last !== false){
54966 this.selectFirstRow();
54968 this.fireEvent("afterselectionchange", this);
54973 var view = this.grid.view;
54974 view.on("refresh", this.onRefresh, this);
54975 view.on("rowupdated", this.onRowUpdated, this);
54976 view.on("rowremoved", this.onRemove, this);
54980 onRefresh : function(){
54981 var ds = this.grid.dataSource, i, v = this.grid.view;
54982 var s = this.selections;
54983 s.each(function(r){
54984 if((i = ds.indexOfId(r.id)) != -1){
54993 onRemove : function(v, index, r){
54994 this.selections.remove(r);
54998 onRowUpdated : function(v, index, r){
54999 if(this.isSelected(r)){
55000 v.onRowSelect(index);
55006 * @param {Array} records The records to select
55007 * @param {Boolean} keepExisting (optional) True to keep existing selections
55009 selectRecords : function(records, keepExisting){
55011 this.clearSelections();
55013 var ds = this.grid.dataSource;
55014 for(var i = 0, len = records.length; i < len; i++){
55015 this.selectRow(ds.indexOf(records[i]), true);
55020 * Gets the number of selected rows.
55023 getCount : function(){
55024 return this.selections.length;
55028 * Selects the first row in the grid.
55030 selectFirstRow : function(){
55035 * Select the last row.
55036 * @param {Boolean} keepExisting (optional) True to keep existing selections
55038 selectLastRow : function(keepExisting){
55039 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55043 * Selects the row immediately following the last selected row.
55044 * @param {Boolean} keepExisting (optional) True to keep existing selections
55046 selectNext : function(keepExisting){
55047 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55048 this.selectRow(this.last+1, keepExisting);
55049 this.grid.getView().focusRow(this.last);
55054 * Selects the row that precedes the last selected row.
55055 * @param {Boolean} keepExisting (optional) True to keep existing selections
55057 selectPrevious : function(keepExisting){
55059 this.selectRow(this.last-1, keepExisting);
55060 this.grid.getView().focusRow(this.last);
55065 * Returns the selected records
55066 * @return {Array} Array of selected records
55068 getSelections : function(){
55069 return [].concat(this.selections.items);
55073 * Returns the first selected record.
55076 getSelected : function(){
55077 return this.selections.itemAt(0);
55082 * Clears all selections.
55084 clearSelections : function(fast){
55085 if(this.locked) return;
55087 var ds = this.grid.dataSource;
55088 var s = this.selections;
55089 s.each(function(r){
55090 this.deselectRow(ds.indexOfId(r.id));
55094 this.selections.clear();
55101 * Selects all rows.
55103 selectAll : function(){
55104 if(this.locked) return;
55105 this.selections.clear();
55106 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55107 this.selectRow(i, true);
55112 * Returns True if there is a selection.
55113 * @return {Boolean}
55115 hasSelection : function(){
55116 return this.selections.length > 0;
55120 * Returns True if the specified row is selected.
55121 * @param {Number/Record} record The record or index of the record to check
55122 * @return {Boolean}
55124 isSelected : function(index){
55125 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55126 return (r && this.selections.key(r.id) ? true : false);
55130 * Returns True if the specified record id is selected.
55131 * @param {String} id The id of record to check
55132 * @return {Boolean}
55134 isIdSelected : function(id){
55135 return (this.selections.key(id) ? true : false);
55139 handleMouseDown : function(e, t){
55140 var view = this.grid.getView(), rowIndex;
55141 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55144 if(e.shiftKey && this.last !== false){
55145 var last = this.last;
55146 this.selectRange(last, rowIndex, e.ctrlKey);
55147 this.last = last; // reset the last
55148 view.focusRow(rowIndex);
55150 var isSelected = this.isSelected(rowIndex);
55151 if(e.button !== 0 && isSelected){
55152 view.focusRow(rowIndex);
55153 }else if(e.ctrlKey && isSelected){
55154 this.deselectRow(rowIndex);
55155 }else if(!isSelected){
55156 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55157 view.focusRow(rowIndex);
55160 this.fireEvent("afterselectionchange", this);
55163 handleDragableRowClick : function(grid, rowIndex, e)
55165 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55166 this.selectRow(rowIndex, false);
55167 grid.view.focusRow(rowIndex);
55168 this.fireEvent("afterselectionchange", this);
55173 * Selects multiple rows.
55174 * @param {Array} rows Array of the indexes of the row to select
55175 * @param {Boolean} keepExisting (optional) True to keep existing selections
55177 selectRows : function(rows, keepExisting){
55179 this.clearSelections();
55181 for(var i = 0, len = rows.length; i < len; i++){
55182 this.selectRow(rows[i], true);
55187 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55188 * @param {Number} startRow The index of the first row in the range
55189 * @param {Number} endRow The index of the last row in the range
55190 * @param {Boolean} keepExisting (optional) True to retain existing selections
55192 selectRange : function(startRow, endRow, keepExisting){
55193 if(this.locked) return;
55195 this.clearSelections();
55197 if(startRow <= endRow){
55198 for(var i = startRow; i <= endRow; i++){
55199 this.selectRow(i, true);
55202 for(var i = startRow; i >= endRow; i--){
55203 this.selectRow(i, true);
55209 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55210 * @param {Number} startRow The index of the first row in the range
55211 * @param {Number} endRow The index of the last row in the range
55213 deselectRange : function(startRow, endRow, preventViewNotify){
55214 if(this.locked) return;
55215 for(var i = startRow; i <= endRow; i++){
55216 this.deselectRow(i, preventViewNotify);
55222 * @param {Number} row The index of the row to select
55223 * @param {Boolean} keepExisting (optional) True to keep existing selections
55225 selectRow : function(index, keepExisting, preventViewNotify){
55226 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55227 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55228 if(!keepExisting || this.singleSelect){
55229 this.clearSelections();
55231 var r = this.grid.dataSource.getAt(index);
55232 this.selections.add(r);
55233 this.last = this.lastActive = index;
55234 if(!preventViewNotify){
55235 this.grid.getView().onRowSelect(index);
55237 this.fireEvent("rowselect", this, index, r);
55238 this.fireEvent("selectionchange", this);
55244 * @param {Number} row The index of the row to deselect
55246 deselectRow : function(index, preventViewNotify){
55247 if(this.locked) return;
55248 if(this.last == index){
55251 if(this.lastActive == index){
55252 this.lastActive = false;
55254 var r = this.grid.dataSource.getAt(index);
55255 this.selections.remove(r);
55256 if(!preventViewNotify){
55257 this.grid.getView().onRowDeselect(index);
55259 this.fireEvent("rowdeselect", this, index);
55260 this.fireEvent("selectionchange", this);
55264 restoreLast : function(){
55266 this.last = this._last;
55271 acceptsNav : function(row, col, cm){
55272 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55276 onEditorKey : function(field, e){
55277 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55282 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55284 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55286 }else if(k == e.ENTER && !e.ctrlKey){
55290 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55292 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55294 }else if(k == e.ESC){
55298 g.startEditing(newCell[0], newCell[1]);
55303 * Ext JS Library 1.1.1
55304 * Copyright(c) 2006-2007, Ext JS, LLC.
55306 * Originally Released Under LGPL - original licence link has changed is not relivant.
55309 * <script type="text/javascript">
55312 * @class Roo.grid.CellSelectionModel
55313 * @extends Roo.grid.AbstractSelectionModel
55314 * This class provides the basic implementation for cell selection in a grid.
55316 * @param {Object} config The object containing the configuration of this model.
55317 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55319 Roo.grid.CellSelectionModel = function(config){
55320 Roo.apply(this, config);
55322 this.selection = null;
55326 * @event beforerowselect
55327 * Fires before a cell is selected.
55328 * @param {SelectionModel} this
55329 * @param {Number} rowIndex The selected row index
55330 * @param {Number} colIndex The selected cell index
55332 "beforecellselect" : true,
55334 * @event cellselect
55335 * Fires when a cell is selected.
55336 * @param {SelectionModel} this
55337 * @param {Number} rowIndex The selected row index
55338 * @param {Number} colIndex The selected cell index
55340 "cellselect" : true,
55342 * @event selectionchange
55343 * Fires when the active selection changes.
55344 * @param {SelectionModel} this
55345 * @param {Object} selection null for no selection or an object (o) with two properties
55347 <li>o.record: the record object for the row the selection is in</li>
55348 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55351 "selectionchange" : true,
55354 * Fires when the tab (or enter) was pressed on the last editable cell
55355 * You can use this to trigger add new row.
55356 * @param {SelectionModel} this
55360 * @event beforeeditnext
55361 * Fires before the next editable sell is made active
55362 * You can use this to skip to another cell or fire the tabend
55363 * if you set cell to false
55364 * @param {Object} eventdata object : { cell : [ row, col ] }
55366 "beforeeditnext" : true
55368 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55371 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55373 enter_is_tab: false,
55376 initEvents : function(){
55377 this.grid.on("mousedown", this.handleMouseDown, this);
55378 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55379 var view = this.grid.view;
55380 view.on("refresh", this.onViewChange, this);
55381 view.on("rowupdated", this.onRowUpdated, this);
55382 view.on("beforerowremoved", this.clearSelections, this);
55383 view.on("beforerowsinserted", this.clearSelections, this);
55384 if(this.grid.isEditor){
55385 this.grid.on("beforeedit", this.beforeEdit, this);
55390 beforeEdit : function(e){
55391 this.select(e.row, e.column, false, true, e.record);
55395 onRowUpdated : function(v, index, r){
55396 if(this.selection && this.selection.record == r){
55397 v.onCellSelect(index, this.selection.cell[1]);
55402 onViewChange : function(){
55403 this.clearSelections(true);
55407 * Returns the currently selected cell,.
55408 * @return {Array} The selected cell (row, column) or null if none selected.
55410 getSelectedCell : function(){
55411 return this.selection ? this.selection.cell : null;
55415 * Clears all selections.
55416 * @param {Boolean} true to prevent the gridview from being notified about the change.
55418 clearSelections : function(preventNotify){
55419 var s = this.selection;
55421 if(preventNotify !== true){
55422 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55424 this.selection = null;
55425 this.fireEvent("selectionchange", this, null);
55430 * Returns true if there is a selection.
55431 * @return {Boolean}
55433 hasSelection : function(){
55434 return this.selection ? true : false;
55438 handleMouseDown : function(e, t){
55439 var v = this.grid.getView();
55440 if(this.isLocked()){
55443 var row = v.findRowIndex(t);
55444 var cell = v.findCellIndex(t);
55445 if(row !== false && cell !== false){
55446 this.select(row, cell);
55452 * @param {Number} rowIndex
55453 * @param {Number} collIndex
55455 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55456 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55457 this.clearSelections();
55458 r = r || this.grid.dataSource.getAt(rowIndex);
55461 cell : [rowIndex, colIndex]
55463 if(!preventViewNotify){
55464 var v = this.grid.getView();
55465 v.onCellSelect(rowIndex, colIndex);
55466 if(preventFocus !== true){
55467 v.focusCell(rowIndex, colIndex);
55470 this.fireEvent("cellselect", this, rowIndex, colIndex);
55471 this.fireEvent("selectionchange", this, this.selection);
55476 isSelectable : function(rowIndex, colIndex, cm){
55477 return !cm.isHidden(colIndex);
55481 handleKeyDown : function(e){
55482 //Roo.log('Cell Sel Model handleKeyDown');
55483 if(!e.isNavKeyPress()){
55486 var g = this.grid, s = this.selection;
55489 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55491 this.select(cell[0], cell[1]);
55496 var walk = function(row, col, step){
55497 return g.walkCells(row, col, step, sm.isSelectable, sm);
55499 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55506 // handled by onEditorKey
55507 if (g.isEditor && g.editing) {
55511 newCell = walk(r, c-1, -1);
55513 newCell = walk(r, c+1, 1);
55518 newCell = walk(r+1, c, 1);
55522 newCell = walk(r-1, c, -1);
55526 newCell = walk(r, c+1, 1);
55530 newCell = walk(r, c-1, -1);
55535 if(g.isEditor && !g.editing){
55536 g.startEditing(r, c);
55545 this.select(newCell[0], newCell[1]);
55551 acceptsNav : function(row, col, cm){
55552 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55556 * @param {Number} field (not used) - as it's normally used as a listener
55557 * @param {Number} e - event - fake it by using
55559 * var e = Roo.EventObjectImpl.prototype;
55560 * e.keyCode = e.TAB
55564 onEditorKey : function(field, e){
55566 var k = e.getKey(),
55569 ed = g.activeEditor,
55571 ///Roo.log('onEditorKey' + k);
55574 if (this.enter_is_tab && k == e.ENTER) {
55580 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55582 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55588 } else if(k == e.ENTER && !e.ctrlKey){
55591 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55593 } else if(k == e.ESC){
55598 var ecall = { cell : newCell, forward : forward };
55599 this.fireEvent('beforeeditnext', ecall );
55600 newCell = ecall.cell;
55601 forward = ecall.forward;
55605 //Roo.log('next cell after edit');
55606 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55607 } else if (forward) {
55608 // tabbed past last
55609 this.fireEvent.defer(100, this, ['tabend',this]);
55614 * Ext JS Library 1.1.1
55615 * Copyright(c) 2006-2007, Ext JS, LLC.
55617 * Originally Released Under LGPL - original licence link has changed is not relivant.
55620 * <script type="text/javascript">
55624 * @class Roo.grid.EditorGrid
55625 * @extends Roo.grid.Grid
55626 * Class for creating and editable grid.
55627 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55628 * The container MUST have some type of size defined for the grid to fill. The container will be
55629 * automatically set to position relative if it isn't already.
55630 * @param {Object} dataSource The data model to bind to
55631 * @param {Object} colModel The column model with info about this grid's columns
55633 Roo.grid.EditorGrid = function(container, config){
55634 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55635 this.getGridEl().addClass("xedit-grid");
55637 if(!this.selModel){
55638 this.selModel = new Roo.grid.CellSelectionModel();
55641 this.activeEditor = null;
55645 * @event beforeedit
55646 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55647 * <ul style="padding:5px;padding-left:16px;">
55648 * <li>grid - This grid</li>
55649 * <li>record - The record being edited</li>
55650 * <li>field - The field name being edited</li>
55651 * <li>value - The value for the field being edited.</li>
55652 * <li>row - The grid row index</li>
55653 * <li>column - The grid column index</li>
55654 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55656 * @param {Object} e An edit event (see above for description)
55658 "beforeedit" : true,
55661 * Fires after a cell is edited. <br />
55662 * <ul style="padding:5px;padding-left:16px;">
55663 * <li>grid - This grid</li>
55664 * <li>record - The record being edited</li>
55665 * <li>field - The field name being edited</li>
55666 * <li>value - The value being set</li>
55667 * <li>originalValue - The original value for the field, before the edit.</li>
55668 * <li>row - The grid row index</li>
55669 * <li>column - The grid column index</li>
55671 * @param {Object} e An edit event (see above for description)
55673 "afteredit" : true,
55675 * @event validateedit
55676 * Fires after a cell is edited, but before the value is set in the record.
55677 * You can use this to modify the value being set in the field, Return false
55678 * to cancel the change. The edit event object has the following properties <br />
55679 * <ul style="padding:5px;padding-left:16px;">
55680 * <li>editor - This editor</li>
55681 * <li>grid - This grid</li>
55682 * <li>record - The record being edited</li>
55683 * <li>field - The field name being edited</li>
55684 * <li>value - The value being set</li>
55685 * <li>originalValue - The original value for the field, before the edit.</li>
55686 * <li>row - The grid row index</li>
55687 * <li>column - The grid column index</li>
55688 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55690 * @param {Object} e An edit event (see above for description)
55692 "validateedit" : true
55694 this.on("bodyscroll", this.stopEditing, this);
55695 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55698 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55700 * @cfg {Number} clicksToEdit
55701 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55708 trackMouseOver: false, // causes very odd FF errors
55710 onCellDblClick : function(g, row, col){
55711 this.startEditing(row, col);
55714 onEditComplete : function(ed, value, startValue){
55715 this.editing = false;
55716 this.activeEditor = null;
55717 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55719 var field = this.colModel.getDataIndex(ed.col);
55724 originalValue: startValue,
55731 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
55734 if(String(value) !== String(startValue)){
55736 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
55737 r.set(field, e.value);
55738 // if we are dealing with a combo box..
55739 // then we also set the 'name' colum to be the displayField
55740 if (ed.field.displayField && ed.field.name) {
55741 r.set(ed.field.name, ed.field.el.dom.value);
55744 delete e.cancel; //?? why!!!
55745 this.fireEvent("afteredit", e);
55748 this.fireEvent("afteredit", e); // always fire it!
55750 this.view.focusCell(ed.row, ed.col);
55754 * Starts editing the specified for the specified row/column
55755 * @param {Number} rowIndex
55756 * @param {Number} colIndex
55758 startEditing : function(row, col){
55759 this.stopEditing();
55760 if(this.colModel.isCellEditable(col, row)){
55761 this.view.ensureVisible(row, col, true);
55763 var r = this.dataSource.getAt(row);
55764 var field = this.colModel.getDataIndex(col);
55765 var cell = Roo.get(this.view.getCell(row,col));
55770 value: r.data[field],
55775 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
55776 this.editing = true;
55777 var ed = this.colModel.getCellEditor(col, row);
55783 ed.render(ed.parentEl || document.body);
55789 (function(){ // complex but required for focus issues in safari, ie and opera
55793 ed.on("complete", this.onEditComplete, this, {single: true});
55794 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
55795 this.activeEditor = ed;
55796 var v = r.data[field];
55797 ed.startEdit(this.view.getCell(row, col), v);
55798 // combo's with 'displayField and name set
55799 if (ed.field.displayField && ed.field.name) {
55800 ed.field.el.dom.value = r.data[ed.field.name];
55804 }).defer(50, this);
55810 * Stops any active editing
55812 stopEditing : function(){
55813 if(this.activeEditor){
55814 this.activeEditor.completeEdit();
55816 this.activeEditor = null;
55820 * Called to get grid's drag proxy text, by default returns this.ddText.
55823 getDragDropText : function(){
55824 var count = this.selModel.getSelectedCell() ? 1 : 0;
55825 return String.format(this.ddText, count, count == 1 ? '' : 's');
55830 * Ext JS Library 1.1.1
55831 * Copyright(c) 2006-2007, Ext JS, LLC.
55833 * Originally Released Under LGPL - original licence link has changed is not relivant.
55836 * <script type="text/javascript">
55839 // private - not really -- you end up using it !
55840 // This is a support class used internally by the Grid components
55843 * @class Roo.grid.GridEditor
55844 * @extends Roo.Editor
55845 * Class for creating and editable grid elements.
55846 * @param {Object} config any settings (must include field)
55848 Roo.grid.GridEditor = function(field, config){
55849 if (!config && field.field) {
55851 field = Roo.factory(config.field, Roo.form);
55853 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
55854 field.monitorTab = false;
55857 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
55860 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
55863 alignment: "tl-tl",
55866 cls: "x-small-editor x-grid-editor",
55871 * Ext JS Library 1.1.1
55872 * Copyright(c) 2006-2007, Ext JS, LLC.
55874 * Originally Released Under LGPL - original licence link has changed is not relivant.
55877 * <script type="text/javascript">
55882 Roo.grid.PropertyRecord = Roo.data.Record.create([
55883 {name:'name',type:'string'}, 'value'
55887 Roo.grid.PropertyStore = function(grid, source){
55889 this.store = new Roo.data.Store({
55890 recordType : Roo.grid.PropertyRecord
55892 this.store.on('update', this.onUpdate, this);
55894 this.setSource(source);
55896 Roo.grid.PropertyStore.superclass.constructor.call(this);
55901 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
55902 setSource : function(o){
55904 this.store.removeAll();
55907 if(this.isEditableValue(o[k])){
55908 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
55911 this.store.loadRecords({records: data}, {}, true);
55914 onUpdate : function(ds, record, type){
55915 if(type == Roo.data.Record.EDIT){
55916 var v = record.data['value'];
55917 var oldValue = record.modified['value'];
55918 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
55919 this.source[record.id] = v;
55921 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
55928 getProperty : function(row){
55929 return this.store.getAt(row);
55932 isEditableValue: function(val){
55933 if(val && val instanceof Date){
55935 }else if(typeof val == 'object' || typeof val == 'function'){
55941 setValue : function(prop, value){
55942 this.source[prop] = value;
55943 this.store.getById(prop).set('value', value);
55946 getSource : function(){
55947 return this.source;
55951 Roo.grid.PropertyColumnModel = function(grid, store){
55954 g.PropertyColumnModel.superclass.constructor.call(this, [
55955 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
55956 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
55958 this.store = store;
55959 this.bselect = Roo.DomHelper.append(document.body, {
55960 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
55961 {tag: 'option', value: 'true', html: 'true'},
55962 {tag: 'option', value: 'false', html: 'false'}
55965 Roo.id(this.bselect);
55968 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
55969 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
55970 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
55971 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
55972 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
55974 this.renderCellDelegate = this.renderCell.createDelegate(this);
55975 this.renderPropDelegate = this.renderProp.createDelegate(this);
55978 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
55982 valueText : 'Value',
55984 dateFormat : 'm/j/Y',
55987 renderDate : function(dateVal){
55988 return dateVal.dateFormat(this.dateFormat);
55991 renderBool : function(bVal){
55992 return bVal ? 'true' : 'false';
55995 isCellEditable : function(colIndex, rowIndex){
55996 return colIndex == 1;
55999 getRenderer : function(col){
56001 this.renderCellDelegate : this.renderPropDelegate;
56004 renderProp : function(v){
56005 return this.getPropertyName(v);
56008 renderCell : function(val){
56010 if(val instanceof Date){
56011 rv = this.renderDate(val);
56012 }else if(typeof val == 'boolean'){
56013 rv = this.renderBool(val);
56015 return Roo.util.Format.htmlEncode(rv);
56018 getPropertyName : function(name){
56019 var pn = this.grid.propertyNames;
56020 return pn && pn[name] ? pn[name] : name;
56023 getCellEditor : function(colIndex, rowIndex){
56024 var p = this.store.getProperty(rowIndex);
56025 var n = p.data['name'], val = p.data['value'];
56027 if(typeof(this.grid.customEditors[n]) == 'string'){
56028 return this.editors[this.grid.customEditors[n]];
56030 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56031 return this.grid.customEditors[n];
56033 if(val instanceof Date){
56034 return this.editors['date'];
56035 }else if(typeof val == 'number'){
56036 return this.editors['number'];
56037 }else if(typeof val == 'boolean'){
56038 return this.editors['boolean'];
56040 return this.editors['string'];
56046 * @class Roo.grid.PropertyGrid
56047 * @extends Roo.grid.EditorGrid
56048 * This class represents the interface of a component based property grid control.
56049 * <br><br>Usage:<pre><code>
56050 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56058 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56059 * The container MUST have some type of size defined for the grid to fill. The container will be
56060 * automatically set to position relative if it isn't already.
56061 * @param {Object} config A config object that sets properties on this grid.
56063 Roo.grid.PropertyGrid = function(container, config){
56064 config = config || {};
56065 var store = new Roo.grid.PropertyStore(this);
56066 this.store = store;
56067 var cm = new Roo.grid.PropertyColumnModel(this, store);
56068 store.store.sort('name', 'ASC');
56069 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56072 enableColLock:false,
56073 enableColumnMove:false,
56075 trackMouseOver: false,
56078 this.getGridEl().addClass('x-props-grid');
56079 this.lastEditRow = null;
56080 this.on('columnresize', this.onColumnResize, this);
56083 * @event beforepropertychange
56084 * Fires before a property changes (return false to stop?)
56085 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56086 * @param {String} id Record Id
56087 * @param {String} newval New Value
56088 * @param {String} oldval Old Value
56090 "beforepropertychange": true,
56092 * @event propertychange
56093 * Fires after a property changes
56094 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56095 * @param {String} id Record Id
56096 * @param {String} newval New Value
56097 * @param {String} oldval Old Value
56099 "propertychange": true
56101 this.customEditors = this.customEditors || {};
56103 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56106 * @cfg {Object} customEditors map of colnames=> custom editors.
56107 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56108 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56109 * false disables editing of the field.
56113 * @cfg {Object} propertyNames map of property Names to their displayed value
56116 render : function(){
56117 Roo.grid.PropertyGrid.superclass.render.call(this);
56118 this.autoSize.defer(100, this);
56121 autoSize : function(){
56122 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56124 this.view.fitColumns();
56128 onColumnResize : function(){
56129 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56133 * Sets the data for the Grid
56134 * accepts a Key => Value object of all the elements avaiable.
56135 * @param {Object} data to appear in grid.
56137 setSource : function(source){
56138 this.store.setSource(source);
56142 * Gets all the data from the grid.
56143 * @return {Object} data data stored in grid
56145 getSource : function(){
56146 return this.store.getSource();
56155 * @class Roo.grid.Calendar
56156 * @extends Roo.util.Grid
56157 * This class extends the Grid to provide a calendar widget
56158 * <br><br>Usage:<pre><code>
56159 var grid = new Roo.grid.Calendar("my-container-id", {
56162 selModel: mySelectionModel,
56163 autoSizeColumns: true,
56164 monitorWindowResize: false,
56165 trackMouseOver: true
56166 eventstore : real data store..
56172 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56173 * The container MUST have some type of size defined for the grid to fill. The container will be
56174 * automatically set to position relative if it isn't already.
56175 * @param {Object} config A config object that sets properties on this grid.
56177 Roo.grid.Calendar = function(container, config){
56178 // initialize the container
56179 this.container = Roo.get(container);
56180 this.container.update("");
56181 this.container.setStyle("overflow", "hidden");
56182 this.container.addClass('x-grid-container');
56184 this.id = this.container.id;
56186 Roo.apply(this, config);
56187 // check and correct shorthanded configs
56191 for (var r = 0;r < 6;r++) {
56194 for (var c =0;c < 7;c++) {
56198 if (this.eventStore) {
56199 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56200 this.eventStore.on('load',this.onLoad, this);
56201 this.eventStore.on('beforeload',this.clearEvents, this);
56205 this.dataSource = new Roo.data.Store({
56206 proxy: new Roo.data.MemoryProxy(rows),
56207 reader: new Roo.data.ArrayReader({}, [
56208 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56211 this.dataSource.load();
56212 this.ds = this.dataSource;
56213 this.ds.xmodule = this.xmodule || false;
56216 var cellRender = function(v,x,r)
56218 return String.format(
56219 '<div class="fc-day fc-widget-content"><div>' +
56220 '<div class="fc-event-container"></div>' +
56221 '<div class="fc-day-number">{0}</div>'+
56223 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56224 '</div></div>', v);
56229 this.colModel = new Roo.grid.ColumnModel( [
56231 xtype: 'ColumnModel',
56233 dataIndex : 'weekday0',
56235 renderer : cellRender
56238 xtype: 'ColumnModel',
56240 dataIndex : 'weekday1',
56242 renderer : cellRender
56245 xtype: 'ColumnModel',
56247 dataIndex : 'weekday2',
56248 header : 'Tuesday',
56249 renderer : cellRender
56252 xtype: 'ColumnModel',
56254 dataIndex : 'weekday3',
56255 header : 'Wednesday',
56256 renderer : cellRender
56259 xtype: 'ColumnModel',
56261 dataIndex : 'weekday4',
56262 header : 'Thursday',
56263 renderer : cellRender
56266 xtype: 'ColumnModel',
56268 dataIndex : 'weekday5',
56270 renderer : cellRender
56273 xtype: 'ColumnModel',
56275 dataIndex : 'weekday6',
56276 header : 'Saturday',
56277 renderer : cellRender
56280 this.cm = this.colModel;
56281 this.cm.xmodule = this.xmodule || false;
56285 //this.selModel = new Roo.grid.CellSelectionModel();
56286 //this.sm = this.selModel;
56287 //this.selModel.init(this);
56291 this.container.setWidth(this.width);
56295 this.container.setHeight(this.height);
56302 * The raw click event for the entire grid.
56303 * @param {Roo.EventObject} e
56308 * The raw dblclick event for the entire grid.
56309 * @param {Roo.EventObject} e
56313 * @event contextmenu
56314 * The raw contextmenu event for the entire grid.
56315 * @param {Roo.EventObject} e
56317 "contextmenu" : true,
56320 * The raw mousedown event for the entire grid.
56321 * @param {Roo.EventObject} e
56323 "mousedown" : true,
56326 * The raw mouseup event for the entire grid.
56327 * @param {Roo.EventObject} e
56332 * The raw mouseover event for the entire grid.
56333 * @param {Roo.EventObject} e
56335 "mouseover" : true,
56338 * The raw mouseout event for the entire grid.
56339 * @param {Roo.EventObject} e
56344 * The raw keypress event for the entire grid.
56345 * @param {Roo.EventObject} e
56350 * The raw keydown event for the entire grid.
56351 * @param {Roo.EventObject} e
56359 * Fires when a cell is clicked
56360 * @param {Grid} this
56361 * @param {Number} rowIndex
56362 * @param {Number} columnIndex
56363 * @param {Roo.EventObject} e
56365 "cellclick" : true,
56367 * @event celldblclick
56368 * Fires when a cell is double clicked
56369 * @param {Grid} this
56370 * @param {Number} rowIndex
56371 * @param {Number} columnIndex
56372 * @param {Roo.EventObject} e
56374 "celldblclick" : true,
56377 * Fires when a row is clicked
56378 * @param {Grid} this
56379 * @param {Number} rowIndex
56380 * @param {Roo.EventObject} e
56384 * @event rowdblclick
56385 * Fires when a row is double clicked
56386 * @param {Grid} this
56387 * @param {Number} rowIndex
56388 * @param {Roo.EventObject} e
56390 "rowdblclick" : true,
56392 * @event headerclick
56393 * Fires when a header is clicked
56394 * @param {Grid} this
56395 * @param {Number} columnIndex
56396 * @param {Roo.EventObject} e
56398 "headerclick" : true,
56400 * @event headerdblclick
56401 * Fires when a header cell is double clicked
56402 * @param {Grid} this
56403 * @param {Number} columnIndex
56404 * @param {Roo.EventObject} e
56406 "headerdblclick" : true,
56408 * @event rowcontextmenu
56409 * Fires when a row is right clicked
56410 * @param {Grid} this
56411 * @param {Number} rowIndex
56412 * @param {Roo.EventObject} e
56414 "rowcontextmenu" : true,
56416 * @event cellcontextmenu
56417 * Fires when a cell is right clicked
56418 * @param {Grid} this
56419 * @param {Number} rowIndex
56420 * @param {Number} cellIndex
56421 * @param {Roo.EventObject} e
56423 "cellcontextmenu" : true,
56425 * @event headercontextmenu
56426 * Fires when a header is right clicked
56427 * @param {Grid} this
56428 * @param {Number} columnIndex
56429 * @param {Roo.EventObject} e
56431 "headercontextmenu" : true,
56433 * @event bodyscroll
56434 * Fires when the body element is scrolled
56435 * @param {Number} scrollLeft
56436 * @param {Number} scrollTop
56438 "bodyscroll" : true,
56440 * @event columnresize
56441 * Fires when the user resizes a column
56442 * @param {Number} columnIndex
56443 * @param {Number} newSize
56445 "columnresize" : true,
56447 * @event columnmove
56448 * Fires when the user moves a column
56449 * @param {Number} oldIndex
56450 * @param {Number} newIndex
56452 "columnmove" : true,
56455 * Fires when row(s) start being dragged
56456 * @param {Grid} this
56457 * @param {Roo.GridDD} dd The drag drop object
56458 * @param {event} e The raw browser event
56460 "startdrag" : true,
56463 * Fires when a drag operation is complete
56464 * @param {Grid} this
56465 * @param {Roo.GridDD} dd The drag drop object
56466 * @param {event} e The raw browser event
56471 * Fires when dragged row(s) are dropped on a valid DD target
56472 * @param {Grid} this
56473 * @param {Roo.GridDD} dd The drag drop object
56474 * @param {String} targetId The target drag drop object
56475 * @param {event} e The raw browser event
56480 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56481 * @param {Grid} this
56482 * @param {Roo.GridDD} dd The drag drop object
56483 * @param {String} targetId The target drag drop object
56484 * @param {event} e The raw browser event
56489 * Fires when the dragged row(s) first cross another DD target while being dragged
56490 * @param {Grid} this
56491 * @param {Roo.GridDD} dd The drag drop object
56492 * @param {String} targetId The target drag drop object
56493 * @param {event} e The raw browser event
56495 "dragenter" : true,
56498 * Fires when the dragged row(s) leave another DD target while being dragged
56499 * @param {Grid} this
56500 * @param {Roo.GridDD} dd The drag drop object
56501 * @param {String} targetId The target drag drop object
56502 * @param {event} e The raw browser event
56507 * Fires when a row is rendered, so you can change add a style to it.
56508 * @param {GridView} gridview The grid view
56509 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56515 * Fires when the grid is rendered
56516 * @param {Grid} grid
56521 * Fires when a date is selected
56522 * @param {DatePicker} this
56523 * @param {Date} date The selected date
56527 * @event monthchange
56528 * Fires when the displayed month changes
56529 * @param {DatePicker} this
56530 * @param {Date} date The selected month
56532 'monthchange': true,
56534 * @event evententer
56535 * Fires when mouse over an event
56536 * @param {Calendar} this
56537 * @param {event} Event
56539 'evententer': true,
56541 * @event eventleave
56542 * Fires when the mouse leaves an
56543 * @param {Calendar} this
56546 'eventleave': true,
56548 * @event eventclick
56549 * Fires when the mouse click an
56550 * @param {Calendar} this
56553 'eventclick': true,
56555 * @event eventrender
56556 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56557 * @param {Calendar} this
56558 * @param {data} data to be modified
56560 'eventrender': true
56564 Roo.grid.Grid.superclass.constructor.call(this);
56565 this.on('render', function() {
56566 this.view.el.addClass('x-grid-cal');
56568 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56572 if (!Roo.grid.Calendar.style) {
56573 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56576 '.x-grid-cal .x-grid-col' : {
56577 height: 'auto !important',
56578 'vertical-align': 'top'
56580 '.x-grid-cal .fc-event-hori' : {
56591 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56593 * @cfg {Store} eventStore The store that loads events.
56598 activeDate : false,
56601 monitorWindowResize : false,
56604 resizeColumns : function() {
56605 var col = (this.view.el.getWidth() / 7) - 3;
56606 // loop through cols, and setWidth
56607 for(var i =0 ; i < 7 ; i++){
56608 this.cm.setColumnWidth(i, col);
56611 setDate :function(date) {
56613 Roo.log('setDate?');
56615 this.resizeColumns();
56616 var vd = this.activeDate;
56617 this.activeDate = date;
56618 // if(vd && this.el){
56619 // var t = date.getTime();
56620 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56621 // Roo.log('using add remove');
56623 // this.fireEvent('monthchange', this, date);
56625 // this.cells.removeClass("fc-state-highlight");
56626 // this.cells.each(function(c){
56627 // if(c.dateValue == t){
56628 // c.addClass("fc-state-highlight");
56629 // setTimeout(function(){
56630 // try{c.dom.firstChild.focus();}catch(e){}
56640 var days = date.getDaysInMonth();
56642 var firstOfMonth = date.getFirstDateOfMonth();
56643 var startingPos = firstOfMonth.getDay()-this.startDay;
56645 if(startingPos < this.startDay){
56649 var pm = date.add(Date.MONTH, -1);
56650 var prevStart = pm.getDaysInMonth()-startingPos;
56654 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56656 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
56657 //this.cells.addClassOnOver('fc-state-hover');
56659 var cells = this.cells.elements;
56660 var textEls = this.textNodes;
56662 //Roo.each(cells, function(cell){
56663 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
56666 days += startingPos;
56668 // convert everything to numbers so it's fast
56669 var day = 86400000;
56670 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
56673 //Roo.log(prevStart);
56675 var today = new Date().clearTime().getTime();
56676 var sel = date.clearTime().getTime();
56677 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
56678 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
56679 var ddMatch = this.disabledDatesRE;
56680 var ddText = this.disabledDatesText;
56681 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
56682 var ddaysText = this.disabledDaysText;
56683 var format = this.format;
56685 var setCellClass = function(cal, cell){
56687 //Roo.log('set Cell Class');
56689 var t = d.getTime();
56694 cell.dateValue = t;
56696 cell.className += " fc-today";
56697 cell.className += " fc-state-highlight";
56698 cell.title = cal.todayText;
56701 // disable highlight in other month..
56702 cell.className += " fc-state-highlight";
56707 //cell.className = " fc-state-disabled";
56708 cell.title = cal.minText;
56712 //cell.className = " fc-state-disabled";
56713 cell.title = cal.maxText;
56717 if(ddays.indexOf(d.getDay()) != -1){
56718 // cell.title = ddaysText;
56719 // cell.className = " fc-state-disabled";
56722 if(ddMatch && format){
56723 var fvalue = d.dateFormat(format);
56724 if(ddMatch.test(fvalue)){
56725 cell.title = ddText.replace("%0", fvalue);
56726 cell.className = " fc-state-disabled";
56730 if (!cell.initialClassName) {
56731 cell.initialClassName = cell.dom.className;
56734 cell.dom.className = cell.initialClassName + ' ' + cell.className;
56739 for(; i < startingPos; i++) {
56740 cells[i].dayName = (++prevStart);
56741 Roo.log(textEls[i]);
56742 d.setDate(d.getDate()+1);
56744 //cells[i].className = "fc-past fc-other-month";
56745 setCellClass(this, cells[i]);
56750 for(; i < days; i++){
56751 intDay = i - startingPos + 1;
56752 cells[i].dayName = (intDay);
56753 d.setDate(d.getDate()+1);
56755 cells[i].className = ''; // "x-date-active";
56756 setCellClass(this, cells[i]);
56760 for(; i < 42; i++) {
56761 //textEls[i].innerHTML = (++extraDays);
56763 d.setDate(d.getDate()+1);
56764 cells[i].dayName = (++extraDays);
56765 cells[i].className = "fc-future fc-other-month";
56766 setCellClass(this, cells[i]);
56769 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
56771 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
56773 // this will cause all the cells to mis
56776 for (var r = 0;r < 6;r++) {
56777 for (var c =0;c < 7;c++) {
56778 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
56782 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56783 for(i=0;i<cells.length;i++) {
56785 this.cells.elements[i].dayName = cells[i].dayName ;
56786 this.cells.elements[i].className = cells[i].className;
56787 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
56788 this.cells.elements[i].title = cells[i].title ;
56789 this.cells.elements[i].dateValue = cells[i].dateValue ;
56795 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
56796 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
56798 ////if(totalRows != 6){
56799 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
56800 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
56803 this.fireEvent('monthchange', this, date);
56808 * Returns the grid's SelectionModel.
56809 * @return {SelectionModel}
56811 getSelectionModel : function(){
56812 if(!this.selModel){
56813 this.selModel = new Roo.grid.CellSelectionModel();
56815 return this.selModel;
56819 this.eventStore.load()
56825 findCell : function(dt) {
56826 dt = dt.clearTime().getTime();
56828 this.cells.each(function(c){
56829 //Roo.log("check " +c.dateValue + '?=' + dt);
56830 if(c.dateValue == dt){
56840 findCells : function(rec) {
56841 var s = rec.data.start_dt.clone().clearTime().getTime();
56843 var e= rec.data.end_dt.clone().clearTime().getTime();
56846 this.cells.each(function(c){
56847 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
56849 if(c.dateValue > e){
56852 if(c.dateValue < s){
56861 findBestRow: function(cells)
56865 for (var i =0 ; i < cells.length;i++) {
56866 ret = Math.max(cells[i].rows || 0,ret);
56873 addItem : function(rec)
56875 // look for vertical location slot in
56876 var cells = this.findCells(rec);
56878 rec.row = this.findBestRow(cells);
56880 // work out the location.
56884 for(var i =0; i < cells.length; i++) {
56892 if (crow.start.getY() == cells[i].getY()) {
56894 crow.end = cells[i];
56910 for (var i = 0; i < cells.length;i++) {
56911 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
56918 clearEvents: function() {
56920 if (!this.eventStore.getCount()) {
56923 // reset number of rows in cells.
56924 Roo.each(this.cells.elements, function(c){
56928 this.eventStore.each(function(e) {
56929 this.clearEvent(e);
56934 clearEvent : function(ev)
56937 Roo.each(ev.els, function(el) {
56938 el.un('mouseenter' ,this.onEventEnter, this);
56939 el.un('mouseleave' ,this.onEventLeave, this);
56947 renderEvent : function(ev,ctr) {
56949 ctr = this.view.el.select('.fc-event-container',true).first();
56953 this.clearEvent(ev);
56959 var cells = ev.cells;
56960 var rows = ev.rows;
56961 this.fireEvent('eventrender', this, ev);
56963 for(var i =0; i < rows.length; i++) {
56967 cls += ' fc-event-start';
56969 if ((i+1) == rows.length) {
56970 cls += ' fc-event-end';
56973 //Roo.log(ev.data);
56974 // how many rows should it span..
56975 var cg = this.eventTmpl.append(ctr,Roo.apply({
56978 }, ev.data) , true);
56981 cg.on('mouseenter' ,this.onEventEnter, this, ev);
56982 cg.on('mouseleave' ,this.onEventLeave, this, ev);
56983 cg.on('click', this.onEventClick, this, ev);
56987 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
56988 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
56991 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
56992 cg.setWidth(ebox.right - sbox.x -2);
56996 renderEvents: function()
56998 // first make sure there is enough space..
57000 if (!this.eventTmpl) {
57001 this.eventTmpl = new Roo.Template(
57002 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57003 '<div class="fc-event-inner">' +
57004 '<span class="fc-event-time">{time}</span>' +
57005 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57007 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57015 this.cells.each(function(c) {
57016 //Roo.log(c.select('.fc-day-content div',true).first());
57017 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57020 var ctr = this.view.el.select('.fc-event-container',true).first();
57023 this.eventStore.each(function(ev){
57025 this.renderEvent(ev);
57029 this.view.layout();
57033 onEventEnter: function (e, el,event,d) {
57034 this.fireEvent('evententer', this, el, event);
57037 onEventLeave: function (e, el,event,d) {
57038 this.fireEvent('eventleave', this, el, event);
57041 onEventClick: function (e, el,event,d) {
57042 this.fireEvent('eventclick', this, el, event);
57045 onMonthChange: function () {
57049 onLoad: function () {
57051 //Roo.log('calendar onload');
57053 if(this.eventStore.getCount() > 0){
57057 this.eventStore.each(function(d){
57062 if (typeof(add.end_dt) == 'undefined') {
57063 Roo.log("Missing End time in calendar data: ");
57067 if (typeof(add.start_dt) == 'undefined') {
57068 Roo.log("Missing Start time in calendar data: ");
57072 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57073 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57074 add.id = add.id || d.id;
57075 add.title = add.title || '??';
57083 this.renderEvents();
57093 render : function ()
57097 if (!this.view.el.hasClass('course-timesheet')) {
57098 this.view.el.addClass('course-timesheet');
57100 if (this.tsStyle) {
57105 Roo.log(_this.grid.view.el.getWidth());
57108 this.tsStyle = Roo.util.CSS.createStyleSheet({
57109 '.course-timesheet .x-grid-row' : {
57112 '.x-grid-row td' : {
57113 'vertical-align' : 0
57115 '.course-edit-link' : {
57117 'text-overflow' : 'ellipsis',
57118 'overflow' : 'hidden',
57119 'white-space' : 'nowrap',
57120 'cursor' : 'pointer'
57125 '.de-act-sup-link' : {
57126 'color' : 'purple',
57127 'text-decoration' : 'line-through'
57131 'text-decoration' : 'line-through'
57133 '.course-timesheet .course-highlight' : {
57134 'border-top-style': 'dashed !important',
57135 'border-bottom-bottom': 'dashed !important'
57137 '.course-timesheet .course-item' : {
57138 'font-family' : 'tahoma, arial, helvetica',
57139 'font-size' : '11px',
57140 'overflow' : 'hidden',
57141 'padding-left' : '10px',
57142 'padding-right' : '10px',
57143 'padding-top' : '10px'
57151 monitorWindowResize : false,
57152 cellrenderer : function(v,x,r)
57157 xtype: 'CellSelectionModel',
57164 beforeload : function (_self, options)
57166 options.params = options.params || {};
57167 options.params._month = _this.monthField.getValue();
57168 options.params.limit = 9999;
57169 options.params['sort'] = 'when_dt';
57170 options.params['dir'] = 'ASC';
57171 this.proxy.loadResponse = this.loadResponse;
57173 //this.addColumns();
57175 load : function (_self, records, options)
57177 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57178 // if you click on the translation.. you can edit it...
57179 var el = Roo.get(this);
57180 var id = el.dom.getAttribute('data-id');
57181 var d = el.dom.getAttribute('data-date');
57182 var t = el.dom.getAttribute('data-time');
57183 //var id = this.child('span').dom.textContent;
57186 Pman.Dialog.CourseCalendar.show({
57190 productitem_active : id ? 1 : 0
57192 _this.grid.ds.load({});
57197 _this.panel.fireEvent('resize', [ '', '' ]);
57200 loadResponse : function(o, success, response){
57201 // this is overridden on before load..
57203 Roo.log("our code?");
57204 //Roo.log(success);
57205 //Roo.log(response)
57206 delete this.activeRequest;
57208 this.fireEvent("loadexception", this, o, response);
57209 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57214 result = o.reader.read(response);
57216 Roo.log("load exception?");
57217 this.fireEvent("loadexception", this, o, response, e);
57218 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57221 Roo.log("ready...");
57222 // loop through result.records;
57223 // and set this.tdate[date] = [] << array of records..
57225 Roo.each(result.records, function(r){
57227 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57228 _this.tdata[r.data.when_dt.format('j')] = [];
57230 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57233 //Roo.log(_this.tdata);
57235 result.records = [];
57236 result.totalRecords = 6;
57238 // let's generate some duumy records for the rows.
57239 //var st = _this.dateField.getValue();
57241 // work out monday..
57242 //st = st.add(Date.DAY, -1 * st.format('w'));
57244 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57246 var firstOfMonth = date.getFirstDayOfMonth();
57247 var days = date.getDaysInMonth();
57249 var firstAdded = false;
57250 for (var i = 0; i < result.totalRecords ; i++) {
57251 //var d= st.add(Date.DAY, i);
57254 for(var w = 0 ; w < 7 ; w++){
57255 if(!firstAdded && firstOfMonth != w){
57262 var dd = (d > 0 && d < 10) ? "0"+d : d;
57263 row['weekday'+w] = String.format(
57264 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57265 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57267 date.format('Y-m-')+dd
57270 if(typeof(_this.tdata[d]) != 'undefined'){
57271 Roo.each(_this.tdata[d], function(r){
57275 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57276 if(r.parent_id*1>0){
57277 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57280 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57281 deactive = 'de-act-link';
57284 row['weekday'+w] += String.format(
57285 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57287 r.product_id_name, //1
57288 r.when_dt.format('h:ia'), //2
57298 // only do this if something added..
57300 result.records.push(_this.grid.dataSource.reader.newRow(row));
57304 // push it twice. (second one with an hour..
57308 this.fireEvent("load", this, o, o.request.arg);
57309 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57311 sortInfo : {field: 'when_dt', direction : 'ASC' },
57313 xtype: 'HttpProxy',
57316 url : baseURL + '/Roo/Shop_course.php'
57319 xtype: 'JsonReader',
57336 'name': 'parent_id',
57340 'name': 'product_id',
57344 'name': 'productitem_id',
57362 click : function (_self, e)
57364 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57365 sd.setMonth(sd.getMonth()-1);
57366 _this.monthField.setValue(sd.format('Y-m-d'));
57367 _this.grid.ds.load({});
57373 xtype: 'Separator',
57377 xtype: 'MonthField',
57380 render : function (_self)
57382 _this.monthField = _self;
57383 // _this.monthField.set today
57385 select : function (combo, date)
57387 _this.grid.ds.load({});
57390 value : (function() { return new Date(); })()
57393 xtype: 'Separator',
57399 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57409 click : function (_self, e)
57411 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57412 sd.setMonth(sd.getMonth()+1);
57413 _this.monthField.setValue(sd.format('Y-m-d'));
57414 _this.grid.ds.load({});
57427 * Ext JS Library 1.1.1
57428 * Copyright(c) 2006-2007, Ext JS, LLC.
57430 * Originally Released Under LGPL - original licence link has changed is not relivant.
57433 * <script type="text/javascript">
57437 * @class Roo.LoadMask
57438 * A simple utility class for generically masking elements while loading data. If the element being masked has
57439 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57440 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57441 * element's UpdateManager load indicator and will be destroyed after the initial load.
57443 * Create a new LoadMask
57444 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57445 * @param {Object} config The config object
57447 Roo.LoadMask = function(el, config){
57448 this.el = Roo.get(el);
57449 Roo.apply(this, config);
57451 this.store.on('beforeload', this.onBeforeLoad, this);
57452 this.store.on('load', this.onLoad, this);
57453 this.store.on('loadexception', this.onLoadException, this);
57454 this.removeMask = false;
57456 var um = this.el.getUpdateManager();
57457 um.showLoadIndicator = false; // disable the default indicator
57458 um.on('beforeupdate', this.onBeforeLoad, this);
57459 um.on('update', this.onLoad, this);
57460 um.on('failure', this.onLoad, this);
57461 this.removeMask = true;
57465 Roo.LoadMask.prototype = {
57467 * @cfg {Boolean} removeMask
57468 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57469 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57472 * @cfg {String} msg
57473 * The text to display in a centered loading message box (defaults to 'Loading...')
57475 msg : 'Loading...',
57477 * @cfg {String} msgCls
57478 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57480 msgCls : 'x-mask-loading',
57483 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57489 * Disables the mask to prevent it from being displayed
57491 disable : function(){
57492 this.disabled = true;
57496 * Enables the mask so that it can be displayed
57498 enable : function(){
57499 this.disabled = false;
57502 onLoadException : function()
57504 Roo.log(arguments);
57506 if (typeof(arguments[3]) != 'undefined') {
57507 Roo.MessageBox.alert("Error loading",arguments[3]);
57511 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57512 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57521 this.el.unmask(this.removeMask);
57524 onLoad : function()
57526 this.el.unmask(this.removeMask);
57530 onBeforeLoad : function(){
57531 if(!this.disabled){
57532 this.el.mask(this.msg, this.msgCls);
57537 destroy : function(){
57539 this.store.un('beforeload', this.onBeforeLoad, this);
57540 this.store.un('load', this.onLoad, this);
57541 this.store.un('loadexception', this.onLoadException, this);
57543 var um = this.el.getUpdateManager();
57544 um.un('beforeupdate', this.onBeforeLoad, this);
57545 um.un('update', this.onLoad, this);
57546 um.un('failure', this.onLoad, this);
57551 * Ext JS Library 1.1.1
57552 * Copyright(c) 2006-2007, Ext JS, LLC.
57554 * Originally Released Under LGPL - original licence link has changed is not relivant.
57557 * <script type="text/javascript">
57562 * @class Roo.XTemplate
57563 * @extends Roo.Template
57564 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57566 var t = new Roo.XTemplate(
57567 '<select name="{name}">',
57568 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57572 // then append, applying the master template values
57575 * Supported features:
57580 {a_variable} - output encoded.
57581 {a_variable.format:("Y-m-d")} - call a method on the variable
57582 {a_variable:raw} - unencoded output
57583 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57584 {a_variable:this.method_on_template(...)} - call a method on the template object.
57589 <tpl for="a_variable or condition.."></tpl>
57590 <tpl if="a_variable or condition"></tpl>
57591 <tpl exec="some javascript"></tpl>
57592 <tpl name="named_template"></tpl> (experimental)
57594 <tpl for="."></tpl> - just iterate the property..
57595 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57599 Roo.XTemplate = function()
57601 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57608 Roo.extend(Roo.XTemplate, Roo.Template, {
57611 * The various sub templates
57616 * basic tag replacing syntax
57619 * // you can fake an object call by doing this
57623 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57626 * compile the template
57628 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57631 compile: function()
57635 s = ['<tpl>', s, '</tpl>'].join('');
57637 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57638 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57639 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57640 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57641 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57646 while(true == !!(m = s.match(re))){
57647 var forMatch = m[0].match(nameRe),
57648 ifMatch = m[0].match(ifRe),
57649 execMatch = m[0].match(execRe),
57650 namedMatch = m[0].match(namedRe),
57655 name = forMatch && forMatch[1] ? forMatch[1] : '';
57658 // if - puts fn into test..
57659 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
57661 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
57666 // exec - calls a function... returns empty if true is returned.
57667 exp = execMatch && execMatch[1] ? execMatch[1] : null;
57669 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
57677 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
57678 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
57679 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
57682 var uid = namedMatch ? namedMatch[1] : id;
57686 id: namedMatch ? namedMatch[1] : id,
57693 s = s.replace(m[0], '');
57695 s = s.replace(m[0], '{xtpl'+ id + '}');
57700 for(var i = tpls.length-1; i >= 0; --i){
57701 this.compileTpl(tpls[i]);
57702 this.tpls[tpls[i].id] = tpls[i];
57704 this.master = tpls[tpls.length-1];
57708 * same as applyTemplate, except it's done to one of the subTemplates
57709 * when using named templates, you can do:
57711 * var str = pl.applySubTemplate('your-name', values);
57714 * @param {Number} id of the template
57715 * @param {Object} values to apply to template
57716 * @param {Object} parent (normaly the instance of this object)
57718 applySubTemplate : function(id, values, parent)
57722 var t = this.tpls[id];
57726 if(t.test && !t.test.call(this, values, parent)){
57730 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
57731 Roo.log(e.toString());
57737 if(t.exec && t.exec.call(this, values, parent)){
57741 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
57742 Roo.log(e.toString());
57747 var vs = t.target ? t.target.call(this, values, parent) : values;
57748 parent = t.target ? values : parent;
57749 if(t.target && vs instanceof Array){
57751 for(var i = 0, len = vs.length; i < len; i++){
57752 buf[buf.length] = t.compiled.call(this, vs[i], parent);
57754 return buf.join('');
57756 return t.compiled.call(this, vs, parent);
57758 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
57759 Roo.log(e.toString());
57760 Roo.log(t.compiled);
57765 compileTpl : function(tpl)
57767 var fm = Roo.util.Format;
57768 var useF = this.disableFormats !== true;
57769 var sep = Roo.isGecko ? "+" : ",";
57770 var undef = function(str) {
57771 Roo.log("Property not found :" + str);
57775 var fn = function(m, name, format, args)
57777 //Roo.log(arguments);
57778 args = args ? args.replace(/\\'/g,"'") : args;
57779 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
57780 if (typeof(format) == 'undefined') {
57781 format= 'htmlEncode';
57783 if (format == 'raw' ) {
57787 if(name.substr(0, 4) == 'xtpl'){
57788 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
57791 // build an array of options to determine if value is undefined..
57793 // basically get 'xxxx.yyyy' then do
57794 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
57795 // (function () { Roo.log("Property not found"); return ''; })() :
57800 Roo.each(name.split('.'), function(st) {
57801 lookfor += (lookfor.length ? '.': '') + st;
57802 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
57805 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
57808 if(format && useF){
57810 args = args ? ',' + args : "";
57812 if(format.substr(0, 5) != "this."){
57813 format = "fm." + format + '(';
57815 format = 'this.call("'+ format.substr(5) + '", ';
57819 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
57823 // called with xxyx.yuu:(test,test)
57825 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
57827 // raw.. - :raw modifier..
57828 return "'"+ sep + udef_st + name + ")"+sep+"'";
57832 // branched to use + in gecko and [].join() in others
57834 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
57835 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
57838 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
57839 body.push(tpl.body.replace(/(\r\n|\n)/g,
57840 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
57841 body.push("'].join('');};};");
57842 body = body.join('');
57845 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
57847 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
57853 applyTemplate : function(values){
57854 return this.master.compiled.call(this, values, {});
57855 //var s = this.subs;
57858 apply : function(){
57859 return this.applyTemplate.apply(this, arguments);
57864 Roo.XTemplate.from = function(el){
57865 el = Roo.getDom(el);
57866 return new Roo.XTemplate(el.value || el.innerHTML);