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;
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(){},
124 * Deep object/array copy. Function clones are actually wrappers around the
125 * original function. Array-like objects are treated as arrays. Primitives are
126 * returned untouched. Optionally, a function can be provided to handle other data
127 * types, filter keys, validate values, etc.
129 * **Note:** Cloning a non-trivial object is a reasonably heavy operation, due to
130 * the need to recursively iterate down non-primitive properties. Clone should be
131 * used only when a deep clone down to leaf level properties is explicitly
132 * required. This method will also
134 In many cases (for example, when trying to isolate objects used as hashes for
135 configuration properties), a shallow copy, using `Y.merge()` is normally
136 sufficient. If more than one level of isolation is required, `Y.merge()` can be
137 used selectively at each level which needs to be isolated from the original
138 without going all the way to leaf properties.
141 @param {object} o what to clone.
142 @param {boolean} safe if true, objects will not have prototype items from the
143 source. If false, they will. In this case, the original is initially
144 protected, but the clone is not completely immune from changes to the source
145 object prototype. Also, cloned prototype items that are deleted from the
146 clone will result in the value of the source prototype being exposed. If
147 operating on a non-safe clone, items should be nulled out rather than
149 @param {function} f optional function to apply to each item in a collection; it
150 will be executed prior to applying the value to the new object.
151 Return false to prevent the copy.
152 @param {object} c optional execution context for f.
153 @param {object} owner Owner object passed when clone is iterating an object.
154 Used to set up context for cloned functions.
155 @param {object} cloned hash of previously cloned objects to avoid multiple
157 @return {Array|Object} the cloned object.
159 clone : function(o, safe, f, c, owner, cloned) {
160 var o2, marked, stamp;
162 // Does not attempt to clone:
164 // * Non-typeof-object values, "primitive" values don't need cloning.
166 // * YUI instances, cloning complex object like YUI instances is not
167 // advised, this is like cloning the world.
169 // * DOM nodes (#2528250), common host objects like DOM nodes cannot be
170 // "subclassed" in Firefox and old versions of IE. Trying to use
171 // `Object.create()` or `Y.extend()` on a DOM node will throw an error in
174 // Instad, the passed-in `o` will be return as-is when it matches one of the
176 // if (!L.isObject(o) ||
177 // Y.instanceOf(o, YUI) ||
178 // (o.addEventListener || o.attachEvent)) {
183 marked = cloned || {};
189 // if we do this we need to set the flags too
190 // return new RegExp(o.source);
193 // o2 = Y.bind(o, owner);
201 // #2528250 only one clone of a given object should be created.
203 return marked[o['_~roo~_']];
208 o2 = (safe) ? {} : Y.Object(o);
210 o['_~roo~_'] = stamp;
214 Roo.each(o, function(v, k) {
215 if ((k || k === 0) && (!f || (f.call(c || this, v, k, this, o) !== false))) {
216 if (k !== '_~roo~_') {
217 if (k == 'prototype') {
218 // skip the prototype
219 // } else if (o[k] === o) {
223 Roo.clone(v, safe, f, c, owner || o, marked);
230 Roo.Object.each(marked, function(v, k) {
245 * Copies all the properties of config to obj if they don't already exist.
246 * @param {Object} obj The receiver of the properties
247 * @param {Object} config The source of the properties
248 * @return {Object} returns obj
250 applyIf : function(o, c){
253 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
260 * Applies event listeners to elements by selectors when the document is ready.
261 * The event name is specified with an @ suffix.
264 // add a listener for click on all anchors in element with id foo
265 '#foo a@click' : function(e, t){
269 // add the same listener to multiple selectors (separated by comma BEFORE the @)
270 '#foo a, #bar span.some-class@mouseover' : function(){
275 * @param {Object} obj The list of behaviors to apply
277 addBehaviors : function(o){
279 Roo.onReady(function(){
284 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
286 var parts = b.split('@');
287 if(parts[1]){ // for Object prototype breakers
290 cache[s] = Roo.select(s);
292 cache[s].on(parts[1], o[b]);
299 * Generates unique ids. If the element already has an id, it is unchanged
300 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
301 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
302 * @return {String} The generated Id.
304 id : function(el, prefix){
305 prefix = prefix || "roo-gen";
307 var id = prefix + (++idSeed);
308 return el ? (el.id ? el.id : (el.id = id)) : id;
313 * Extends one class with another class and optionally overrides members with the passed literal. This class
314 * also adds the function "override()" to the class that can be used to override
315 * members on an instance.
316 * @param {Object} subclass The class inheriting the functionality
317 * @param {Object} superclass The class being extended
318 * @param {Object} overrides (optional) A literal with members
323 var io = function(o){
328 return function(sb, sp, overrides){
329 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
332 sb = function(){sp.apply(this, arguments);};
334 var F = function(){}, sbp, spp = sp.prototype;
336 sbp = sb.prototype = new F();
340 if(spp.constructor == Object.prototype.constructor){
345 sb.override = function(o){
349 Roo.override(sb, overrides);
355 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
357 Roo.override(MyClass, {
358 newMethod1: function(){
361 newMethod2: function(foo){
366 * @param {Object} origclass The class to override
367 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
368 * containing one or more methods.
371 override : function(origclass, overrides){
373 var p = origclass.prototype;
374 for(var method in overrides){
375 p[method] = overrides[method];
380 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
382 Roo.namespace('Company', 'Company.data');
383 Company.Widget = function() { ... }
384 Company.data.CustomStore = function(config) { ... }
386 * @param {String} namespace1
387 * @param {String} namespace2
388 * @param {String} etc
391 namespace : function(){
392 var a=arguments, o=null, i, j, d, rt;
393 for (i=0; i<a.length; ++i) {
397 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
398 for (j=1; j<d.length; ++j) {
399 o[d[j]]=o[d[j]] || {};
405 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
407 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
408 Roo.factory(conf, Roo.data);
410 * @param {String} classname
411 * @param {String} namespace (optional)
415 factory : function(c, ns)
417 // no xtype, no ns or c.xns - or forced off by c.xns
418 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
421 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
422 if (c.constructor == ns[c.xtype]) {// already created...
426 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
427 var ret = new ns[c.xtype](c);
431 c.xns = false; // prevent recursion..
435 * Logs to console if it can.
437 * @param {String|Object} string
442 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
449 * 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.
453 urlEncode : function(o){
459 var ov = o[key], k = Roo.encodeURIComponent(key);
460 var type = typeof ov;
461 if(type == 'undefined'){
463 }else if(type != "function" && type != "object"){
464 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
465 }else if(ov instanceof Array){
467 for(var i = 0, len = ov.length; i < len; i++) {
468 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
479 * Safe version of encodeURIComponent
480 * @param {String} data
484 encodeURIComponent : function (data)
487 return encodeURIComponent(data);
488 } catch(e) {} // should be an uri encode error.
490 if (data == '' || data == null){
493 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
494 function nibble_to_hex(nibble){
495 var chars = '0123456789ABCDEF';
496 return chars.charAt(nibble);
498 data = data.toString();
500 for(var i=0; i<data.length; i++){
501 var c = data.charCodeAt(i);
502 var bs = new Array();
505 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
506 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
507 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
508 bs[3] = 0x80 | (c & 0x3F);
509 }else if (c > 0x800){
511 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
512 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
513 bs[2] = 0x80 | (c & 0x3F);
516 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
517 bs[1] = 0x80 | (c & 0x3F);
522 for(var j=0; j<bs.length; j++){
524 var hex = nibble_to_hex((b & 0xF0) >>> 4)
525 + nibble_to_hex(b &0x0F);
534 * 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]}.
535 * @param {String} string
536 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
537 * @return {Object} A literal with members
539 urlDecode : function(string, overwrite){
540 if(!string || !string.length){
544 var pairs = string.split('&');
545 var pair, name, value;
546 for(var i = 0, len = pairs.length; i < len; i++){
547 pair = pairs[i].split('=');
548 name = decodeURIComponent(pair[0]);
549 value = decodeURIComponent(pair[1]);
550 if(overwrite !== true){
551 if(typeof obj[name] == "undefined"){
553 }else if(typeof obj[name] == "string"){
554 obj[name] = [obj[name]];
555 obj[name].push(value);
557 obj[name].push(value);
567 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
568 * passed array is not really an array, your function is called once with it.
569 * The supplied function is called with (Object item, Number index, Array allItems).
570 * @param {Array/NodeList/Mixed} array
571 * @param {Function} fn
572 * @param {Object} scope
574 each : function(array, fn, scope){
575 if(typeof array.length == "undefined" || typeof array == "string"){
578 for(var i = 0, len = array.length; i < len; i++){
579 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
584 combine : function(){
585 var as = arguments, l = as.length, r = [];
586 for(var i = 0; i < l; i++){
588 if(a instanceof Array){
590 }else if(a.length !== undefined && !a.substr){
591 r = r.concat(Array.prototype.slice.call(a, 0));
600 * Escapes the passed string for use in a regular expression
601 * @param {String} str
604 escapeRe : function(s) {
605 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
609 callback : function(cb, scope, args, delay){
610 if(typeof cb == "function"){
612 cb.defer(delay, scope, args || []);
614 cb.apply(scope, args || []);
620 * Return the dom node for the passed string (id), dom node, or Roo.Element
621 * @param {String/HTMLElement/Roo.Element} el
622 * @return HTMLElement
624 getDom : function(el){
628 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
632 * Shorthand for {@link Roo.ComponentMgr#get}
634 * @return Roo.Component
636 getCmp : function(id){
637 return Roo.ComponentMgr.get(id);
640 num : function(v, defaultValue){
641 if(typeof v != 'number'){
647 destroy : function(){
648 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
652 as.removeAllListeners();
656 if(typeof as.purgeListeners == 'function'){
659 if(typeof as.destroy == 'function'){
666 // inpired by a similar function in mootools library
668 * Returns the type of object that is passed in. If the object passed in is null or undefined it
669 * return false otherwise it returns one of the following values:<ul>
670 * <li><b>string</b>: If the object passed is a string</li>
671 * <li><b>number</b>: If the object passed is a number</li>
672 * <li><b>boolean</b>: If the object passed is a boolean value</li>
673 * <li><b>function</b>: If the object passed is a function reference</li>
674 * <li><b>object</b>: If the object passed is an object</li>
675 * <li><b>array</b>: If the object passed is an array</li>
676 * <li><b>regexp</b>: If the object passed is a regular expression</li>
677 * <li><b>element</b>: If the object passed is a DOM Element</li>
678 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
679 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
680 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
681 * @param {Mixed} object
685 if(o === undefined || o === null){
692 if(t == 'object' && o.nodeName) {
694 case 1: return 'element';
695 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
698 if(t == 'object' || t == 'function') {
699 switch(o.constructor) {
700 case Array: return 'array';
701 case RegExp: return 'regexp';
703 if(typeof o.length == 'number' && typeof o.item == 'function') {
711 * Returns true if the passed value is null, undefined or an empty string (optional).
712 * @param {Mixed} value The value to test
713 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
716 isEmpty : function(v, allowBlank){
717 return v === null || v === undefined || (!allowBlank ? v === '' : false);
731 isBorderBox : isBorderBox,
733 isWindows : isWindows,
740 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
741 * you may want to set this to true.
744 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
749 * Selects a single element as a Roo Element
750 * This is about as close as you can get to jQuery's $('do crazy stuff')
751 * @param {String} selector The selector/xpath query
752 * @param {Node} root (optional) The start of the query (defaults to document).
753 * @return {Roo.Element}
755 selectNode : function(selector, root)
757 var node = Roo.DomQuery.selectNode(selector,root);
758 return node ? Roo.get(node) : new Roo.Element(false);
766 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
767 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
770 * Ext JS Library 1.1.1
771 * Copyright(c) 2006-2007, Ext JS, LLC.
773 * Originally Released Under LGPL - original licence link has changed is not relivant.
776 * <script type="text/javascript">
780 // wrappedn so fnCleanup is not in global scope...
782 function fnCleanUp() {
783 var p = Function.prototype;
784 delete p.createSequence;
786 delete p.createDelegate;
787 delete p.createCallback;
788 delete p.createInterceptor;
790 window.detachEvent("onunload", fnCleanUp);
792 window.attachEvent("onunload", fnCleanUp);
799 * These functions are available on every Function object (any JavaScript function).
801 Roo.apply(Function.prototype, {
803 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
804 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
805 * Will create a function that is bound to those 2 args.
806 * @return {Function} The new function
808 createCallback : function(/*args...*/){
809 // make args available, in function below
810 var args = arguments;
813 return method.apply(window, args);
818 * Creates a delegate (callback) that sets the scope to obj.
819 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
820 * Will create a function that is automatically scoped to this.
821 * @param {Object} obj (optional) The object for which the scope is set
822 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
823 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
824 * if a number the args are inserted at the specified position
825 * @return {Function} The new function
827 createDelegate : function(obj, args, appendArgs){
830 var callArgs = args || arguments;
831 if(appendArgs === true){
832 callArgs = Array.prototype.slice.call(arguments, 0);
833 callArgs = callArgs.concat(args);
834 }else if(typeof appendArgs == "number"){
835 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
836 var applyArgs = [appendArgs, 0].concat(args); // create method call params
837 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
839 return method.apply(obj || window, callArgs);
844 * Calls this function after the number of millseconds specified.
845 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
846 * @param {Object} obj (optional) The object for which the scope is set
847 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
848 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
849 * if a number the args are inserted at the specified position
850 * @return {Number} The timeout id that can be used with clearTimeout
852 defer : function(millis, obj, args, appendArgs){
853 var fn = this.createDelegate(obj, args, appendArgs);
855 return setTimeout(fn, millis);
861 * Create a combined function call sequence of the original function + the passed function.
862 * The resulting function returns the results of the original function.
863 * The passed fcn is called with the parameters of the original function
864 * @param {Function} fcn The function to sequence
865 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
866 * @return {Function} The new function
868 createSequence : function(fcn, scope){
869 if(typeof fcn != "function"){
874 var retval = method.apply(this || window, arguments);
875 fcn.apply(scope || this || window, arguments);
881 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
882 * The resulting function returns the results of the original function.
883 * The passed fcn is called with the parameters of the original function.
885 * @param {Function} fcn The function to call before the original
886 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
887 * @return {Function} The new function
889 createInterceptor : function(fcn, scope){
890 if(typeof fcn != "function"){
897 if(fcn.apply(scope || this || window, arguments) === false){
900 return method.apply(this || window, arguments);
906 * Ext JS Library 1.1.1
907 * Copyright(c) 2006-2007, Ext JS, LLC.
909 * Originally Released Under LGPL - original licence link has changed is not relivant.
912 * <script type="text/javascript">
915 Roo.applyIf(String, {
920 * Escapes the passed string for ' and \
921 * @param {String} string The string to escape
922 * @return {String} The escaped string
925 escape : function(string) {
926 return string.replace(/('|\\)/g, "\\$1");
930 * Pads the left side of a string with a specified character. This is especially useful
931 * for normalizing number and date strings. Example usage:
933 var s = String.leftPad('123', 5, '0');
934 // s now contains the string: '00123'
936 * @param {String} string The original string
937 * @param {Number} size The total length of the output string
938 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
939 * @return {String} The padded string
942 leftPad : function (val, size, ch) {
943 var result = new String(val);
944 if(ch === null || ch === undefined || ch === '') {
947 while (result.length < size) {
948 result = ch + result;
954 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
955 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
957 var cls = 'my-class', text = 'Some text';
958 var s = String.format('<div class="{0}">{1}</div>', cls, text);
959 // s now contains the string: '<div class="my-class">Some text</div>'
961 * @param {String} string The tokenized string to be formatted
962 * @param {String} value1 The value to replace token {0}
963 * @param {String} value2 Etc...
964 * @return {String} The formatted string
967 format : function(format){
968 var args = Array.prototype.slice.call(arguments, 1);
969 return format.replace(/\{(\d+)\}/g, function(m, i){
970 return Roo.util.Format.htmlEncode(args[i]);
976 * Utility function that allows you to easily switch a string between two alternating values. The passed value
977 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
978 * they are already different, the first value passed in is returned. Note that this method returns the new value
979 * but does not change the current string.
981 // alternate sort directions
982 sort = sort.toggle('ASC', 'DESC');
984 // instead of conditional logic:
985 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
987 * @param {String} value The value to compare to the current string
988 * @param {String} other The new value to use if the string already equals the first value passed in
989 * @return {String} The new value
992 String.prototype.toggle = function(value, other){
993 return this == value ? other : value;
996 * Ext JS Library 1.1.1
997 * Copyright(c) 2006-2007, Ext JS, LLC.
999 * Originally Released Under LGPL - original licence link has changed is not relivant.
1002 * <script type="text/javascript">
1008 Roo.applyIf(Number.prototype, {
1010 * Checks whether or not the current number is within a desired range. If the number is already within the
1011 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
1012 * exceeded. Note that this method returns the constrained value but does not change the current number.
1013 * @param {Number} min The minimum number in the range
1014 * @param {Number} max The maximum number in the range
1015 * @return {Number} The constrained value if outside the range, otherwise the current value
1017 constrain : function(min, max){
1018 return Math.min(Math.max(this, min), max);
1022 * Ext JS Library 1.1.1
1023 * Copyright(c) 2006-2007, Ext JS, LLC.
1025 * Originally Released Under LGPL - original licence link has changed is not relivant.
1028 * <script type="text/javascript">
1033 Roo.applyIf(Array.prototype, {
1035 * Checks whether or not the specified object exists in the array.
1036 * @param {Object} o The object to check for
1037 * @return {Number} The index of o in the array (or -1 if it is not found)
1039 indexOf : function(o){
1040 for (var i = 0, len = this.length; i < len; i++){
1041 if(this[i] == o) return i;
1047 * Removes the specified object from the array. If the object is not found nothing happens.
1048 * @param {Object} o The object to remove
1050 remove : function(o){
1051 var index = this.indexOf(o);
1053 this.splice(index, 1);
1057 * Map (JS 1.6 compatibility)
1058 * @param {Function} function to call
1060 map : function(fun )
1062 var len = this.length >>> 0;
1063 if (typeof fun != "function")
1064 throw new TypeError();
1066 var res = new Array(len);
1067 var thisp = arguments[1];
1068 for (var i = 0; i < len; i++)
1071 res[i] = fun.call(thisp, this[i], i, this);
1082 * Ext JS Library 1.1.1
1083 * Copyright(c) 2006-2007, Ext JS, LLC.
1085 * Originally Released Under LGPL - original licence link has changed is not relivant.
1088 * <script type="text/javascript">
1094 * The date parsing and format syntax is a subset of
1095 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1096 * supported will provide results equivalent to their PHP versions.
1098 * Following is the list of all currently supported formats:
1101 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1103 Format Output Description
1104 ------ ---------- --------------------------------------------------------------
1105 d 10 Day of the month, 2 digits with leading zeros
1106 D Wed A textual representation of a day, three letters
1107 j 10 Day of the month without leading zeros
1108 l Wednesday A full textual representation of the day of the week
1109 S th English ordinal day of month suffix, 2 chars (use with j)
1110 w 3 Numeric representation of the day of the week
1111 z 9 The julian date, or day of the year (0-365)
1112 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1113 F January A full textual representation of the month
1114 m 01 Numeric representation of a month, with leading zeros
1115 M Jan Month name abbreviation, three letters
1116 n 1 Numeric representation of a month, without leading zeros
1117 t 31 Number of days in the given month
1118 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1119 Y 2007 A full numeric representation of a year, 4 digits
1120 y 07 A two digit representation of a year
1121 a pm Lowercase Ante meridiem and Post meridiem
1122 A PM Uppercase Ante meridiem and Post meridiem
1123 g 3 12-hour format of an hour without leading zeros
1124 G 15 24-hour format of an hour without leading zeros
1125 h 03 12-hour format of an hour with leading zeros
1126 H 15 24-hour format of an hour with leading zeros
1127 i 05 Minutes with leading zeros
1128 s 01 Seconds, with leading zeros
1129 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1130 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1131 T CST Timezone setting of the machine running the code
1132 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1135 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1137 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1138 document.write(dt.format('Y-m-d')); //2007-01-10
1139 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1140 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
1143 * Here are some standard date/time patterns that you might find helpful. They
1144 * are not part of the source of Date.js, but to use them you can simply copy this
1145 * block of code into any script that is included after Date.js and they will also become
1146 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1149 ISO8601Long:"Y-m-d H:i:s",
1150 ISO8601Short:"Y-m-d",
1152 LongDate: "l, F d, Y",
1153 FullDateTime: "l, F d, Y g:i:s A",
1156 LongTime: "g:i:s A",
1157 SortableDateTime: "Y-m-d\\TH:i:s",
1158 UniversalSortableDateTime: "Y-m-d H:i:sO",
1165 var dt = new Date();
1166 document.write(dt.format(Date.patterns.ShortDate));
1171 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1172 * They generate precompiled functions from date formats instead of parsing and
1173 * processing the pattern every time you format a date. These functions are available
1174 * on every Date object (any javascript function).
1176 * The original article and download are here:
1177 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1184 Returns the number of milliseconds between this date and date
1185 @param {Date} date (optional) Defaults to now
1186 @return {Number} The diff in milliseconds
1187 @member Date getElapsed
1189 Date.prototype.getElapsed = function(date) {
1190 return Math.abs((date || new Date()).getTime()-this.getTime());
1192 // was in date file..
1196 Date.parseFunctions = {count:0};
1198 Date.parseRegexes = [];
1200 Date.formatFunctions = {count:0};
1203 Date.prototype.dateFormat = function(format) {
1204 if (Date.formatFunctions[format] == null) {
1205 Date.createNewFormat(format);
1207 var func = Date.formatFunctions[format];
1208 return this[func]();
1213 * Formats a date given the supplied format string
1214 * @param {String} format The format string
1215 * @return {String} The formatted date
1218 Date.prototype.format = Date.prototype.dateFormat;
1221 Date.createNewFormat = function(format) {
1222 var funcName = "format" + Date.formatFunctions.count++;
1223 Date.formatFunctions[format] = funcName;
1224 var code = "Date.prototype." + funcName + " = function(){return ";
1225 var special = false;
1227 for (var i = 0; i < format.length; ++i) {
1228 ch = format.charAt(i);
1229 if (!special && ch == "\\") {
1234 code += "'" + String.escape(ch) + "' + ";
1237 code += Date.getFormatCode(ch);
1240 /** eval:var:zzzzzzzzzzzzz */
1241 eval(code.substring(0, code.length - 3) + ";}");
1245 Date.getFormatCode = function(character) {
1246 switch (character) {
1248 return "String.leftPad(this.getDate(), 2, '0') + ";
1250 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1252 return "this.getDate() + ";
1254 return "Date.dayNames[this.getDay()] + ";
1256 return "this.getSuffix() + ";
1258 return "this.getDay() + ";
1260 return "this.getDayOfYear() + ";
1262 return "this.getWeekOfYear() + ";
1264 return "Date.monthNames[this.getMonth()] + ";
1266 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1268 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1270 return "(this.getMonth() + 1) + ";
1272 return "this.getDaysInMonth() + ";
1274 return "(this.isLeapYear() ? 1 : 0) + ";
1276 return "this.getFullYear() + ";
1278 return "('' + this.getFullYear()).substring(2, 4) + ";
1280 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1282 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1284 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1286 return "this.getHours() + ";
1288 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1290 return "String.leftPad(this.getHours(), 2, '0') + ";
1292 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1294 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1296 return "this.getGMTOffset() + ";
1298 return "this.getGMTColonOffset() + ";
1300 return "this.getTimezone() + ";
1302 return "(this.getTimezoneOffset() * -60) + ";
1304 return "'" + String.escape(character) + "' + ";
1309 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1310 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1311 * the date format that is not specified will default to the current date value for that part. Time parts can also
1312 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1313 * string or the parse operation will fail.
1316 //dt = Fri May 25 2007 (current date)
1317 var dt = new Date();
1319 //dt = Thu May 25 2006 (today's month/day in 2006)
1320 dt = Date.parseDate("2006", "Y");
1322 //dt = Sun Jan 15 2006 (all date parts specified)
1323 dt = Date.parseDate("2006-1-15", "Y-m-d");
1325 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1326 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1328 * @param {String} input The unparsed date as a string
1329 * @param {String} format The format the date is in
1330 * @return {Date} The parsed date
1333 Date.parseDate = function(input, format) {
1334 if (Date.parseFunctions[format] == null) {
1335 Date.createParser(format);
1337 var func = Date.parseFunctions[format];
1338 return Date[func](input);
1343 Date.createParser = function(format) {
1344 var funcName = "parse" + Date.parseFunctions.count++;
1345 var regexNum = Date.parseRegexes.length;
1346 var currentGroup = 1;
1347 Date.parseFunctions[format] = funcName;
1349 var code = "Date." + funcName + " = function(input){\n"
1350 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1351 + "var d = new Date();\n"
1352 + "y = d.getFullYear();\n"
1353 + "m = d.getMonth();\n"
1354 + "d = d.getDate();\n"
1355 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1356 + "if (results && results.length > 0) {";
1359 var special = false;
1361 for (var i = 0; i < format.length; ++i) {
1362 ch = format.charAt(i);
1363 if (!special && ch == "\\") {
1368 regex += String.escape(ch);
1371 var obj = Date.formatCodeToRegex(ch, currentGroup);
1372 currentGroup += obj.g;
1374 if (obj.g && obj.c) {
1380 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1381 + "{v = new Date(y, m, d, h, i, s);}\n"
1382 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1383 + "{v = new Date(y, m, d, h, i);}\n"
1384 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1385 + "{v = new Date(y, m, d, h);}\n"
1386 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1387 + "{v = new Date(y, m, d);}\n"
1388 + "else if (y >= 0 && m >= 0)\n"
1389 + "{v = new Date(y, m);}\n"
1390 + "else if (y >= 0)\n"
1391 + "{v = new Date(y);}\n"
1392 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1393 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1394 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1397 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1398 /** eval:var:zzzzzzzzzzzzz */
1403 Date.formatCodeToRegex = function(character, currentGroup) {
1404 switch (character) {
1408 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1411 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1412 s:"(\\d{1,2})"}; // day of month without leading zeroes
1415 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1416 s:"(\\d{2})"}; // day of month with leading zeroes
1420 s:"(?:" + Date.dayNames.join("|") + ")"};
1424 s:"(?:st|nd|rd|th)"};
1439 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1440 s:"(" + Date.monthNames.join("|") + ")"};
1443 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1444 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1447 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1448 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1451 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1452 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1463 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1467 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1468 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1472 c:"if (results[" + currentGroup + "] == 'am') {\n"
1473 + "if (h == 12) { h = 0; }\n"
1474 + "} else { if (h < 12) { h += 12; }}",
1478 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1479 + "if (h == 12) { h = 0; }\n"
1480 + "} else { if (h < 12) { h += 12; }}",
1485 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1486 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1490 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1491 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1494 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1498 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1503 "o = results[", currentGroup, "];\n",
1504 "var sn = o.substring(0,1);\n", // get + / - sign
1505 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1506 "var mn = o.substring(3,5) % 60;\n", // get minutes
1507 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1508 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1510 s:"([+\-]\\d{2,4})"};
1516 "o = results[", currentGroup, "];\n",
1517 "var sn = o.substring(0,1);\n",
1518 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1519 "var mn = o.substring(4,6) % 60;\n",
1520 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1521 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1527 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1530 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1531 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1532 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1536 s:String.escape(character)};
1541 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1542 * @return {String} The abbreviated timezone name (e.g. 'CST')
1544 Date.prototype.getTimezone = function() {
1545 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1549 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1550 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1552 Date.prototype.getGMTOffset = function() {
1553 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1554 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1555 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1559 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1560 * @return {String} 2-characters representing hours and 2-characters representing minutes
1561 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1563 Date.prototype.getGMTColonOffset = function() {
1564 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1565 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1567 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1571 * Get the numeric day number of the year, adjusted for leap year.
1572 * @return {Number} 0 through 364 (365 in leap years)
1574 Date.prototype.getDayOfYear = function() {
1576 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1577 for (var i = 0; i < this.getMonth(); ++i) {
1578 num += Date.daysInMonth[i];
1580 return num + this.getDate() - 1;
1584 * Get the string representation of the numeric week number of the year
1585 * (equivalent to the format specifier 'W').
1586 * @return {String} '00' through '52'
1588 Date.prototype.getWeekOfYear = function() {
1589 // Skip to Thursday of this week
1590 var now = this.getDayOfYear() + (4 - this.getDay());
1591 // Find the first Thursday of the year
1592 var jan1 = new Date(this.getFullYear(), 0, 1);
1593 var then = (7 - jan1.getDay() + 4);
1594 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1598 * Whether or not the current date is in a leap year.
1599 * @return {Boolean} True if the current date is in a leap year, else false
1601 Date.prototype.isLeapYear = function() {
1602 var year = this.getFullYear();
1603 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1607 * Get the first day of the current month, adjusted for leap year. The returned value
1608 * is the numeric day index within the week (0-6) which can be used in conjunction with
1609 * the {@link #monthNames} array to retrieve the textual day name.
1612 var dt = new Date('1/10/2007');
1613 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1615 * @return {Number} The day number (0-6)
1617 Date.prototype.getFirstDayOfMonth = function() {
1618 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1619 return (day < 0) ? (day + 7) : day;
1623 * Get the last day of the current month, adjusted for leap year. The returned value
1624 * is the numeric day index within the week (0-6) which can be used in conjunction with
1625 * the {@link #monthNames} array to retrieve the textual day name.
1628 var dt = new Date('1/10/2007');
1629 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1631 * @return {Number} The day number (0-6)
1633 Date.prototype.getLastDayOfMonth = function() {
1634 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1635 return (day < 0) ? (day + 7) : day;
1640 * Get the first date of this date's month
1643 Date.prototype.getFirstDateOfMonth = function() {
1644 return new Date(this.getFullYear(), this.getMonth(), 1);
1648 * Get the last date of this date's month
1651 Date.prototype.getLastDateOfMonth = function() {
1652 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1655 * Get the number of days in the current month, adjusted for leap year.
1656 * @return {Number} The number of days in the month
1658 Date.prototype.getDaysInMonth = function() {
1659 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1660 return Date.daysInMonth[this.getMonth()];
1664 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1665 * @return {String} 'st, 'nd', 'rd' or 'th'
1667 Date.prototype.getSuffix = function() {
1668 switch (this.getDate()) {
1685 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1688 * An array of textual month names.
1689 * Override these values for international dates, for example...
1690 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1709 * An array of textual day names.
1710 * Override these values for international dates, for example...
1711 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1727 Date.monthNumbers = {
1742 * Creates and returns a new Date instance with the exact same date value as the called instance.
1743 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1744 * variable will also be changed. When the intention is to create a new variable that will not
1745 * modify the original instance, you should create a clone.
1747 * Example of correctly cloning a date:
1750 var orig = new Date('10/1/2006');
1753 document.write(orig); //returns 'Thu Oct 05 2006'!
1756 var orig = new Date('10/1/2006');
1757 var copy = orig.clone();
1759 document.write(orig); //returns 'Thu Oct 01 2006'
1761 * @return {Date} The new Date instance
1763 Date.prototype.clone = function() {
1764 return new Date(this.getTime());
1768 * Clears any time information from this date
1769 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1770 @return {Date} this or the clone
1772 Date.prototype.clearTime = function(clone){
1774 return this.clone().clearTime();
1779 this.setMilliseconds(0);
1784 // safari setMonth is broken
1786 Date.brokenSetMonth = Date.prototype.setMonth;
1787 Date.prototype.setMonth = function(num){
1789 var n = Math.ceil(-num);
1790 var back_year = Math.ceil(n/12);
1791 var month = (n % 12) ? 12 - n % 12 : 0 ;
1792 this.setFullYear(this.getFullYear() - back_year);
1793 return Date.brokenSetMonth.call(this, month);
1795 return Date.brokenSetMonth.apply(this, arguments);
1800 /** Date interval constant
1804 /** Date interval constant
1808 /** Date interval constant
1812 /** Date interval constant
1816 /** Date interval constant
1820 /** Date interval constant
1824 /** Date interval constant
1830 * Provides a convenient method of performing basic date arithmetic. This method
1831 * does not modify the Date instance being called - it creates and returns
1832 * a new Date instance containing the resulting date value.
1837 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1838 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1840 //Negative values will subtract correctly:
1841 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1842 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1844 //You can even chain several calls together in one line!
1845 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1846 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1849 * @param {String} interval A valid date interval enum value
1850 * @param {Number} value The amount to add to the current date
1851 * @return {Date} The new Date instance
1853 Date.prototype.add = function(interval, value){
1854 var d = this.clone();
1855 if (!interval || value === 0) return d;
1856 switch(interval.toLowerCase()){
1858 d.setMilliseconds(this.getMilliseconds() + value);
1861 d.setSeconds(this.getSeconds() + value);
1864 d.setMinutes(this.getMinutes() + value);
1867 d.setHours(this.getHours() + value);
1870 d.setDate(this.getDate() + value);
1873 var day = this.getDate();
1875 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1878 d.setMonth(this.getMonth() + value);
1881 d.setFullYear(this.getFullYear() + value);
1888 * Ext JS Library 1.1.1
1889 * Copyright(c) 2006-2007, Ext JS, LLC.
1891 * Originally Released Under LGPL - original licence link has changed is not relivant.
1894 * <script type="text/javascript">
1898 * @class Roo.lib.Dom
1901 * Dom utils (from YIU afaik)
1906 * Get the view width
1907 * @param {Boolean} full True will get the full document, otherwise it's the view width
1908 * @return {Number} The width
1911 getViewWidth : function(full) {
1912 return full ? this.getDocumentWidth() : this.getViewportWidth();
1915 * Get the view height
1916 * @param {Boolean} full True will get the full document, otherwise it's the view height
1917 * @return {Number} The height
1919 getViewHeight : function(full) {
1920 return full ? this.getDocumentHeight() : this.getViewportHeight();
1923 getDocumentHeight: function() {
1924 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1925 return Math.max(scrollHeight, this.getViewportHeight());
1928 getDocumentWidth: function() {
1929 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1930 return Math.max(scrollWidth, this.getViewportWidth());
1933 getViewportHeight: function() {
1934 var height = self.innerHeight;
1935 var mode = document.compatMode;
1937 if ((mode || Roo.isIE) && !Roo.isOpera) {
1938 height = (mode == "CSS1Compat") ?
1939 document.documentElement.clientHeight :
1940 document.body.clientHeight;
1946 getViewportWidth: function() {
1947 var width = self.innerWidth;
1948 var mode = document.compatMode;
1950 if (mode || Roo.isIE) {
1951 width = (mode == "CSS1Compat") ?
1952 document.documentElement.clientWidth :
1953 document.body.clientWidth;
1958 isAncestor : function(p, c) {
1965 if (p.contains && !Roo.isSafari) {
1966 return p.contains(c);
1967 } else if (p.compareDocumentPosition) {
1968 return !!(p.compareDocumentPosition(c) & 16);
1970 var parent = c.parentNode;
1975 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1978 parent = parent.parentNode;
1984 getRegion : function(el) {
1985 return Roo.lib.Region.getRegion(el);
1988 getY : function(el) {
1989 return this.getXY(el)[1];
1992 getX : function(el) {
1993 return this.getXY(el)[0];
1996 getXY : function(el) {
1997 var p, pe, b, scroll, bd = document.body;
1998 el = Roo.getDom(el);
1999 var fly = Roo.lib.AnimBase.fly;
2000 if (el.getBoundingClientRect) {
2001 b = el.getBoundingClientRect();
2002 scroll = fly(document).getScroll();
2003 return [b.left + scroll.left, b.top + scroll.top];
2009 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2016 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2023 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2024 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2031 if (p != el && pe.getStyle('overflow') != 'visible') {
2039 if (Roo.isSafari && hasAbsolute) {
2044 if (Roo.isGecko && !hasAbsolute) {
2046 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2047 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2051 while (p && p != bd) {
2052 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2064 setXY : function(el, xy) {
2065 el = Roo.fly(el, '_setXY');
2067 var pts = el.translatePoints(xy);
2068 if (xy[0] !== false) {
2069 el.dom.style.left = pts.left + "px";
2071 if (xy[1] !== false) {
2072 el.dom.style.top = pts.top + "px";
2076 setX : function(el, x) {
2077 this.setXY(el, [x, false]);
2080 setY : function(el, y) {
2081 this.setXY(el, [false, y]);
2085 * Portions of this file are based on pieces of Yahoo User Interface Library
2086 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2087 * YUI licensed under the BSD License:
2088 * http://developer.yahoo.net/yui/license.txt
2089 * <script type="text/javascript">
2093 Roo.lib.Event = function() {
2094 var loadComplete = false;
2096 var unloadListeners = [];
2098 var onAvailStack = [];
2100 var lastError = null;
2113 startInterval: function() {
2114 if (!this._interval) {
2116 var callback = function() {
2117 self._tryPreloadAttach();
2119 this._interval = setInterval(callback, this.POLL_INTERVAL);
2124 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2125 onAvailStack.push({ id: p_id,
2128 override: p_override,
2129 checkReady: false });
2131 retryCount = this.POLL_RETRYS;
2132 this.startInterval();
2136 addListener: function(el, eventName, fn) {
2137 el = Roo.getDom(el);
2142 if ("unload" == eventName) {
2143 unloadListeners[unloadListeners.length] =
2144 [el, eventName, fn];
2148 var wrappedFn = function(e) {
2149 return fn(Roo.lib.Event.getEvent(e));
2152 var li = [el, eventName, fn, wrappedFn];
2154 var index = listeners.length;
2155 listeners[index] = li;
2157 this.doAdd(el, eventName, wrappedFn, false);
2163 removeListener: function(el, eventName, fn) {
2166 el = Roo.getDom(el);
2169 return this.purgeElement(el, false, eventName);
2173 if ("unload" == eventName) {
2175 for (i = 0,len = unloadListeners.length; i < len; i++) {
2176 var li = unloadListeners[i];
2179 li[1] == eventName &&
2181 unloadListeners.splice(i, 1);
2189 var cacheItem = null;
2192 var index = arguments[3];
2194 if ("undefined" == typeof index) {
2195 index = this._getCacheIndex(el, eventName, fn);
2199 cacheItem = listeners[index];
2202 if (!el || !cacheItem) {
2206 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2208 delete listeners[index][this.WFN];
2209 delete listeners[index][this.FN];
2210 listeners.splice(index, 1);
2217 getTarget: function(ev, resolveTextNode) {
2218 ev = ev.browserEvent || ev;
2219 var t = ev.target || ev.srcElement;
2220 return this.resolveTextNode(t);
2224 resolveTextNode: function(node) {
2225 if (Roo.isSafari && node && 3 == node.nodeType) {
2226 return node.parentNode;
2233 getPageX: function(ev) {
2234 ev = ev.browserEvent || ev;
2236 if (!x && 0 !== x) {
2237 x = ev.clientX || 0;
2240 x += this.getScroll()[1];
2248 getPageY: function(ev) {
2249 ev = ev.browserEvent || ev;
2251 if (!y && 0 !== y) {
2252 y = ev.clientY || 0;
2255 y += this.getScroll()[0];
2264 getXY: function(ev) {
2265 ev = ev.browserEvent || ev;
2266 return [this.getPageX(ev), this.getPageY(ev)];
2270 getRelatedTarget: function(ev) {
2271 ev = ev.browserEvent || ev;
2272 var t = ev.relatedTarget;
2274 if (ev.type == "mouseout") {
2276 } else if (ev.type == "mouseover") {
2281 return this.resolveTextNode(t);
2285 getTime: function(ev) {
2286 ev = ev.browserEvent || ev;
2288 var t = new Date().getTime();
2292 this.lastError = ex;
2301 stopEvent: function(ev) {
2302 this.stopPropagation(ev);
2303 this.preventDefault(ev);
2307 stopPropagation: function(ev) {
2308 ev = ev.browserEvent || ev;
2309 if (ev.stopPropagation) {
2310 ev.stopPropagation();
2312 ev.cancelBubble = true;
2317 preventDefault: function(ev) {
2318 ev = ev.browserEvent || ev;
2319 if(ev.preventDefault) {
2320 ev.preventDefault();
2322 ev.returnValue = false;
2327 getEvent: function(e) {
2328 var ev = e || window.event;
2330 var c = this.getEvent.caller;
2332 ev = c.arguments[0];
2333 if (ev && Event == ev.constructor) {
2343 getCharCode: function(ev) {
2344 ev = ev.browserEvent || ev;
2345 return ev.charCode || ev.keyCode || 0;
2349 _getCacheIndex: function(el, eventName, fn) {
2350 for (var i = 0,len = listeners.length; i < len; ++i) {
2351 var li = listeners[i];
2353 li[this.FN] == fn &&
2354 li[this.EL] == el &&
2355 li[this.TYPE] == eventName) {
2367 getEl: function(id) {
2368 return document.getElementById(id);
2372 clearCache: function() {
2376 _load: function(e) {
2377 loadComplete = true;
2378 var EU = Roo.lib.Event;
2382 EU.doRemove(window, "load", EU._load);
2387 _tryPreloadAttach: function() {
2396 var tryAgain = !loadComplete;
2398 tryAgain = (retryCount > 0);
2403 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2404 var item = onAvailStack[i];
2406 var el = this.getEl(item.id);
2409 if (!item.checkReady ||
2412 (document && document.body)) {
2415 if (item.override) {
2416 if (item.override === true) {
2419 scope = item.override;
2422 item.fn.call(scope, item.obj);
2423 onAvailStack[i] = null;
2426 notAvail.push(item);
2431 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2435 this.startInterval();
2437 clearInterval(this._interval);
2438 this._interval = null;
2441 this.locked = false;
2448 purgeElement: function(el, recurse, eventName) {
2449 var elListeners = this.getListeners(el, eventName);
2451 for (var i = 0,len = elListeners.length; i < len; ++i) {
2452 var l = elListeners[i];
2453 this.removeListener(el, l.type, l.fn);
2457 if (recurse && el && el.childNodes) {
2458 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2459 this.purgeElement(el.childNodes[i], recurse, eventName);
2465 getListeners: function(el, eventName) {
2466 var results = [], searchLists;
2468 searchLists = [listeners, unloadListeners];
2469 } else if (eventName == "unload") {
2470 searchLists = [unloadListeners];
2472 searchLists = [listeners];
2475 for (var j = 0; j < searchLists.length; ++j) {
2476 var searchList = searchLists[j];
2477 if (searchList && searchList.length > 0) {
2478 for (var i = 0,len = searchList.length; i < len; ++i) {
2479 var l = searchList[i];
2480 if (l && l[this.EL] === el &&
2481 (!eventName || eventName === l[this.TYPE])) {
2486 adjust: l[this.ADJ_SCOPE],
2494 return (results.length) ? results : null;
2498 _unload: function(e) {
2500 var EU = Roo.lib.Event, i, j, l, len, index;
2502 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2503 l = unloadListeners[i];
2506 if (l[EU.ADJ_SCOPE]) {
2507 if (l[EU.ADJ_SCOPE] === true) {
2510 scope = l[EU.ADJ_SCOPE];
2513 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2514 unloadListeners[i] = null;
2520 unloadListeners = null;
2522 if (listeners && listeners.length > 0) {
2523 j = listeners.length;
2526 l = listeners[index];
2528 EU.removeListener(l[EU.EL], l[EU.TYPE],
2538 EU.doRemove(window, "unload", EU._unload);
2543 getScroll: function() {
2544 var dd = document.documentElement, db = document.body;
2545 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2546 return [dd.scrollTop, dd.scrollLeft];
2548 return [db.scrollTop, db.scrollLeft];
2555 doAdd: function () {
2556 if (window.addEventListener) {
2557 return function(el, eventName, fn, capture) {
2558 el.addEventListener(eventName, fn, (capture));
2560 } else if (window.attachEvent) {
2561 return function(el, eventName, fn, capture) {
2562 el.attachEvent("on" + eventName, fn);
2571 doRemove: function() {
2572 if (window.removeEventListener) {
2573 return function (el, eventName, fn, capture) {
2574 el.removeEventListener(eventName, fn, (capture));
2576 } else if (window.detachEvent) {
2577 return function (el, eventName, fn) {
2578 el.detachEvent("on" + eventName, fn);
2590 var E = Roo.lib.Event;
2591 E.on = E.addListener;
2592 E.un = E.removeListener;
2594 if (document && document.body) {
2597 E.doAdd(window, "load", E._load);
2599 E.doAdd(window, "unload", E._unload);
2600 E._tryPreloadAttach();
2604 * Portions of this file are based on pieces of Yahoo User Interface Library
2605 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2606 * YUI licensed under the BSD License:
2607 * http://developer.yahoo.net/yui/license.txt
2608 * <script type="text/javascript">
2614 * @class Roo.lib.Ajax
2621 request : function(method, uri, cb, data, options) {
2623 var hs = options.headers;
2626 if(hs.hasOwnProperty(h)){
2627 this.initHeader(h, hs[h], false);
2631 if(options.xmlData){
2632 this.initHeader('Content-Type', 'text/xml', false);
2634 data = options.xmlData;
2638 return this.asyncRequest(method, uri, cb, data);
2641 serializeForm : function(form) {
2642 if(typeof form == 'string') {
2643 form = (document.getElementById(form) || document.forms[form]);
2646 var el, name, val, disabled, data = '', hasSubmit = false;
2647 for (var i = 0; i < form.elements.length; i++) {
2648 el = form.elements[i];
2649 disabled = form.elements[i].disabled;
2650 name = form.elements[i].name;
2651 val = form.elements[i].value;
2653 if (!disabled && name){
2657 case 'select-multiple':
2658 for (var j = 0; j < el.options.length; j++) {
2659 if (el.options[j].selected) {
2661 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2664 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2672 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2685 if(hasSubmit == false) {
2686 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2691 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2696 data = data.substr(0, data.length - 1);
2704 useDefaultHeader:true,
2706 defaultPostHeader:'application/x-www-form-urlencoded',
2708 useDefaultXhrHeader:true,
2710 defaultXhrHeader:'XMLHttpRequest',
2712 hasDefaultHeaders:true,
2724 setProgId:function(id)
2726 this.activeX.unshift(id);
2729 setDefaultPostHeader:function(b)
2731 this.useDefaultHeader = b;
2734 setDefaultXhrHeader:function(b)
2736 this.useDefaultXhrHeader = b;
2739 setPollingInterval:function(i)
2741 if (typeof i == 'number' && isFinite(i)) {
2742 this.pollInterval = i;
2746 createXhrObject:function(transactionId)
2752 http = new XMLHttpRequest();
2754 obj = { conn:http, tId:transactionId };
2758 for (var i = 0; i < this.activeX.length; ++i) {
2762 http = new ActiveXObject(this.activeX[i]);
2764 obj = { conn:http, tId:transactionId };
2777 getConnectionObject:function()
2780 var tId = this.transactionId;
2784 o = this.createXhrObject(tId);
2786 this.transactionId++;
2797 asyncRequest:function(method, uri, callback, postData)
2799 var o = this.getConnectionObject();
2805 o.conn.open(method, uri, true);
2807 if (this.useDefaultXhrHeader) {
2808 if (!this.defaultHeaders['X-Requested-With']) {
2809 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2813 if(postData && this.useDefaultHeader){
2814 this.initHeader('Content-Type', this.defaultPostHeader);
2817 if (this.hasDefaultHeaders || this.hasHeaders) {
2821 this.handleReadyState(o, callback);
2822 o.conn.send(postData || null);
2828 handleReadyState:function(o, callback)
2832 if (callback && callback.timeout) {
2834 this.timeout[o.tId] = window.setTimeout(function() {
2835 oConn.abort(o, callback, true);
2836 }, callback.timeout);
2839 this.poll[o.tId] = window.setInterval(
2841 if (o.conn && o.conn.readyState == 4) {
2842 window.clearInterval(oConn.poll[o.tId]);
2843 delete oConn.poll[o.tId];
2845 if(callback && callback.timeout) {
2846 window.clearTimeout(oConn.timeout[o.tId]);
2847 delete oConn.timeout[o.tId];
2850 oConn.handleTransactionResponse(o, callback);
2853 , this.pollInterval);
2856 handleTransactionResponse:function(o, callback, isAbort)
2860 this.releaseObject(o);
2864 var httpStatus, responseObject;
2868 if (o.conn.status !== undefined && o.conn.status != 0) {
2869 httpStatus = o.conn.status;
2881 if (httpStatus >= 200 && httpStatus < 300) {
2882 responseObject = this.createResponseObject(o, callback.argument);
2883 if (callback.success) {
2884 if (!callback.scope) {
2885 callback.success(responseObject);
2890 callback.success.apply(callback.scope, [responseObject]);
2895 switch (httpStatus) {
2903 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2904 if (callback.failure) {
2905 if (!callback.scope) {
2906 callback.failure(responseObject);
2909 callback.failure.apply(callback.scope, [responseObject]);
2914 responseObject = this.createResponseObject(o, callback.argument);
2915 if (callback.failure) {
2916 if (!callback.scope) {
2917 callback.failure(responseObject);
2920 callback.failure.apply(callback.scope, [responseObject]);
2926 this.releaseObject(o);
2927 responseObject = null;
2930 createResponseObject:function(o, callbackArg)
2937 var headerStr = o.conn.getAllResponseHeaders();
2938 var header = headerStr.split('\n');
2939 for (var i = 0; i < header.length; i++) {
2940 var delimitPos = header[i].indexOf(':');
2941 if (delimitPos != -1) {
2942 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2950 obj.status = o.conn.status;
2951 obj.statusText = o.conn.statusText;
2952 obj.getResponseHeader = headerObj;
2953 obj.getAllResponseHeaders = headerStr;
2954 obj.responseText = o.conn.responseText;
2955 obj.responseXML = o.conn.responseXML;
2957 if (typeof callbackArg !== undefined) {
2958 obj.argument = callbackArg;
2964 createExceptionObject:function(tId, callbackArg, isAbort)
2967 var COMM_ERROR = 'communication failure';
2968 var ABORT_CODE = -1;
2969 var ABORT_ERROR = 'transaction aborted';
2975 obj.status = ABORT_CODE;
2976 obj.statusText = ABORT_ERROR;
2979 obj.status = COMM_CODE;
2980 obj.statusText = COMM_ERROR;
2984 obj.argument = callbackArg;
2990 initHeader:function(label, value, isDefault)
2992 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2994 if (headerObj[label] === undefined) {
2995 headerObj[label] = value;
3000 headerObj[label] = value + "," + headerObj[label];
3004 this.hasDefaultHeaders = true;
3007 this.hasHeaders = true;
3012 setHeader:function(o)
3014 if (this.hasDefaultHeaders) {
3015 for (var prop in this.defaultHeaders) {
3016 if (this.defaultHeaders.hasOwnProperty(prop)) {
3017 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3022 if (this.hasHeaders) {
3023 for (var prop in this.headers) {
3024 if (this.headers.hasOwnProperty(prop)) {
3025 o.conn.setRequestHeader(prop, this.headers[prop]);
3029 this.hasHeaders = false;
3033 resetDefaultHeaders:function() {
3034 delete this.defaultHeaders;
3035 this.defaultHeaders = {};
3036 this.hasDefaultHeaders = false;
3039 abort:function(o, callback, isTimeout)
3041 if(this.isCallInProgress(o)) {
3043 window.clearInterval(this.poll[o.tId]);
3044 delete this.poll[o.tId];
3046 delete this.timeout[o.tId];
3049 this.handleTransactionResponse(o, callback, true);
3059 isCallInProgress:function(o)
3062 return o.conn.readyState != 4 && o.conn.readyState != 0;
3071 releaseObject:function(o)
3080 'MSXML2.XMLHTTP.3.0',
3088 * Portions of this file are based on pieces of Yahoo User Interface Library
3089 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3090 * YUI licensed under the BSD License:
3091 * http://developer.yahoo.net/yui/license.txt
3092 * <script type="text/javascript">
3096 Roo.lib.Region = function(t, r, b, l) {
3106 Roo.lib.Region.prototype = {
3107 contains : function(region) {
3108 return ( region.left >= this.left &&
3109 region.right <= this.right &&
3110 region.top >= this.top &&
3111 region.bottom <= this.bottom );
3115 getArea : function() {
3116 return ( (this.bottom - this.top) * (this.right - this.left) );
3119 intersect : function(region) {
3120 var t = Math.max(this.top, region.top);
3121 var r = Math.min(this.right, region.right);
3122 var b = Math.min(this.bottom, region.bottom);
3123 var l = Math.max(this.left, region.left);
3125 if (b >= t && r >= l) {
3126 return new Roo.lib.Region(t, r, b, l);
3131 union : function(region) {
3132 var t = Math.min(this.top, region.top);
3133 var r = Math.max(this.right, region.right);
3134 var b = Math.max(this.bottom, region.bottom);
3135 var l = Math.min(this.left, region.left);
3137 return new Roo.lib.Region(t, r, b, l);
3140 adjust : function(t, l, b, r) {
3149 Roo.lib.Region.getRegion = function(el) {
3150 var p = Roo.lib.Dom.getXY(el);
3153 var r = p[0] + el.offsetWidth;
3154 var b = p[1] + el.offsetHeight;
3157 return new Roo.lib.Region(t, r, b, l);
3160 * Portions of this file are based on pieces of Yahoo User Interface Library
3161 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3162 * YUI licensed under the BSD License:
3163 * http://developer.yahoo.net/yui/license.txt
3164 * <script type="text/javascript">
3167 //@@dep Roo.lib.Region
3170 Roo.lib.Point = function(x, y) {
3171 if (x instanceof Array) {
3175 this.x = this.right = this.left = this[0] = x;
3176 this.y = this.top = this.bottom = this[1] = y;
3179 Roo.lib.Point.prototype = new Roo.lib.Region();
3181 * Portions of this file are based on pieces of Yahoo User Interface Library
3182 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3183 * YUI licensed under the BSD License:
3184 * http://developer.yahoo.net/yui/license.txt
3185 * <script type="text/javascript">
3192 scroll : function(el, args, duration, easing, cb, scope) {
3193 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3196 motion : function(el, args, duration, easing, cb, scope) {
3197 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3200 color : function(el, args, duration, easing, cb, scope) {
3201 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3204 run : function(el, args, duration, easing, cb, scope, type) {
3205 type = type || Roo.lib.AnimBase;
3206 if (typeof easing == "string") {
3207 easing = Roo.lib.Easing[easing];
3209 var anim = new type(el, args, duration, easing);
3210 anim.animateX(function() {
3211 Roo.callback(cb, scope);
3217 * Portions of this file are based on pieces of Yahoo User Interface Library
3218 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3219 * YUI licensed under the BSD License:
3220 * http://developer.yahoo.net/yui/license.txt
3221 * <script type="text/javascript">
3229 if (!libFlyweight) {
3230 libFlyweight = new Roo.Element.Flyweight();
3232 libFlyweight.dom = el;
3233 return libFlyweight;
3236 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3240 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3242 this.init(el, attributes, duration, method);
3246 Roo.lib.AnimBase.fly = fly;
3250 Roo.lib.AnimBase.prototype = {
3252 toString: function() {
3253 var el = this.getEl();
3254 var id = el.id || el.tagName;
3255 return ("Anim " + id);
3259 noNegatives: /width|height|opacity|padding/i,
3260 offsetAttribute: /^((width|height)|(top|left))$/,
3261 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3262 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3266 doMethod: function(attr, start, end) {
3267 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3271 setAttribute: function(attr, val, unit) {
3272 if (this.patterns.noNegatives.test(attr)) {
3273 val = (val > 0) ? val : 0;
3276 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3280 getAttribute: function(attr) {
3281 var el = this.getEl();
3282 var val = fly(el).getStyle(attr);
3284 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3285 return parseFloat(val);
3288 var a = this.patterns.offsetAttribute.exec(attr) || [];
3289 var pos = !!( a[3] );
3290 var box = !!( a[2] );
3293 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3294 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3303 getDefaultUnit: function(attr) {
3304 if (this.patterns.defaultUnit.test(attr)) {
3311 animateX : function(callback, scope) {
3312 var f = function() {
3313 this.onComplete.removeListener(f);
3314 if (typeof callback == "function") {
3315 callback.call(scope || this, this);
3318 this.onComplete.addListener(f, this);
3323 setRuntimeAttribute: function(attr) {
3326 var attributes = this.attributes;
3328 this.runtimeAttributes[attr] = {};
3330 var isset = function(prop) {
3331 return (typeof prop !== 'undefined');
3334 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3338 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3341 if (isset(attributes[attr]['to'])) {
3342 end = attributes[attr]['to'];
3343 } else if (isset(attributes[attr]['by'])) {
3344 if (start.constructor == Array) {
3346 for (var i = 0, len = start.length; i < len; ++i) {
3347 end[i] = start[i] + attributes[attr]['by'][i];
3350 end = start + attributes[attr]['by'];
3354 this.runtimeAttributes[attr].start = start;
3355 this.runtimeAttributes[attr].end = end;
3358 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3362 init: function(el, attributes, duration, method) {
3364 var isAnimated = false;
3367 var startTime = null;
3370 var actualFrames = 0;
3373 el = Roo.getDom(el);
3376 this.attributes = attributes || {};
3379 this.duration = duration || 1;
3382 this.method = method || Roo.lib.Easing.easeNone;
3385 this.useSeconds = true;
3388 this.currentFrame = 0;
3391 this.totalFrames = Roo.lib.AnimMgr.fps;
3394 this.getEl = function() {
3399 this.isAnimated = function() {
3404 this.getStartTime = function() {
3408 this.runtimeAttributes = {};
3411 this.animate = function() {
3412 if (this.isAnimated()) {
3416 this.currentFrame = 0;
3418 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3420 Roo.lib.AnimMgr.registerElement(this);
3424 this.stop = function(finish) {
3426 this.currentFrame = this.totalFrames;
3427 this._onTween.fire();
3429 Roo.lib.AnimMgr.stop(this);
3432 var onStart = function() {
3433 this.onStart.fire();
3435 this.runtimeAttributes = {};
3436 for (var attr in this.attributes) {
3437 this.setRuntimeAttribute(attr);
3442 startTime = new Date();
3446 var onTween = function() {
3448 duration: new Date() - this.getStartTime(),
3449 currentFrame: this.currentFrame
3452 data.toString = function() {
3454 'duration: ' + data.duration +
3455 ', currentFrame: ' + data.currentFrame
3459 this.onTween.fire(data);
3461 var runtimeAttributes = this.runtimeAttributes;
3463 for (var attr in runtimeAttributes) {
3464 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3470 var onComplete = function() {
3471 var actual_duration = (new Date() - startTime) / 1000 ;
3474 duration: actual_duration,
3475 frames: actualFrames,
3476 fps: actualFrames / actual_duration
3479 data.toString = function() {
3481 'duration: ' + data.duration +
3482 ', frames: ' + data.frames +
3483 ', fps: ' + data.fps
3489 this.onComplete.fire(data);
3493 this._onStart = new Roo.util.Event(this);
3494 this.onStart = new Roo.util.Event(this);
3495 this.onTween = new Roo.util.Event(this);
3496 this._onTween = new Roo.util.Event(this);
3497 this.onComplete = new Roo.util.Event(this);
3498 this._onComplete = new Roo.util.Event(this);
3499 this._onStart.addListener(onStart);
3500 this._onTween.addListener(onTween);
3501 this._onComplete.addListener(onComplete);
3506 * Portions of this file are based on pieces of Yahoo User Interface Library
3507 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3508 * YUI licensed under the BSD License:
3509 * http://developer.yahoo.net/yui/license.txt
3510 * <script type="text/javascript">
3514 Roo.lib.AnimMgr = new function() {
3531 this.registerElement = function(tween) {
3532 queue[queue.length] = tween;
3534 tween._onStart.fire();
3539 this.unRegister = function(tween, index) {
3540 tween._onComplete.fire();
3541 index = index || getIndex(tween);
3543 queue.splice(index, 1);
3547 if (tweenCount <= 0) {
3553 this.start = function() {
3554 if (thread === null) {
3555 thread = setInterval(this.run, this.delay);
3560 this.stop = function(tween) {
3562 clearInterval(thread);
3564 for (var i = 0, len = queue.length; i < len; ++i) {
3565 if (queue[0].isAnimated()) {
3566 this.unRegister(queue[0], 0);
3575 this.unRegister(tween);
3580 this.run = function() {
3581 for (var i = 0, len = queue.length; i < len; ++i) {
3582 var tween = queue[i];
3583 if (!tween || !tween.isAnimated()) {
3587 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3589 tween.currentFrame += 1;
3591 if (tween.useSeconds) {
3592 correctFrame(tween);
3594 tween._onTween.fire();
3597 Roo.lib.AnimMgr.stop(tween, i);
3602 var getIndex = function(anim) {
3603 for (var i = 0, len = queue.length; i < len; ++i) {
3604 if (queue[i] == anim) {
3612 var correctFrame = function(tween) {
3613 var frames = tween.totalFrames;
3614 var frame = tween.currentFrame;
3615 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3616 var elapsed = (new Date() - tween.getStartTime());
3619 if (elapsed < tween.duration * 1000) {
3620 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3622 tweak = frames - (frame + 1);
3624 if (tweak > 0 && isFinite(tweak)) {
3625 if (tween.currentFrame + tweak >= frames) {
3626 tweak = frames - (frame + 1);
3629 tween.currentFrame += tweak;
3633 * Portions of this file are based on pieces of Yahoo User Interface Library
3634 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3635 * YUI licensed under the BSD License:
3636 * http://developer.yahoo.net/yui/license.txt
3637 * <script type="text/javascript">
3640 Roo.lib.Bezier = new function() {
3642 this.getPosition = function(points, t) {
3643 var n = points.length;
3646 for (var i = 0; i < n; ++i) {
3647 tmp[i] = [points[i][0], points[i][1]];
3650 for (var j = 1; j < n; ++j) {
3651 for (i = 0; i < n - j; ++i) {
3652 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3653 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3657 return [ tmp[0][0], tmp[0][1] ];
3661 * Portions of this file are based on pieces of Yahoo User Interface Library
3662 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3663 * YUI licensed under the BSD License:
3664 * http://developer.yahoo.net/yui/license.txt
3665 * <script type="text/javascript">
3670 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3671 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3674 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3676 var fly = Roo.lib.AnimBase.fly;
3678 var superclass = Y.ColorAnim.superclass;
3679 var proto = Y.ColorAnim.prototype;
3681 proto.toString = function() {
3682 var el = this.getEl();
3683 var id = el.id || el.tagName;
3684 return ("ColorAnim " + id);
3687 proto.patterns.color = /color$/i;
3688 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3689 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3690 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3691 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3694 proto.parseColor = function(s) {
3695 if (s.length == 3) {
3699 var c = this.patterns.hex.exec(s);
3700 if (c && c.length == 4) {
3701 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3704 c = this.patterns.rgb.exec(s);
3705 if (c && c.length == 4) {
3706 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3709 c = this.patterns.hex3.exec(s);
3710 if (c && c.length == 4) {
3711 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3716 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3717 proto.getAttribute = function(attr) {
3718 var el = this.getEl();
3719 if (this.patterns.color.test(attr)) {
3720 var val = fly(el).getStyle(attr);
3722 if (this.patterns.transparent.test(val)) {
3723 var parent = el.parentNode;
3724 val = fly(parent).getStyle(attr);
3726 while (parent && this.patterns.transparent.test(val)) {
3727 parent = parent.parentNode;
3728 val = fly(parent).getStyle(attr);
3729 if (parent.tagName.toUpperCase() == 'HTML') {
3735 val = superclass.getAttribute.call(this, attr);
3740 proto.getAttribute = function(attr) {
3741 var el = this.getEl();
3742 if (this.patterns.color.test(attr)) {
3743 var val = fly(el).getStyle(attr);
3745 if (this.patterns.transparent.test(val)) {
3746 var parent = el.parentNode;
3747 val = fly(parent).getStyle(attr);
3749 while (parent && this.patterns.transparent.test(val)) {
3750 parent = parent.parentNode;
3751 val = fly(parent).getStyle(attr);
3752 if (parent.tagName.toUpperCase() == 'HTML') {
3758 val = superclass.getAttribute.call(this, attr);
3764 proto.doMethod = function(attr, start, end) {
3767 if (this.patterns.color.test(attr)) {
3769 for (var i = 0, len = start.length; i < len; ++i) {
3770 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3773 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3776 val = superclass.doMethod.call(this, attr, start, end);
3782 proto.setRuntimeAttribute = function(attr) {
3783 superclass.setRuntimeAttribute.call(this, attr);
3785 if (this.patterns.color.test(attr)) {
3786 var attributes = this.attributes;
3787 var start = this.parseColor(this.runtimeAttributes[attr].start);
3788 var end = this.parseColor(this.runtimeAttributes[attr].end);
3790 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3791 end = this.parseColor(attributes[attr].by);
3793 for (var i = 0, len = start.length; i < len; ++i) {
3794 end[i] = start[i] + end[i];
3798 this.runtimeAttributes[attr].start = start;
3799 this.runtimeAttributes[attr].end = end;
3805 * Portions of this file are based on pieces of Yahoo User Interface Library
3806 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3807 * YUI licensed under the BSD License:
3808 * http://developer.yahoo.net/yui/license.txt
3809 * <script type="text/javascript">
3815 easeNone: function (t, b, c, d) {
3816 return c * t / d + b;
3820 easeIn: function (t, b, c, d) {
3821 return c * (t /= d) * t + b;
3825 easeOut: function (t, b, c, d) {
3826 return -c * (t /= d) * (t - 2) + b;
3830 easeBoth: function (t, b, c, d) {
3831 if ((t /= d / 2) < 1) {
3832 return c / 2 * t * t + b;
3835 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3839 easeInStrong: function (t, b, c, d) {
3840 return c * (t /= d) * t * t * t + b;
3844 easeOutStrong: function (t, b, c, d) {
3845 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3849 easeBothStrong: function (t, b, c, d) {
3850 if ((t /= d / 2) < 1) {
3851 return c / 2 * t * t * t * t + b;
3854 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3859 elasticIn: function (t, b, c, d, a, p) {
3863 if ((t /= d) == 1) {
3870 if (!a || a < Math.abs(c)) {
3875 var s = p / (2 * Math.PI) * Math.asin(c / a);
3878 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3882 elasticOut: function (t, b, c, d, a, p) {
3886 if ((t /= d) == 1) {
3893 if (!a || a < Math.abs(c)) {
3898 var s = p / (2 * Math.PI) * Math.asin(c / a);
3901 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3905 elasticBoth: function (t, b, c, d, a, p) {
3910 if ((t /= d / 2) == 2) {
3918 if (!a || a < Math.abs(c)) {
3923 var s = p / (2 * Math.PI) * Math.asin(c / a);
3927 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3928 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3930 return a * Math.pow(2, -10 * (t -= 1)) *
3931 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3936 backIn: function (t, b, c, d, s) {
3937 if (typeof s == 'undefined') {
3940 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3944 backOut: function (t, b, c, d, s) {
3945 if (typeof s == 'undefined') {
3948 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3952 backBoth: function (t, b, c, d, s) {
3953 if (typeof s == 'undefined') {
3957 if ((t /= d / 2 ) < 1) {
3958 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3960 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3964 bounceIn: function (t, b, c, d) {
3965 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3969 bounceOut: function (t, b, c, d) {
3970 if ((t /= d) < (1 / 2.75)) {
3971 return c * (7.5625 * t * t) + b;
3972 } else if (t < (2 / 2.75)) {
3973 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3974 } else if (t < (2.5 / 2.75)) {
3975 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3977 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3981 bounceBoth: function (t, b, c, d) {
3983 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3985 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3988 * Portions of this file are based on pieces of Yahoo User Interface Library
3989 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3990 * YUI licensed under the BSD License:
3991 * http://developer.yahoo.net/yui/license.txt
3992 * <script type="text/javascript">
3996 Roo.lib.Motion = function(el, attributes, duration, method) {
3998 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4002 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4006 var superclass = Y.Motion.superclass;
4007 var proto = Y.Motion.prototype;
4009 proto.toString = function() {
4010 var el = this.getEl();
4011 var id = el.id || el.tagName;
4012 return ("Motion " + id);
4015 proto.patterns.points = /^points$/i;
4017 proto.setAttribute = function(attr, val, unit) {
4018 if (this.patterns.points.test(attr)) {
4019 unit = unit || 'px';
4020 superclass.setAttribute.call(this, 'left', val[0], unit);
4021 superclass.setAttribute.call(this, 'top', val[1], unit);
4023 superclass.setAttribute.call(this, attr, val, unit);
4027 proto.getAttribute = function(attr) {
4028 if (this.patterns.points.test(attr)) {
4030 superclass.getAttribute.call(this, 'left'),
4031 superclass.getAttribute.call(this, 'top')
4034 val = superclass.getAttribute.call(this, attr);
4040 proto.doMethod = function(attr, start, end) {
4043 if (this.patterns.points.test(attr)) {
4044 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4045 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4047 val = superclass.doMethod.call(this, attr, start, end);
4052 proto.setRuntimeAttribute = function(attr) {
4053 if (this.patterns.points.test(attr)) {
4054 var el = this.getEl();
4055 var attributes = this.attributes;
4057 var control = attributes['points']['control'] || [];
4061 if (control.length > 0 && !(control[0] instanceof Array)) {
4062 control = [control];
4065 for (i = 0,len = control.length; i < len; ++i) {
4066 tmp[i] = control[i];
4071 Roo.fly(el).position();
4073 if (isset(attributes['points']['from'])) {
4074 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4077 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4080 start = this.getAttribute('points');
4083 if (isset(attributes['points']['to'])) {
4084 end = translateValues.call(this, attributes['points']['to'], start);
4086 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4087 for (i = 0,len = control.length; i < len; ++i) {
4088 control[i] = translateValues.call(this, control[i], start);
4092 } else if (isset(attributes['points']['by'])) {
4093 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4095 for (i = 0,len = control.length; i < len; ++i) {
4096 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4100 this.runtimeAttributes[attr] = [start];
4102 if (control.length > 0) {
4103 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4106 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4109 superclass.setRuntimeAttribute.call(this, attr);
4113 var translateValues = function(val, start) {
4114 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4115 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4120 var isset = function(prop) {
4121 return (typeof prop !== 'undefined');
4125 * Portions of this file are based on pieces of Yahoo User Interface Library
4126 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4127 * YUI licensed under the BSD License:
4128 * http://developer.yahoo.net/yui/license.txt
4129 * <script type="text/javascript">
4133 Roo.lib.Scroll = function(el, attributes, duration, method) {
4135 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4139 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4143 var superclass = Y.Scroll.superclass;
4144 var proto = Y.Scroll.prototype;
4146 proto.toString = function() {
4147 var el = this.getEl();
4148 var id = el.id || el.tagName;
4149 return ("Scroll " + id);
4152 proto.doMethod = function(attr, start, end) {
4155 if (attr == 'scroll') {
4157 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4158 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4162 val = superclass.doMethod.call(this, attr, start, end);
4167 proto.getAttribute = function(attr) {
4169 var el = this.getEl();
4171 if (attr == 'scroll') {
4172 val = [ el.scrollLeft, el.scrollTop ];
4174 val = superclass.getAttribute.call(this, attr);
4180 proto.setAttribute = function(attr, val, unit) {
4181 var el = this.getEl();
4183 if (attr == 'scroll') {
4184 el.scrollLeft = val[0];
4185 el.scrollTop = val[1];
4187 superclass.setAttribute.call(this, attr, val, unit);
4193 * Ext JS Library 1.1.1
4194 * Copyright(c) 2006-2007, Ext JS, LLC.
4196 * Originally Released Under LGPL - original licence link has changed is not relivant.
4199 * <script type="text/javascript">
4203 // nasty IE9 hack - what a pile of crap that is..
4205 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4206 Range.prototype.createContextualFragment = function (html) {
4207 var doc = window.document;
4208 var container = doc.createElement("div");
4209 container.innerHTML = html;
4210 var frag = doc.createDocumentFragment(), n;
4211 while ((n = container.firstChild)) {
4212 frag.appendChild(n);
4219 * @class Roo.DomHelper
4220 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4221 * 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>.
4224 Roo.DomHelper = function(){
4225 var tempTableEl = null;
4226 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4227 var tableRe = /^table|tbody|tr|td$/i;
4229 // build as innerHTML where available
4231 var createHtml = function(o){
4232 if(typeof o == 'string'){
4241 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4242 if(attr == "style"){
4244 if(typeof s == "function"){
4247 if(typeof s == "string"){
4248 b += ' style="' + s + '"';
4249 }else if(typeof s == "object"){
4252 if(typeof s[key] != "function"){
4253 b += key + ":" + s[key] + ";";
4260 b += ' class="' + o["cls"] + '"';
4261 }else if(attr == "htmlFor"){
4262 b += ' for="' + o["htmlFor"] + '"';
4264 b += " " + attr + '="' + o[attr] + '"';
4268 if(emptyTags.test(o.tag)){
4272 var cn = o.children || o.cn;
4274 //http://bugs.kde.org/show_bug.cgi?id=71506
4275 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4276 for(var i = 0, len = cn.length; i < len; i++) {
4277 b += createHtml(cn[i], b);
4280 b += createHtml(cn, b);
4286 b += "</" + o.tag + ">";
4293 var createDom = function(o, parentNode){
4295 // defininition craeted..
4297 if (o.ns && o.ns != 'html') {
4299 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4300 xmlns[o.ns] = o.xmlns;
4303 if (typeof(xmlns[o.ns]) == 'undefined') {
4304 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4310 if (typeof(o) == 'string') {
4311 return parentNode.appendChild(document.createTextNode(o));
4313 o.tag = o.tag || div;
4314 if (o.ns && Roo.isIE) {
4316 o.tag = o.ns + ':' + o.tag;
4319 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4320 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4323 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4324 attr == "style" || typeof o[attr] == "function") continue;
4326 if(attr=="cls" && Roo.isIE){
4327 el.className = o["cls"];
4329 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4330 else el[attr] = o[attr];
4333 Roo.DomHelper.applyStyles(el, o.style);
4334 var cn = o.children || o.cn;
4336 //http://bugs.kde.org/show_bug.cgi?id=71506
4337 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4338 for(var i = 0, len = cn.length; i < len; i++) {
4339 createDom(cn[i], el);
4346 el.innerHTML = o.html;
4349 parentNode.appendChild(el);
4354 var ieTable = function(depth, s, h, e){
4355 tempTableEl.innerHTML = [s, h, e].join('');
4356 var i = -1, el = tempTableEl;
4363 // kill repeat to save bytes
4367 tbe = '</tbody>'+te,
4373 * Nasty code for IE's broken table implementation
4375 var insertIntoTable = function(tag, where, el, html){
4377 tempTableEl = document.createElement('div');
4382 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4385 if(where == 'beforebegin'){
4389 before = el.nextSibling;
4392 node = ieTable(4, trs, html, tre);
4394 else if(tag == 'tr'){
4395 if(where == 'beforebegin'){
4398 node = ieTable(3, tbs, html, tbe);
4399 } else if(where == 'afterend'){
4400 before = el.nextSibling;
4402 node = ieTable(3, tbs, html, tbe);
4403 } else{ // INTO a TR
4404 if(where == 'afterbegin'){
4405 before = el.firstChild;
4407 node = ieTable(4, trs, html, tre);
4409 } else if(tag == 'tbody'){
4410 if(where == 'beforebegin'){
4413 node = ieTable(2, ts, html, te);
4414 } else if(where == 'afterend'){
4415 before = el.nextSibling;
4417 node = ieTable(2, ts, html, te);
4419 if(where == 'afterbegin'){
4420 before = el.firstChild;
4422 node = ieTable(3, tbs, html, tbe);
4425 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4428 if(where == 'afterbegin'){
4429 before = el.firstChild;
4431 node = ieTable(2, ts, html, te);
4433 el.insertBefore(node, before);
4438 /** True to force the use of DOM instead of html fragments @type Boolean */
4442 * Returns the markup for the passed Element(s) config
4443 * @param {Object} o The Dom object spec (and children)
4446 markup : function(o){
4447 return createHtml(o);
4451 * Applies a style specification to an element
4452 * @param {String/HTMLElement} el The element to apply styles to
4453 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4454 * a function which returns such a specification.
4456 applyStyles : function(el, styles){
4459 if(typeof styles == "string"){
4460 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4462 while ((matches = re.exec(styles)) != null){
4463 el.setStyle(matches[1], matches[2]);
4465 }else if (typeof styles == "object"){
4466 for (var style in styles){
4467 el.setStyle(style, styles[style]);
4469 }else if (typeof styles == "function"){
4470 Roo.DomHelper.applyStyles(el, styles.call());
4476 * Inserts an HTML fragment into the Dom
4477 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4478 * @param {HTMLElement} el The context element
4479 * @param {String} html The HTML fragmenet
4480 * @return {HTMLElement} The new node
4482 insertHtml : function(where, el, html){
4483 where = where.toLowerCase();
4484 if(el.insertAdjacentHTML){
4485 if(tableRe.test(el.tagName)){
4487 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4493 el.insertAdjacentHTML('BeforeBegin', html);
4494 return el.previousSibling;
4496 el.insertAdjacentHTML('AfterBegin', html);
4497 return el.firstChild;
4499 el.insertAdjacentHTML('BeforeEnd', html);
4500 return el.lastChild;
4502 el.insertAdjacentHTML('AfterEnd', html);
4503 return el.nextSibling;
4505 throw 'Illegal insertion point -> "' + where + '"';
4507 var range = el.ownerDocument.createRange();
4511 range.setStartBefore(el);
4512 frag = range.createContextualFragment(html);
4513 el.parentNode.insertBefore(frag, el);
4514 return el.previousSibling;
4517 range.setStartBefore(el.firstChild);
4518 frag = range.createContextualFragment(html);
4519 el.insertBefore(frag, el.firstChild);
4520 return el.firstChild;
4522 el.innerHTML = html;
4523 return el.firstChild;
4527 range.setStartAfter(el.lastChild);
4528 frag = range.createContextualFragment(html);
4529 el.appendChild(frag);
4530 return el.lastChild;
4532 el.innerHTML = html;
4533 return el.lastChild;
4536 range.setStartAfter(el);
4537 frag = range.createContextualFragment(html);
4538 el.parentNode.insertBefore(frag, el.nextSibling);
4539 return el.nextSibling;
4541 throw 'Illegal insertion point -> "' + where + '"';
4545 * Creates new Dom element(s) and inserts them before el
4546 * @param {String/HTMLElement/Element} el The context element
4547 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4548 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4549 * @return {HTMLElement/Roo.Element} The new node
4551 insertBefore : function(el, o, returnElement){
4552 return this.doInsert(el, o, returnElement, "beforeBegin");
4556 * Creates new Dom element(s) and inserts them after el
4557 * @param {String/HTMLElement/Element} el The context element
4558 * @param {Object} o The Dom object spec (and children)
4559 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4560 * @return {HTMLElement/Roo.Element} The new node
4562 insertAfter : function(el, o, returnElement){
4563 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4567 * Creates new Dom element(s) and inserts them as the first child of el
4568 * @param {String/HTMLElement/Element} el The context element
4569 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4570 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4571 * @return {HTMLElement/Roo.Element} The new node
4573 insertFirst : function(el, o, returnElement){
4574 return this.doInsert(el, o, returnElement, "afterBegin");
4578 doInsert : function(el, o, returnElement, pos, sibling){
4579 el = Roo.getDom(el);
4581 if(this.useDom || o.ns){
4582 newNode = createDom(o, null);
4583 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4585 var html = createHtml(o);
4586 newNode = this.insertHtml(pos, el, html);
4588 return returnElement ? Roo.get(newNode, true) : newNode;
4592 * Creates new Dom element(s) and appends them to el
4593 * @param {String/HTMLElement/Element} el The context element
4594 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4595 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4596 * @return {HTMLElement/Roo.Element} The new node
4598 append : function(el, o, returnElement){
4599 el = Roo.getDom(el);
4601 if(this.useDom || o.ns){
4602 newNode = createDom(o, null);
4603 el.appendChild(newNode);
4605 var html = createHtml(o);
4606 newNode = this.insertHtml("beforeEnd", el, html);
4608 return returnElement ? Roo.get(newNode, true) : newNode;
4612 * Creates new Dom element(s) and overwrites the contents of el with them
4613 * @param {String/HTMLElement/Element} el The context element
4614 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4615 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4616 * @return {HTMLElement/Roo.Element} The new node
4618 overwrite : function(el, o, returnElement){
4619 el = Roo.getDom(el);
4622 while (el.childNodes.length) {
4623 el.removeChild(el.firstChild);
4627 el.innerHTML = createHtml(o);
4630 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4634 * Creates a new Roo.DomHelper.Template from the Dom object spec
4635 * @param {Object} o The Dom object spec (and children)
4636 * @return {Roo.DomHelper.Template} The new template
4638 createTemplate : function(o){
4639 var html = createHtml(o);
4640 return new Roo.Template(html);
4646 * Ext JS Library 1.1.1
4647 * Copyright(c) 2006-2007, Ext JS, LLC.
4649 * Originally Released Under LGPL - original licence link has changed is not relivant.
4652 * <script type="text/javascript">
4656 * @class Roo.Template
4657 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4658 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4661 var t = new Roo.Template({
4662 html : '<div name="{id}">' +
4663 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4665 myformat: function (value, allValues) {
4666 return 'XX' + value;
4669 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4671 * For more information see this blog post with examples:
4672 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4673 - Create Elements using DOM, HTML fragments and Templates</a>.
4675 * @param {Object} cfg - Configuration object.
4677 Roo.Template = function(cfg){
4679 if(cfg instanceof Array){
4681 }else if(arguments.length > 1){
4682 cfg = Array.prototype.join.call(arguments, "");
4686 if (typeof(cfg) == 'object') {
4697 Roo.Template.prototype = {
4700 * @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..
4701 * it should be fixed so that template is observable...
4705 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4709 * Returns an HTML fragment of this template with the specified values applied.
4710 * @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'})
4711 * @return {String} The HTML fragment
4713 applyTemplate : function(values){
4717 return this.compiled(values);
4719 var useF = this.disableFormats !== true;
4720 var fm = Roo.util.Format, tpl = this;
4721 var fn = function(m, name, format, args){
4723 if(format.substr(0, 5) == "this."){
4724 return tpl.call(format.substr(5), values[name], values);
4727 // quoted values are required for strings in compiled templates,
4728 // but for non compiled we need to strip them
4729 // quoted reversed for jsmin
4730 var re = /^\s*['"](.*)["']\s*$/;
4731 args = args.split(',');
4732 for(var i = 0, len = args.length; i < len; i++){
4733 args[i] = args[i].replace(re, "$1");
4735 args = [values[name]].concat(args);
4737 args = [values[name]];
4739 return fm[format].apply(fm, args);
4742 return values[name] !== undefined ? values[name] : "";
4745 return this.html.replace(this.re, fn);
4763 this.loading = true;
4764 this.compiled = false;
4766 var cx = new Roo.data.Connection();
4770 success : function (response) {
4772 _t.html = response.responseText;
4776 failure : function(response) {
4777 Roo.log("Template failed to load from " + _t.url);
4784 * Sets the HTML used as the template and optionally compiles it.
4785 * @param {String} html
4786 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4787 * @return {Roo.Template} this
4789 set : function(html, compile){
4791 this.compiled = null;
4799 * True to disable format functions (defaults to false)
4802 disableFormats : false,
4805 * The regular expression used to match template variables
4809 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4812 * Compiles the template into an internal function, eliminating the RegEx overhead.
4813 * @return {Roo.Template} this
4815 compile : function(){
4816 var fm = Roo.util.Format;
4817 var useF = this.disableFormats !== true;
4818 var sep = Roo.isGecko ? "+" : ",";
4819 var fn = function(m, name, format, args){
4821 args = args ? ',' + args : "";
4822 if(format.substr(0, 5) != "this."){
4823 format = "fm." + format + '(';
4825 format = 'this.call("'+ format.substr(5) + '", ';
4829 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4831 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4834 // branched to use + in gecko and [].join() in others
4836 body = "this.compiled = function(values){ return '" +
4837 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4840 body = ["this.compiled = function(values){ return ['"];
4841 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4842 body.push("'].join('');};");
4843 body = body.join('');
4853 // private function used to call members
4854 call : function(fnName, value, allValues){
4855 return this[fnName](value, allValues);
4859 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4860 * @param {String/HTMLElement/Roo.Element} el The context element
4861 * @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'})
4862 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4863 * @return {HTMLElement/Roo.Element} The new node or Element
4865 insertFirst: function(el, values, returnElement){
4866 return this.doInsert('afterBegin', el, values, returnElement);
4870 * Applies the supplied values to the template and inserts the new node(s) before el.
4871 * @param {String/HTMLElement/Roo.Element} el The context element
4872 * @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'})
4873 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4874 * @return {HTMLElement/Roo.Element} The new node or Element
4876 insertBefore: function(el, values, returnElement){
4877 return this.doInsert('beforeBegin', el, values, returnElement);
4881 * Applies the supplied values to the template and inserts the new node(s) after el.
4882 * @param {String/HTMLElement/Roo.Element} el The context element
4883 * @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'})
4884 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4885 * @return {HTMLElement/Roo.Element} The new node or Element
4887 insertAfter : function(el, values, returnElement){
4888 return this.doInsert('afterEnd', el, values, returnElement);
4892 * Applies the supplied values to the template and appends the new node(s) to el.
4893 * @param {String/HTMLElement/Roo.Element} el The context element
4894 * @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'})
4895 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896 * @return {HTMLElement/Roo.Element} The new node or Element
4898 append : function(el, values, returnElement){
4899 return this.doInsert('beforeEnd', el, values, returnElement);
4902 doInsert : function(where, el, values, returnEl){
4903 el = Roo.getDom(el);
4904 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4905 return returnEl ? Roo.get(newNode, true) : newNode;
4909 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4910 * @param {String/HTMLElement/Roo.Element} el The context element
4911 * @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'})
4912 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4913 * @return {HTMLElement/Roo.Element} The new node or Element
4915 overwrite : function(el, values, returnElement){
4916 el = Roo.getDom(el);
4917 el.innerHTML = this.applyTemplate(values);
4918 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4922 * Alias for {@link #applyTemplate}
4925 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4928 Roo.DomHelper.Template = Roo.Template;
4931 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4932 * @param {String/HTMLElement} el A DOM element or its id
4933 * @returns {Roo.Template} The created template
4936 Roo.Template.from = function(el){
4937 el = Roo.getDom(el);
4938 return new Roo.Template(el.value || el.innerHTML);
4941 * Ext JS Library 1.1.1
4942 * Copyright(c) 2006-2007, Ext JS, LLC.
4944 * Originally Released Under LGPL - original licence link has changed is not relivant.
4947 * <script type="text/javascript">
4952 * This is code is also distributed under MIT license for use
4953 * with jQuery and prototype JavaScript libraries.
4956 * @class Roo.DomQuery
4957 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).
4959 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>
4962 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.
4964 <h4>Element Selectors:</h4>
4966 <li> <b>*</b> any element</li>
4967 <li> <b>E</b> an element with the tag E</li>
4968 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4969 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4970 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4971 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4973 <h4>Attribute Selectors:</h4>
4974 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4976 <li> <b>E[foo]</b> has an attribute "foo"</li>
4977 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4978 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4979 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4980 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4981 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4982 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4984 <h4>Pseudo Classes:</h4>
4986 <li> <b>E:first-child</b> E is the first child of its parent</li>
4987 <li> <b>E:last-child</b> E is the last child of its parent</li>
4988 <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>
4989 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4990 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4991 <li> <b>E:only-child</b> E is the only child of its parent</li>
4992 <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>
4993 <li> <b>E:first</b> the first E in the resultset</li>
4994 <li> <b>E:last</b> the last E in the resultset</li>
4995 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4996 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4997 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4998 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4999 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5000 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5001 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5002 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5003 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5005 <h4>CSS Value Selectors:</h4>
5007 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5008 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5009 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5010 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5011 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5012 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5016 Roo.DomQuery = function(){
5017 var cache = {}, simpleCache = {}, valueCache = {};
5018 var nonSpace = /\S/;
5019 var trimRe = /^\s+|\s+$/g;
5020 var tplRe = /\{(\d+)\}/g;
5021 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5022 var tagTokenRe = /^(#)?([\w-\*]+)/;
5023 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5025 function child(p, index){
5027 var n = p.firstChild;
5029 if(n.nodeType == 1){
5040 while((n = n.nextSibling) && n.nodeType != 1);
5045 while((n = n.previousSibling) && n.nodeType != 1);
5049 function children(d){
5050 var n = d.firstChild, ni = -1;
5052 var nx = n.nextSibling;
5053 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5063 function byClassName(c, a, v){
5067 var r = [], ri = -1, cn;
5068 for(var i = 0, ci; ci = c[i]; i++){
5069 if((' '+ci.className+' ').indexOf(v) != -1){
5076 function attrValue(n, attr){
5077 if(!n.tagName && typeof n.length != "undefined"){
5086 if(attr == "class" || attr == "className"){
5089 return n.getAttribute(attr) || n[attr];
5093 function getNodes(ns, mode, tagName){
5094 var result = [], ri = -1, cs;
5098 tagName = tagName || "*";
5099 if(typeof ns.getElementsByTagName != "undefined"){
5103 for(var i = 0, ni; ni = ns[i]; i++){
5104 cs = ni.getElementsByTagName(tagName);
5105 for(var j = 0, ci; ci = cs[j]; j++){
5109 }else if(mode == "/" || mode == ">"){
5110 var utag = tagName.toUpperCase();
5111 for(var i = 0, ni, cn; ni = ns[i]; i++){
5112 cn = ni.children || ni.childNodes;
5113 for(var j = 0, cj; cj = cn[j]; j++){
5114 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5119 }else if(mode == "+"){
5120 var utag = tagName.toUpperCase();
5121 for(var i = 0, n; n = ns[i]; i++){
5122 while((n = n.nextSibling) && n.nodeType != 1);
5123 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5127 }else if(mode == "~"){
5128 for(var i = 0, n; n = ns[i]; i++){
5129 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5138 function concat(a, b){
5142 for(var i = 0, l = b.length; i < l; i++){
5148 function byTag(cs, tagName){
5149 if(cs.tagName || cs == document){
5155 var r = [], ri = -1;
5156 tagName = tagName.toLowerCase();
5157 for(var i = 0, ci; ci = cs[i]; i++){
5158 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5165 function byId(cs, attr, id){
5166 if(cs.tagName || cs == document){
5172 var r = [], ri = -1;
5173 for(var i = 0,ci; ci = cs[i]; i++){
5174 if(ci && ci.id == id){
5182 function byAttribute(cs, attr, value, op, custom){
5183 var r = [], ri = -1, st = custom=="{";
5184 var f = Roo.DomQuery.operators[op];
5185 for(var i = 0, ci; ci = cs[i]; i++){
5188 a = Roo.DomQuery.getStyle(ci, attr);
5190 else if(attr == "class" || attr == "className"){
5192 }else if(attr == "for"){
5194 }else if(attr == "href"){
5195 a = ci.getAttribute("href", 2);
5197 a = ci.getAttribute(attr);
5199 if((f && f(a, value)) || (!f && a)){
5206 function byPseudo(cs, name, value){
5207 return Roo.DomQuery.pseudos[name](cs, value);
5210 // This is for IE MSXML which does not support expandos.
5211 // IE runs the same speed using setAttribute, however FF slows way down
5212 // and Safari completely fails so they need to continue to use expandos.
5213 var isIE = window.ActiveXObject ? true : false;
5215 // this eval is stop the compressor from
5216 // renaming the variable to something shorter
5218 /** eval:var:batch */
5223 function nodupIEXml(cs){
5225 cs[0].setAttribute("_nodup", d);
5227 for(var i = 1, len = cs.length; i < len; i++){
5229 if(!c.getAttribute("_nodup") != d){
5230 c.setAttribute("_nodup", d);
5234 for(var i = 0, len = cs.length; i < len; i++){
5235 cs[i].removeAttribute("_nodup");
5244 var len = cs.length, c, i, r = cs, cj, ri = -1;
5245 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5248 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5249 return nodupIEXml(cs);
5253 for(i = 1; c = cs[i]; i++){
5258 for(var j = 0; j < i; j++){
5261 for(j = i+1; cj = cs[j]; j++){
5273 function quickDiffIEXml(c1, c2){
5275 for(var i = 0, len = c1.length; i < len; i++){
5276 c1[i].setAttribute("_qdiff", d);
5279 for(var i = 0, len = c2.length; i < len; i++){
5280 if(c2[i].getAttribute("_qdiff") != d){
5281 r[r.length] = c2[i];
5284 for(var i = 0, len = c1.length; i < len; i++){
5285 c1[i].removeAttribute("_qdiff");
5290 function quickDiff(c1, c2){
5291 var len1 = c1.length;
5295 if(isIE && c1[0].selectSingleNode){
5296 return quickDiffIEXml(c1, c2);
5299 for(var i = 0; i < len1; i++){
5303 for(var i = 0, len = c2.length; i < len; i++){
5304 if(c2[i]._qdiff != d){
5305 r[r.length] = c2[i];
5311 function quickId(ns, mode, root, id){
5313 var d = root.ownerDocument || root;
5314 return d.getElementById(id);
5316 ns = getNodes(ns, mode, "*");
5317 return byId(ns, null, id);
5321 getStyle : function(el, name){
5322 return Roo.fly(el).getStyle(name);
5325 * Compiles a selector/xpath query into a reusable function. The returned function
5326 * takes one parameter "root" (optional), which is the context node from where the query should start.
5327 * @param {String} selector The selector/xpath query
5328 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5329 * @return {Function}
5331 compile : function(path, type){
5332 type = type || "select";
5334 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5335 var q = path, mode, lq;
5336 var tk = Roo.DomQuery.matchers;
5337 var tklen = tk.length;
5340 // accept leading mode switch
5341 var lmode = q.match(modeRe);
5342 if(lmode && lmode[1]){
5343 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5344 q = q.replace(lmode[1], "");
5346 // strip leading slashes
5347 while(path.substr(0, 1)=="/"){
5348 path = path.substr(1);
5351 while(q && lq != q){
5353 var tm = q.match(tagTokenRe);
5354 if(type == "select"){
5357 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5359 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5361 q = q.replace(tm[0], "");
5362 }else if(q.substr(0, 1) != '@'){
5363 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5368 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5370 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5372 q = q.replace(tm[0], "");
5375 while(!(mm = q.match(modeRe))){
5376 var matched = false;
5377 for(var j = 0; j < tklen; j++){
5379 var m = q.match(t.re);
5381 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5384 q = q.replace(m[0], "");
5389 // prevent infinite loop on bad selector
5391 throw 'Error parsing selector, parsing failed at "' + q + '"';
5395 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5396 q = q.replace(mm[1], "");
5399 fn[fn.length] = "return nodup(n);\n}";
5402 * list of variables that need from compression as they are used by eval.
5412 * eval:var:byClassName
5414 * eval:var:byAttribute
5415 * eval:var:attrValue
5423 * Selects a group of elements.
5424 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5425 * @param {Node} root (optional) The start of the query (defaults to document).
5428 select : function(path, root, type){
5429 if(!root || root == document){
5432 if(typeof root == "string"){
5433 root = document.getElementById(root);
5435 var paths = path.split(",");
5437 for(var i = 0, len = paths.length; i < len; i++){
5438 var p = paths[i].replace(trimRe, "");
5440 cache[p] = Roo.DomQuery.compile(p);
5442 throw p + " is not a valid selector";
5445 var result = cache[p](root);
5446 if(result && result != document){
5447 results = results.concat(result);
5450 if(paths.length > 1){
5451 return nodup(results);
5457 * Selects a single element.
5458 * @param {String} selector The selector/xpath query
5459 * @param {Node} root (optional) The start of the query (defaults to document).
5462 selectNode : function(path, root){
5463 return Roo.DomQuery.select(path, root)[0];
5467 * Selects the value of a node, optionally replacing null with the defaultValue.
5468 * @param {String} selector The selector/xpath query
5469 * @param {Node} root (optional) The start of the query (defaults to document).
5470 * @param {String} defaultValue
5472 selectValue : function(path, root, defaultValue){
5473 path = path.replace(trimRe, "");
5474 if(!valueCache[path]){
5475 valueCache[path] = Roo.DomQuery.compile(path, "select");
5477 var n = valueCache[path](root);
5478 n = n[0] ? n[0] : n;
5479 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5480 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5484 * Selects the value of a node, parsing integers and floats.
5485 * @param {String} selector The selector/xpath query
5486 * @param {Node} root (optional) The start of the query (defaults to document).
5487 * @param {Number} defaultValue
5490 selectNumber : function(path, root, defaultValue){
5491 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5492 return parseFloat(v);
5496 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5497 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5498 * @param {String} selector The simple selector to test
5501 is : function(el, ss){
5502 if(typeof el == "string"){
5503 el = document.getElementById(el);
5505 var isArray = (el instanceof Array);
5506 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5507 return isArray ? (result.length == el.length) : (result.length > 0);
5511 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5512 * @param {Array} el An array of elements to filter
5513 * @param {String} selector The simple selector to test
5514 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5515 * the selector instead of the ones that match
5518 filter : function(els, ss, nonMatches){
5519 ss = ss.replace(trimRe, "");
5520 if(!simpleCache[ss]){
5521 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5523 var result = simpleCache[ss](els);
5524 return nonMatches ? quickDiff(result, els) : result;
5528 * Collection of matching regular expressions and code snippets.
5532 select: 'n = byClassName(n, null, " {1} ");'
5534 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5535 select: 'n = byPseudo(n, "{1}", "{2}");'
5537 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5538 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5541 select: 'n = byId(n, null, "{1}");'
5544 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5549 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5550 * 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, > <.
5553 "=" : function(a, v){
5556 "!=" : function(a, v){
5559 "^=" : function(a, v){
5560 return a && a.substr(0, v.length) == v;
5562 "$=" : function(a, v){
5563 return a && a.substr(a.length-v.length) == v;
5565 "*=" : function(a, v){
5566 return a && a.indexOf(v) !== -1;
5568 "%=" : function(a, v){
5569 return (a % v) == 0;
5571 "|=" : function(a, v){
5572 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5574 "~=" : function(a, v){
5575 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5580 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5581 * and the argument (if any) supplied in the selector.
5584 "first-child" : function(c){
5585 var r = [], ri = -1, n;
5586 for(var i = 0, ci; ci = n = c[i]; i++){
5587 while((n = n.previousSibling) && n.nodeType != 1);
5595 "last-child" : function(c){
5596 var r = [], ri = -1, n;
5597 for(var i = 0, ci; ci = n = c[i]; i++){
5598 while((n = n.nextSibling) && n.nodeType != 1);
5606 "nth-child" : function(c, a) {
5607 var r = [], ri = -1;
5608 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5609 var f = (m[1] || 1) - 0, l = m[2] - 0;
5610 for(var i = 0, n; n = c[i]; i++){
5611 var pn = n.parentNode;
5612 if (batch != pn._batch) {
5614 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5615 if(cn.nodeType == 1){
5622 if (l == 0 || n.nodeIndex == l){
5625 } else if ((n.nodeIndex + l) % f == 0){
5633 "only-child" : function(c){
5634 var r = [], ri = -1;;
5635 for(var i = 0, ci; ci = c[i]; i++){
5636 if(!prev(ci) && !next(ci)){
5643 "empty" : function(c){
5644 var r = [], ri = -1;
5645 for(var i = 0, ci; ci = c[i]; i++){
5646 var cns = ci.childNodes, j = 0, cn, empty = true;
5649 if(cn.nodeType == 1 || cn.nodeType == 3){
5661 "contains" : function(c, v){
5662 var r = [], ri = -1;
5663 for(var i = 0, ci; ci = c[i]; i++){
5664 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5671 "nodeValue" : function(c, v){
5672 var r = [], ri = -1;
5673 for(var i = 0, ci; ci = c[i]; i++){
5674 if(ci.firstChild && ci.firstChild.nodeValue == v){
5681 "checked" : function(c){
5682 var r = [], ri = -1;
5683 for(var i = 0, ci; ci = c[i]; i++){
5684 if(ci.checked == true){
5691 "not" : function(c, ss){
5692 return Roo.DomQuery.filter(c, ss, true);
5695 "odd" : function(c){
5696 return this["nth-child"](c, "odd");
5699 "even" : function(c){
5700 return this["nth-child"](c, "even");
5703 "nth" : function(c, a){
5704 return c[a-1] || [];
5707 "first" : function(c){
5711 "last" : function(c){
5712 return c[c.length-1] || [];
5715 "has" : function(c, ss){
5716 var s = Roo.DomQuery.select;
5717 var r = [], ri = -1;
5718 for(var i = 0, ci; ci = c[i]; i++){
5719 if(s(ss, ci).length > 0){
5726 "next" : function(c, ss){
5727 var is = Roo.DomQuery.is;
5728 var r = [], ri = -1;
5729 for(var i = 0, ci; ci = c[i]; i++){
5738 "prev" : function(c, ss){
5739 var is = Roo.DomQuery.is;
5740 var r = [], ri = -1;
5741 for(var i = 0, ci; ci = c[i]; i++){
5754 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5755 * @param {String} path The selector/xpath query
5756 * @param {Node} root (optional) The start of the query (defaults to document).
5761 Roo.query = Roo.DomQuery.select;
5764 * Ext JS Library 1.1.1
5765 * Copyright(c) 2006-2007, Ext JS, LLC.
5767 * Originally Released Under LGPL - original licence link has changed is not relivant.
5770 * <script type="text/javascript">
5774 * @class Roo.util.Observable
5775 * Base class that provides a common interface for publishing events. Subclasses are expected to
5776 * to have a property "events" with all the events defined.<br>
5779 Employee = function(name){
5786 Roo.extend(Employee, Roo.util.Observable);
5788 * @param {Object} config properties to use (incuding events / listeners)
5791 Roo.util.Observable = function(cfg){
5794 this.addEvents(cfg.events || {});
5796 delete cfg.events; // make sure
5799 Roo.apply(this, cfg);
5802 this.on(this.listeners);
5803 delete this.listeners;
5806 Roo.util.Observable.prototype = {
5808 * @cfg {Object} listeners list of events and functions to call for this object,
5812 'click' : function(e) {
5822 * Fires the specified event with the passed parameters (minus the event name).
5823 * @param {String} eventName
5824 * @param {Object...} args Variable number of parameters are passed to handlers
5825 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5827 fireEvent : function(){
5828 var ce = this.events[arguments[0].toLowerCase()];
5829 if(typeof ce == "object"){
5830 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5837 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5840 * Appends an event handler to this component
5841 * @param {String} eventName The type of event to listen for
5842 * @param {Function} handler The method the event invokes
5843 * @param {Object} scope (optional) The scope in which to execute the handler
5844 * function. The handler function's "this" context.
5845 * @param {Object} options (optional) An object containing handler configuration
5846 * properties. This may contain any of the following properties:<ul>
5847 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5848 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5849 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5850 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5851 * by the specified number of milliseconds. If the event fires again within that time, the original
5852 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5855 * <b>Combining Options</b><br>
5856 * Using the options argument, it is possible to combine different types of listeners:<br>
5858 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5860 el.on('click', this.onClick, this, {
5867 * <b>Attaching multiple handlers in 1 call</b><br>
5868 * The method also allows for a single argument to be passed which is a config object containing properties
5869 * which specify multiple handlers.
5878 fn: this.onMouseOver,
5882 fn: this.onMouseOut,
5888 * Or a shorthand syntax which passes the same scope object to all handlers:
5891 'click': this.onClick,
5892 'mouseover': this.onMouseOver,
5893 'mouseout': this.onMouseOut,
5898 addListener : function(eventName, fn, scope, o){
5899 if(typeof eventName == "object"){
5902 if(this.filterOptRe.test(e)){
5905 if(typeof o[e] == "function"){
5907 this.addListener(e, o[e], o.scope, o);
5909 // individual options
5910 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5915 o = (!o || typeof o == "boolean") ? {} : o;
5916 eventName = eventName.toLowerCase();
5917 var ce = this.events[eventName] || true;
5918 if(typeof ce == "boolean"){
5919 ce = new Roo.util.Event(this, eventName);
5920 this.events[eventName] = ce;
5922 ce.addListener(fn, scope, o);
5926 * Removes a listener
5927 * @param {String} eventName The type of event to listen for
5928 * @param {Function} handler The handler to remove
5929 * @param {Object} scope (optional) The scope (this object) for the handler
5931 removeListener : function(eventName, fn, scope){
5932 var ce = this.events[eventName.toLowerCase()];
5933 if(typeof ce == "object"){
5934 ce.removeListener(fn, scope);
5939 * Removes all listeners for this object
5941 purgeListeners : function(){
5942 for(var evt in this.events){
5943 if(typeof this.events[evt] == "object"){
5944 this.events[evt].clearListeners();
5949 relayEvents : function(o, events){
5950 var createHandler = function(ename){
5952 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5955 for(var i = 0, len = events.length; i < len; i++){
5956 var ename = events[i];
5957 if(!this.events[ename]){ this.events[ename] = true; };
5958 o.on(ename, createHandler(ename), this);
5963 * Used to define events on this Observable
5964 * @param {Object} object The object with the events defined
5966 addEvents : function(o){
5970 Roo.applyIf(this.events, o);
5974 * Checks to see if this object has any listeners for a specified event
5975 * @param {String} eventName The name of the event to check for
5976 * @return {Boolean} True if the event is being listened for, else false
5978 hasListener : function(eventName){
5979 var e = this.events[eventName];
5980 return typeof e == "object" && e.listeners.length > 0;
5984 * Appends an event handler to this element (shorthand for addListener)
5985 * @param {String} eventName The type of event to listen for
5986 * @param {Function} handler The method the event invokes
5987 * @param {Object} scope (optional) The scope in which to execute the handler
5988 * function. The handler function's "this" context.
5989 * @param {Object} options (optional)
5992 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5994 * Removes a listener (shorthand for removeListener)
5995 * @param {String} eventName The type of event to listen for
5996 * @param {Function} handler The handler to remove
5997 * @param {Object} scope (optional) The scope (this object) for the handler
6000 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6003 * Starts capture on the specified Observable. All events will be passed
6004 * to the supplied function with the event name + standard signature of the event
6005 * <b>before</b> the event is fired. If the supplied function returns false,
6006 * the event will not fire.
6007 * @param {Observable} o The Observable to capture
6008 * @param {Function} fn The function to call
6009 * @param {Object} scope (optional) The scope (this object) for the fn
6012 Roo.util.Observable.capture = function(o, fn, scope){
6013 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6017 * Removes <b>all</b> added captures from the Observable.
6018 * @param {Observable} o The Observable to release
6021 Roo.util.Observable.releaseCapture = function(o){
6022 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6027 var createBuffered = function(h, o, scope){
6028 var task = new Roo.util.DelayedTask();
6030 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6034 var createSingle = function(h, e, fn, scope){
6036 e.removeListener(fn, scope);
6037 return h.apply(scope, arguments);
6041 var createDelayed = function(h, o, scope){
6043 var args = Array.prototype.slice.call(arguments, 0);
6044 setTimeout(function(){
6045 h.apply(scope, args);
6050 Roo.util.Event = function(obj, name){
6053 this.listeners = [];
6056 Roo.util.Event.prototype = {
6057 addListener : function(fn, scope, options){
6058 var o = options || {};
6059 scope = scope || this.obj;
6060 if(!this.isListening(fn, scope)){
6061 var l = {fn: fn, scope: scope, options: o};
6064 h = createDelayed(h, o, scope);
6067 h = createSingle(h, this, fn, scope);
6070 h = createBuffered(h, o, scope);
6073 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6074 this.listeners.push(l);
6076 this.listeners = this.listeners.slice(0);
6077 this.listeners.push(l);
6082 findListener : function(fn, scope){
6083 scope = scope || this.obj;
6084 var ls = this.listeners;
6085 for(var i = 0, len = ls.length; i < len; i++){
6087 if(l.fn == fn && l.scope == scope){
6094 isListening : function(fn, scope){
6095 return this.findListener(fn, scope) != -1;
6098 removeListener : function(fn, scope){
6100 if((index = this.findListener(fn, scope)) != -1){
6102 this.listeners.splice(index, 1);
6104 this.listeners = this.listeners.slice(0);
6105 this.listeners.splice(index, 1);
6112 clearListeners : function(){
6113 this.listeners = [];
6117 var ls = this.listeners, scope, len = ls.length;
6120 var args = Array.prototype.slice.call(arguments, 0);
6121 for(var i = 0; i < len; i++){
6123 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6124 this.firing = false;
6128 this.firing = false;
6135 * Ext JS Library 1.1.1
6136 * Copyright(c) 2006-2007, Ext JS, LLC.
6138 * Originally Released Under LGPL - original licence link has changed is not relivant.
6141 * <script type="text/javascript">
6145 * @class Roo.EventManager
6146 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6147 * several useful events directly.
6148 * See {@link Roo.EventObject} for more details on normalized event objects.
6151 Roo.EventManager = function(){
6152 var docReadyEvent, docReadyProcId, docReadyState = false;
6153 var resizeEvent, resizeTask, textEvent, textSize;
6154 var E = Roo.lib.Event;
6155 var D = Roo.lib.Dom;
6158 var fireDocReady = function(){
6160 docReadyState = true;
6163 clearInterval(docReadyProcId);
6165 if(Roo.isGecko || Roo.isOpera) {
6166 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6169 var defer = document.getElementById("ie-deferred-loader");
6171 defer.onreadystatechange = null;
6172 defer.parentNode.removeChild(defer);
6176 docReadyEvent.fire();
6177 docReadyEvent.clearListeners();
6182 var initDocReady = function(){
6183 docReadyEvent = new Roo.util.Event();
6184 if(Roo.isGecko || Roo.isOpera) {
6185 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6187 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6188 var defer = document.getElementById("ie-deferred-loader");
6189 defer.onreadystatechange = function(){
6190 if(this.readyState == "complete"){
6194 }else if(Roo.isSafari){
6195 docReadyProcId = setInterval(function(){
6196 var rs = document.readyState;
6197 if(rs == "complete") {
6202 // no matter what, make sure it fires on load
6203 E.on(window, "load", fireDocReady);
6206 var createBuffered = function(h, o){
6207 var task = new Roo.util.DelayedTask(h);
6209 // create new event object impl so new events don't wipe out properties
6210 e = new Roo.EventObjectImpl(e);
6211 task.delay(o.buffer, h, null, [e]);
6215 var createSingle = function(h, el, ename, fn){
6217 Roo.EventManager.removeListener(el, ename, fn);
6222 var createDelayed = function(h, o){
6224 // create new event object impl so new events don't wipe out properties
6225 e = new Roo.EventObjectImpl(e);
6226 setTimeout(function(){
6232 var listen = function(element, ename, opt, fn, scope){
6233 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6234 fn = fn || o.fn; scope = scope || o.scope;
6235 var el = Roo.getDom(element);
6237 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6239 var h = function(e){
6240 e = Roo.EventObject.setEvent(e);
6243 t = e.getTarget(o.delegate, el);
6250 if(o.stopEvent === true){
6253 if(o.preventDefault === true){
6256 if(o.stopPropagation === true){
6257 e.stopPropagation();
6260 if(o.normalized === false){
6264 fn.call(scope || el, e, t, o);
6267 h = createDelayed(h, o);
6270 h = createSingle(h, el, ename, fn);
6273 h = createBuffered(h, o);
6275 fn._handlers = fn._handlers || [];
6276 fn._handlers.push([Roo.id(el), ename, h]);
6279 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6280 el.addEventListener("DOMMouseScroll", h, false);
6281 E.on(window, 'unload', function(){
6282 el.removeEventListener("DOMMouseScroll", h, false);
6285 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6286 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6291 var stopListening = function(el, ename, fn){
6292 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6294 for(var i = 0, len = hds.length; i < len; i++){
6296 if(h[0] == id && h[1] == ename){
6303 E.un(el, ename, hd);
6304 el = Roo.getDom(el);
6305 if(ename == "mousewheel" && el.addEventListener){
6306 el.removeEventListener("DOMMouseScroll", hd, false);
6308 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6309 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6313 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6320 * @scope Roo.EventManager
6325 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6326 * object with a Roo.EventObject
6327 * @param {Function} fn The method the event invokes
6328 * @param {Object} scope An object that becomes the scope of the handler
6329 * @param {boolean} override If true, the obj passed in becomes
6330 * the execution scope of the listener
6331 * @return {Function} The wrapped function
6334 wrap : function(fn, scope, override){
6336 Roo.EventObject.setEvent(e);
6337 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6342 * Appends an event handler to an element (shorthand for addListener)
6343 * @param {String/HTMLElement} element The html element or id to assign the
6344 * @param {String} eventName The type of event to listen for
6345 * @param {Function} handler The method the event invokes
6346 * @param {Object} scope (optional) The scope in which to execute the handler
6347 * function. The handler function's "this" context.
6348 * @param {Object} options (optional) An object containing handler configuration
6349 * properties. This may contain any of the following properties:<ul>
6350 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6351 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6352 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6353 * <li>preventDefault {Boolean} True to prevent the default action</li>
6354 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6355 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6356 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6357 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6358 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6359 * by the specified number of milliseconds. If the event fires again within that time, the original
6360 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6363 * <b>Combining Options</b><br>
6364 * Using the options argument, it is possible to combine different types of listeners:<br>
6366 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6368 el.on('click', this.onClick, this, {
6375 * <b>Attaching multiple handlers in 1 call</b><br>
6376 * The method also allows for a single argument to be passed which is a config object containing properties
6377 * which specify multiple handlers.
6387 fn: this.onMouseOver
6396 * Or a shorthand syntax:<br>
6399 'click' : this.onClick,
6400 'mouseover' : this.onMouseOver,
6401 'mouseout' : this.onMouseOut
6405 addListener : function(element, eventName, fn, scope, options){
6406 if(typeof eventName == "object"){
6412 if(typeof o[e] == "function"){
6414 listen(element, e, o, o[e], o.scope);
6416 // individual options
6417 listen(element, e, o[e]);
6422 return listen(element, eventName, options, fn, scope);
6426 * Removes an event handler
6428 * @param {String/HTMLElement} element The id or html element to remove the
6430 * @param {String} eventName The type of event
6431 * @param {Function} fn
6432 * @return {Boolean} True if a listener was actually removed
6434 removeListener : function(element, eventName, fn){
6435 return stopListening(element, eventName, fn);
6439 * Fires when the document is ready (before onload and before images are loaded). Can be
6440 * accessed shorthanded Roo.onReady().
6441 * @param {Function} fn The method the event invokes
6442 * @param {Object} scope An object that becomes the scope of the handler
6443 * @param {boolean} options
6445 onDocumentReady : function(fn, scope, options){
6446 if(docReadyState){ // if it already fired
6447 docReadyEvent.addListener(fn, scope, options);
6448 docReadyEvent.fire();
6449 docReadyEvent.clearListeners();
6455 docReadyEvent.addListener(fn, scope, options);
6459 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6460 * @param {Function} fn The method the event invokes
6461 * @param {Object} scope An object that becomes the scope of the handler
6462 * @param {boolean} options
6464 onWindowResize : function(fn, scope, options){
6466 resizeEvent = new Roo.util.Event();
6467 resizeTask = new Roo.util.DelayedTask(function(){
6468 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6470 E.on(window, "resize", function(){
6472 resizeTask.delay(50);
6474 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6478 resizeEvent.addListener(fn, scope, options);
6482 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6483 * @param {Function} fn The method the event invokes
6484 * @param {Object} scope An object that becomes the scope of the handler
6485 * @param {boolean} options
6487 onTextResize : function(fn, scope, options){
6489 textEvent = new Roo.util.Event();
6490 var textEl = new Roo.Element(document.createElement('div'));
6491 textEl.dom.className = 'x-text-resize';
6492 textEl.dom.innerHTML = 'X';
6493 textEl.appendTo(document.body);
6494 textSize = textEl.dom.offsetHeight;
6495 setInterval(function(){
6496 if(textEl.dom.offsetHeight != textSize){
6497 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6499 }, this.textResizeInterval);
6501 textEvent.addListener(fn, scope, options);
6505 * Removes the passed window resize listener.
6506 * @param {Function} fn The method the event invokes
6507 * @param {Object} scope The scope of handler
6509 removeResizeListener : function(fn, scope){
6511 resizeEvent.removeListener(fn, scope);
6516 fireResize : function(){
6518 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6522 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6526 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6528 textResizeInterval : 50
6533 * @scopeAlias pub=Roo.EventManager
6537 * Appends an event handler to an element (shorthand for addListener)
6538 * @param {String/HTMLElement} element The html element or id to assign the
6539 * @param {String} eventName The type of event to listen for
6540 * @param {Function} handler The method the event invokes
6541 * @param {Object} scope (optional) The scope in which to execute the handler
6542 * function. The handler function's "this" context.
6543 * @param {Object} options (optional) An object containing handler configuration
6544 * properties. This may contain any of the following properties:<ul>
6545 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6546 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6547 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6548 * <li>preventDefault {Boolean} True to prevent the default action</li>
6549 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6550 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6551 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6552 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6553 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6554 * by the specified number of milliseconds. If the event fires again within that time, the original
6555 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6558 * <b>Combining Options</b><br>
6559 * Using the options argument, it is possible to combine different types of listeners:<br>
6561 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6563 el.on('click', this.onClick, this, {
6570 * <b>Attaching multiple handlers in 1 call</b><br>
6571 * The method also allows for a single argument to be passed which is a config object containing properties
6572 * which specify multiple handlers.
6582 fn: this.onMouseOver
6591 * Or a shorthand syntax:<br>
6594 'click' : this.onClick,
6595 'mouseover' : this.onMouseOver,
6596 'mouseout' : this.onMouseOut
6600 pub.on = pub.addListener;
6601 pub.un = pub.removeListener;
6603 pub.stoppedMouseDownEvent = new Roo.util.Event();
6607 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6608 * @param {Function} fn The method the event invokes
6609 * @param {Object} scope An object that becomes the scope of the handler
6610 * @param {boolean} override If true, the obj passed in becomes
6611 * the execution scope of the listener
6615 Roo.onReady = Roo.EventManager.onDocumentReady;
6617 Roo.onReady(function(){
6618 var bd = Roo.get(document.body);
6623 : Roo.isGecko ? "roo-gecko"
6624 : Roo.isOpera ? "roo-opera"
6625 : Roo.isSafari ? "roo-safari" : ""];
6628 cls.push("roo-mac");
6631 cls.push("roo-linux");
6633 if(Roo.isBorderBox){
6634 cls.push('roo-border-box');
6636 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6637 var p = bd.dom.parentNode;
6639 p.className += ' roo-strict';
6642 bd.addClass(cls.join(' '));
6646 * @class Roo.EventObject
6647 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6648 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6651 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6653 var target = e.getTarget();
6656 var myDiv = Roo.get("myDiv");
6657 myDiv.on("click", handleClick);
6659 Roo.EventManager.on("myDiv", 'click', handleClick);
6660 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6664 Roo.EventObject = function(){
6666 var E = Roo.lib.Event;
6668 // safari keypress events for special keys return bad keycodes
6671 63235 : 39, // right
6674 63276 : 33, // page up
6675 63277 : 34, // page down
6676 63272 : 46, // delete
6681 // normalize button clicks
6682 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6683 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6685 Roo.EventObjectImpl = function(e){
6687 this.setEvent(e.browserEvent || e);
6690 Roo.EventObjectImpl.prototype = {
6692 * Used to fix doc tools.
6693 * @scope Roo.EventObject.prototype
6699 /** The normal browser event */
6700 browserEvent : null,
6701 /** The button pressed in a mouse event */
6703 /** True if the shift key was down during the event */
6705 /** True if the control key was down during the event */
6707 /** True if the alt key was down during the event */
6766 setEvent : function(e){
6767 if(e == this || (e && e.browserEvent)){ // already wrapped
6770 this.browserEvent = e;
6772 // normalize buttons
6773 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6774 if(e.type == 'click' && this.button == -1){
6778 this.shiftKey = e.shiftKey;
6779 // mac metaKey behaves like ctrlKey
6780 this.ctrlKey = e.ctrlKey || e.metaKey;
6781 this.altKey = e.altKey;
6782 // in getKey these will be normalized for the mac
6783 this.keyCode = e.keyCode;
6784 // keyup warnings on firefox.
6785 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6786 // cache the target for the delayed and or buffered events
6787 this.target = E.getTarget(e);
6789 this.xy = E.getXY(e);
6792 this.shiftKey = false;
6793 this.ctrlKey = false;
6794 this.altKey = false;
6804 * Stop the event (preventDefault and stopPropagation)
6806 stopEvent : function(){
6807 if(this.browserEvent){
6808 if(this.browserEvent.type == 'mousedown'){
6809 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6811 E.stopEvent(this.browserEvent);
6816 * Prevents the browsers default handling of the event.
6818 preventDefault : function(){
6819 if(this.browserEvent){
6820 E.preventDefault(this.browserEvent);
6825 isNavKeyPress : function(){
6826 var k = this.keyCode;
6827 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6828 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6831 isSpecialKey : function(){
6832 var k = this.keyCode;
6833 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6834 (k == 16) || (k == 17) ||
6835 (k >= 18 && k <= 20) ||
6836 (k >= 33 && k <= 35) ||
6837 (k >= 36 && k <= 39) ||
6838 (k >= 44 && k <= 45);
6841 * Cancels bubbling of the event.
6843 stopPropagation : function(){
6844 if(this.browserEvent){
6845 if(this.type == 'mousedown'){
6846 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6848 E.stopPropagation(this.browserEvent);
6853 * Gets the key code for the event.
6856 getCharCode : function(){
6857 return this.charCode || this.keyCode;
6861 * Returns a normalized keyCode for the event.
6862 * @return {Number} The key code
6864 getKey : function(){
6865 var k = this.keyCode || this.charCode;
6866 return Roo.isSafari ? (safariKeys[k] || k) : k;
6870 * Gets the x coordinate of the event.
6873 getPageX : function(){
6878 * Gets the y coordinate of the event.
6881 getPageY : function(){
6886 * Gets the time of the event.
6889 getTime : function(){
6890 if(this.browserEvent){
6891 return E.getTime(this.browserEvent);
6897 * Gets the page coordinates of the event.
6898 * @return {Array} The xy values like [x, y]
6905 * Gets the target for the event.
6906 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6907 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6908 search as a number or element (defaults to 10 || document.body)
6909 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6910 * @return {HTMLelement}
6912 getTarget : function(selector, maxDepth, returnEl){
6913 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6916 * Gets the related target.
6917 * @return {HTMLElement}
6919 getRelatedTarget : function(){
6920 if(this.browserEvent){
6921 return E.getRelatedTarget(this.browserEvent);
6927 * Normalizes mouse wheel delta across browsers
6928 * @return {Number} The delta
6930 getWheelDelta : function(){
6931 var e = this.browserEvent;
6933 if(e.wheelDelta){ /* IE/Opera. */
6934 delta = e.wheelDelta/120;
6935 }else if(e.detail){ /* Mozilla case. */
6936 delta = -e.detail/3;
6942 * Returns true if the control, meta, shift or alt key was pressed during this event.
6945 hasModifier : function(){
6946 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6950 * Returns true if the target of this event equals el or is a child of el
6951 * @param {String/HTMLElement/Element} el
6952 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6955 within : function(el, related){
6956 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6957 return t && Roo.fly(el).contains(t);
6960 getPoint : function(){
6961 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6965 return new Roo.EventObjectImpl();
6970 * Ext JS Library 1.1.1
6971 * Copyright(c) 2006-2007, Ext JS, LLC.
6973 * Originally Released Under LGPL - original licence link has changed is not relivant.
6976 * <script type="text/javascript">
6980 // was in Composite Element!??!?!
6983 var D = Roo.lib.Dom;
6984 var E = Roo.lib.Event;
6985 var A = Roo.lib.Anim;
6987 // local style camelizing for speed
6989 var camelRe = /(-[a-z])/gi;
6990 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6991 var view = document.defaultView;
6994 * @class Roo.Element
6995 * Represents an Element in the DOM.<br><br>
6998 var el = Roo.get("my-div");
7001 var el = getEl("my-div");
7003 // or with a DOM element
7004 var el = Roo.get(myDivElement);
7006 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7007 * each call instead of constructing a new one.<br><br>
7008 * <b>Animations</b><br />
7009 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7010 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7012 Option Default Description
7013 --------- -------- ---------------------------------------------
7014 duration .35 The duration of the animation in seconds
7015 easing easeOut The YUI easing method
7016 callback none A function to execute when the anim completes
7017 scope this The scope (this) of the callback function
7019 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7020 * manipulate the animation. Here's an example:
7022 var el = Roo.get("my-div");
7027 // default animation
7028 el.setWidth(100, true);
7030 // animation with some options set
7037 // using the "anim" property to get the Anim object
7043 el.setWidth(100, opt);
7045 if(opt.anim.isAnimated()){
7049 * <b> Composite (Collections of) Elements</b><br />
7050 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7051 * @constructor Create a new Element directly.
7052 * @param {String/HTMLElement} element
7053 * @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).
7055 Roo.Element = function(element, forceNew){
7056 var dom = typeof element == "string" ?
7057 document.getElementById(element) : element;
7058 if(!dom){ // invalid id/element
7062 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7063 return Roo.Element.cache[id];
7073 * The DOM element ID
7076 this.id = id || Roo.id(dom);
7079 var El = Roo.Element;
7083 * The element's default display mode (defaults to "")
7086 originalDisplay : "",
7090 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7095 * Sets the element's visibility mode. When setVisible() is called it
7096 * will use this to determine whether to set the visibility or the display property.
7097 * @param visMode Element.VISIBILITY or Element.DISPLAY
7098 * @return {Roo.Element} this
7100 setVisibilityMode : function(visMode){
7101 this.visibilityMode = visMode;
7105 * Convenience method for setVisibilityMode(Element.DISPLAY)
7106 * @param {String} display (optional) What to set display to when visible
7107 * @return {Roo.Element} this
7109 enableDisplayMode : function(display){
7110 this.setVisibilityMode(El.DISPLAY);
7111 if(typeof display != "undefined") this.originalDisplay = display;
7116 * 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)
7117 * @param {String} selector The simple selector to test
7118 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7119 search as a number or element (defaults to 10 || document.body)
7120 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7121 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7123 findParent : function(simpleSelector, maxDepth, returnEl){
7124 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7125 maxDepth = maxDepth || 50;
7126 if(typeof maxDepth != "number"){
7127 stopEl = Roo.getDom(maxDepth);
7130 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7131 if(dq.is(p, simpleSelector)){
7132 return returnEl ? Roo.get(p) : p;
7142 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7143 * @param {String} selector The simple selector to test
7144 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7145 search as a number or element (defaults to 10 || document.body)
7146 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7147 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7149 findParentNode : function(simpleSelector, maxDepth, returnEl){
7150 var p = Roo.fly(this.dom.parentNode, '_internal');
7151 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7155 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7156 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7157 * @param {String} selector The simple selector to test
7158 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7159 search as a number or element (defaults to 10 || document.body)
7160 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7162 up : function(simpleSelector, maxDepth){
7163 return this.findParentNode(simpleSelector, maxDepth, true);
7169 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7170 * @param {String} selector The simple selector to test
7171 * @return {Boolean} True if this element matches the selector, else false
7173 is : function(simpleSelector){
7174 return Roo.DomQuery.is(this.dom, simpleSelector);
7178 * Perform animation on this element.
7179 * @param {Object} args The YUI animation control args
7180 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7181 * @param {Function} onComplete (optional) Function to call when animation completes
7182 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7183 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7184 * @return {Roo.Element} this
7186 animate : function(args, duration, onComplete, easing, animType){
7187 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7192 * @private Internal animation call
7194 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7195 animType = animType || 'run';
7197 var anim = Roo.lib.Anim[animType](
7199 (opt.duration || defaultDur) || .35,
7200 (opt.easing || defaultEase) || 'easeOut',
7202 Roo.callback(cb, this);
7203 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7211 // private legacy anim prep
7212 preanim : function(a, i){
7213 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7217 * Removes worthless text nodes
7218 * @param {Boolean} forceReclean (optional) By default the element
7219 * keeps track if it has been cleaned already so
7220 * you can call this over and over. However, if you update the element and
7221 * need to force a reclean, you can pass true.
7223 clean : function(forceReclean){
7224 if(this.isCleaned && forceReclean !== true){
7228 var d = this.dom, n = d.firstChild, ni = -1;
7230 var nx = n.nextSibling;
7231 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7238 this.isCleaned = true;
7243 calcOffsetsTo : function(el){
7246 var restorePos = false;
7247 if(el.getStyle('position') == 'static'){
7248 el.position('relative');
7253 while(op && op != d && op.tagName != 'HTML'){
7256 op = op.offsetParent;
7259 el.position('static');
7265 * Scrolls this element into view within the passed container.
7266 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7267 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7268 * @return {Roo.Element} this
7270 scrollIntoView : function(container, hscroll){
7271 var c = Roo.getDom(container) || document.body;
7274 var o = this.calcOffsetsTo(c),
7277 b = t+el.offsetHeight,
7278 r = l+el.offsetWidth;
7280 var ch = c.clientHeight;
7281 var ct = parseInt(c.scrollTop, 10);
7282 var cl = parseInt(c.scrollLeft, 10);
7284 var cr = cl + c.clientWidth;
7292 if(hscroll !== false){
7296 c.scrollLeft = r-c.clientWidth;
7303 scrollChildIntoView : function(child, hscroll){
7304 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7308 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7309 * the new height may not be available immediately.
7310 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7311 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7312 * @param {Function} onComplete (optional) Function to call when animation completes
7313 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7314 * @return {Roo.Element} this
7316 autoHeight : function(animate, duration, onComplete, easing){
7317 var oldHeight = this.getHeight();
7319 this.setHeight(1); // force clipping
7320 setTimeout(function(){
7321 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7323 this.setHeight(height);
7325 if(typeof onComplete == "function"){
7329 this.setHeight(oldHeight); // restore original height
7330 this.setHeight(height, animate, duration, function(){
7332 if(typeof onComplete == "function") onComplete();
7333 }.createDelegate(this), easing);
7335 }.createDelegate(this), 0);
7340 * Returns true if this element is an ancestor of the passed element
7341 * @param {HTMLElement/String} el The element to check
7342 * @return {Boolean} True if this element is an ancestor of el, else false
7344 contains : function(el){
7345 if(!el){return false;}
7346 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7350 * Checks whether the element is currently visible using both visibility and display properties.
7351 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7352 * @return {Boolean} True if the element is currently visible, else false
7354 isVisible : function(deep) {
7355 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7356 if(deep !== true || !vis){
7359 var p = this.dom.parentNode;
7360 while(p && p.tagName.toLowerCase() != "body"){
7361 if(!Roo.fly(p, '_isVisible').isVisible()){
7370 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7371 * @param {String} selector The CSS selector
7372 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7373 * @return {CompositeElement/CompositeElementLite} The composite element
7375 select : function(selector, unique){
7376 return El.select(selector, unique, this.dom);
7380 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7381 * @param {String} selector The CSS selector
7382 * @return {Array} An array of the matched nodes
7384 query : function(selector, unique){
7385 return Roo.DomQuery.select(selector, this.dom);
7389 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7390 * @param {String} selector The CSS selector
7391 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7392 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7394 child : function(selector, returnDom){
7395 var n = Roo.DomQuery.selectNode(selector, this.dom);
7396 return returnDom ? n : Roo.get(n);
7400 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7401 * @param {String} selector The CSS selector
7402 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7403 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7405 down : function(selector, returnDom){
7406 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7407 return returnDom ? n : Roo.get(n);
7411 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7412 * @param {String} group The group the DD object is member of
7413 * @param {Object} config The DD config object
7414 * @param {Object} overrides An object containing methods to override/implement on the DD object
7415 * @return {Roo.dd.DD} The DD object
7417 initDD : function(group, config, overrides){
7418 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7419 return Roo.apply(dd, overrides);
7423 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7424 * @param {String} group The group the DDProxy object is member of
7425 * @param {Object} config The DDProxy config object
7426 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7427 * @return {Roo.dd.DDProxy} The DDProxy object
7429 initDDProxy : function(group, config, overrides){
7430 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7431 return Roo.apply(dd, overrides);
7435 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7436 * @param {String} group The group the DDTarget object is member of
7437 * @param {Object} config The DDTarget config object
7438 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7439 * @return {Roo.dd.DDTarget} The DDTarget object
7441 initDDTarget : function(group, config, overrides){
7442 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7443 return Roo.apply(dd, overrides);
7447 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7448 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7449 * @param {Boolean} visible Whether the element is visible
7450 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7451 * @return {Roo.Element} this
7453 setVisible : function(visible, animate){
7455 if(this.visibilityMode == El.DISPLAY){
7456 this.setDisplayed(visible);
7459 this.dom.style.visibility = visible ? "visible" : "hidden";
7462 // closure for composites
7464 var visMode = this.visibilityMode;
7466 this.setOpacity(.01);
7467 this.setVisible(true);
7469 this.anim({opacity: { to: (visible?1:0) }},
7470 this.preanim(arguments, 1),
7471 null, .35, 'easeIn', function(){
7473 if(visMode == El.DISPLAY){
7474 dom.style.display = "none";
7476 dom.style.visibility = "hidden";
7478 Roo.get(dom).setOpacity(1);
7486 * Returns true if display is not "none"
7489 isDisplayed : function() {
7490 return this.getStyle("display") != "none";
7494 * Toggles the element's visibility or display, depending on visibility mode.
7495 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7496 * @return {Roo.Element} this
7498 toggle : function(animate){
7499 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7504 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7505 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7506 * @return {Roo.Element} this
7508 setDisplayed : function(value) {
7509 if(typeof value == "boolean"){
7510 value = value ? this.originalDisplay : "none";
7512 this.setStyle("display", value);
7517 * Tries to focus the element. Any exceptions are caught and ignored.
7518 * @return {Roo.Element} this
7520 focus : function() {
7528 * Tries to blur the element. Any exceptions are caught and ignored.
7529 * @return {Roo.Element} this
7539 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7540 * @param {String/Array} className The CSS class to add, or an array of classes
7541 * @return {Roo.Element} this
7543 addClass : function(className){
7544 if(className instanceof Array){
7545 for(var i = 0, len = className.length; i < len; i++) {
7546 this.addClass(className[i]);
7549 if(className && !this.hasClass(className)){
7550 this.dom.className = this.dom.className + " " + className;
7557 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7558 * @param {String/Array} className The CSS class to add, or an array of classes
7559 * @return {Roo.Element} this
7561 radioClass : function(className){
7562 var siblings = this.dom.parentNode.childNodes;
7563 for(var i = 0; i < siblings.length; i++) {
7564 var s = siblings[i];
7565 if(s.nodeType == 1){
7566 Roo.get(s).removeClass(className);
7569 this.addClass(className);
7574 * Removes one or more CSS classes from the element.
7575 * @param {String/Array} className The CSS class to remove, or an array of classes
7576 * @return {Roo.Element} this
7578 removeClass : function(className){
7579 if(!className || !this.dom.className){
7582 if(className instanceof Array){
7583 for(var i = 0, len = className.length; i < len; i++) {
7584 this.removeClass(className[i]);
7587 if(this.hasClass(className)){
7588 var re = this.classReCache[className];
7590 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7591 this.classReCache[className] = re;
7593 this.dom.className =
7594 this.dom.className.replace(re, " ");
7604 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7605 * @param {String} className The CSS class to toggle
7606 * @return {Roo.Element} this
7608 toggleClass : function(className){
7609 if(this.hasClass(className)){
7610 this.removeClass(className);
7612 this.addClass(className);
7618 * Checks if the specified CSS class exists on this element's DOM node.
7619 * @param {String} className The CSS class to check for
7620 * @return {Boolean} True if the class exists, else false
7622 hasClass : function(className){
7623 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7627 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7628 * @param {String} oldClassName The CSS class to replace
7629 * @param {String} newClassName The replacement CSS class
7630 * @return {Roo.Element} this
7632 replaceClass : function(oldClassName, newClassName){
7633 this.removeClass(oldClassName);
7634 this.addClass(newClassName);
7639 * Returns an object with properties matching the styles requested.
7640 * For example, el.getStyles('color', 'font-size', 'width') might return
7641 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7642 * @param {String} style1 A style name
7643 * @param {String} style2 A style name
7644 * @param {String} etc.
7645 * @return {Object} The style object
7647 getStyles : function(){
7648 var a = arguments, len = a.length, r = {};
7649 for(var i = 0; i < len; i++){
7650 r[a[i]] = this.getStyle(a[i]);
7656 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7657 * @param {String} property The style property whose value is returned.
7658 * @return {String} The current value of the style property for this element.
7660 getStyle : function(){
7661 return view && view.getComputedStyle ?
7663 var el = this.dom, v, cs, camel;
7664 if(prop == 'float'){
7667 if(el.style && (v = el.style[prop])){
7670 if(cs = view.getComputedStyle(el, "")){
7671 if(!(camel = propCache[prop])){
7672 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7679 var el = this.dom, v, cs, camel;
7680 if(prop == 'opacity'){
7681 if(typeof el.style.filter == 'string'){
7682 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7684 var fv = parseFloat(m[1]);
7686 return fv ? fv / 100 : 0;
7691 }else if(prop == 'float'){
7692 prop = "styleFloat";
7694 if(!(camel = propCache[prop])){
7695 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7697 if(v = el.style[camel]){
7700 if(cs = el.currentStyle){
7708 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7709 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7710 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7711 * @return {Roo.Element} this
7713 setStyle : function(prop, value){
7714 if(typeof prop == "string"){
7716 if (prop == 'float') {
7717 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7722 if(!(camel = propCache[prop])){
7723 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7726 if(camel == 'opacity') {
7727 this.setOpacity(value);
7729 this.dom.style[camel] = value;
7732 for(var style in prop){
7733 if(typeof prop[style] != "function"){
7734 this.setStyle(style, prop[style]);
7742 * More flexible version of {@link #setStyle} for setting style properties.
7743 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7744 * a function which returns such a specification.
7745 * @return {Roo.Element} this
7747 applyStyles : function(style){
7748 Roo.DomHelper.applyStyles(this.dom, style);
7753 * 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).
7754 * @return {Number} The X position of the element
7757 return D.getX(this.dom);
7761 * 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).
7762 * @return {Number} The Y position of the element
7765 return D.getY(this.dom);
7769 * 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).
7770 * @return {Array} The XY position of the element
7773 return D.getXY(this.dom);
7777 * 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).
7778 * @param {Number} The X position of the element
7779 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7780 * @return {Roo.Element} this
7782 setX : function(x, animate){
7784 D.setX(this.dom, x);
7786 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7792 * 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).
7793 * @param {Number} The Y position of the element
7794 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7795 * @return {Roo.Element} this
7797 setY : function(y, animate){
7799 D.setY(this.dom, y);
7801 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7807 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7808 * @param {String} left The left CSS property value
7809 * @return {Roo.Element} this
7811 setLeft : function(left){
7812 this.setStyle("left", this.addUnits(left));
7817 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7818 * @param {String} top The top CSS property value
7819 * @return {Roo.Element} this
7821 setTop : function(top){
7822 this.setStyle("top", this.addUnits(top));
7827 * Sets the element's CSS right style.
7828 * @param {String} right The right CSS property value
7829 * @return {Roo.Element} this
7831 setRight : function(right){
7832 this.setStyle("right", this.addUnits(right));
7837 * Sets the element's CSS bottom style.
7838 * @param {String} bottom The bottom CSS property value
7839 * @return {Roo.Element} this
7841 setBottom : function(bottom){
7842 this.setStyle("bottom", this.addUnits(bottom));
7847 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7848 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7849 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7850 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7851 * @return {Roo.Element} this
7853 setXY : function(pos, animate){
7855 D.setXY(this.dom, pos);
7857 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7863 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7864 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7865 * @param {Number} x X value for new position (coordinates are page-based)
7866 * @param {Number} y Y value for new position (coordinates are page-based)
7867 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7868 * @return {Roo.Element} this
7870 setLocation : function(x, y, animate){
7871 this.setXY([x, y], this.preanim(arguments, 2));
7876 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7877 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7878 * @param {Number} x X value for new position (coordinates are page-based)
7879 * @param {Number} y Y value for new position (coordinates are page-based)
7880 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7881 * @return {Roo.Element} this
7883 moveTo : function(x, y, animate){
7884 this.setXY([x, y], this.preanim(arguments, 2));
7889 * Returns the region of the given element.
7890 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7891 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7893 getRegion : function(){
7894 return D.getRegion(this.dom);
7898 * Returns the offset height of the element
7899 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7900 * @return {Number} The element's height
7902 getHeight : function(contentHeight){
7903 var h = this.dom.offsetHeight || 0;
7904 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7908 * Returns the offset width of the element
7909 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7910 * @return {Number} The element's width
7912 getWidth : function(contentWidth){
7913 var w = this.dom.offsetWidth || 0;
7914 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7918 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7919 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7920 * if a height has not been set using CSS.
7923 getComputedHeight : function(){
7924 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7926 h = parseInt(this.getStyle('height'), 10) || 0;
7927 if(!this.isBorderBox()){
7928 h += this.getFrameWidth('tb');
7935 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7936 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7937 * if a width has not been set using CSS.
7940 getComputedWidth : function(){
7941 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7943 w = parseInt(this.getStyle('width'), 10) || 0;
7944 if(!this.isBorderBox()){
7945 w += this.getFrameWidth('lr');
7952 * Returns the size of the element.
7953 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7954 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7956 getSize : function(contentSize){
7957 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7961 * Returns the width and height of the viewport.
7962 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7964 getViewSize : function(){
7965 var d = this.dom, doc = document, aw = 0, ah = 0;
7966 if(d == doc || d == doc.body){
7967 return {width : D.getViewWidth(), height: D.getViewHeight()};
7970 width : d.clientWidth,
7971 height: d.clientHeight
7977 * Returns the value of the "value" attribute
7978 * @param {Boolean} asNumber true to parse the value as a number
7979 * @return {String/Number}
7981 getValue : function(asNumber){
7982 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7986 adjustWidth : function(width){
7987 if(typeof width == "number"){
7988 if(this.autoBoxAdjust && !this.isBorderBox()){
7989 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7999 adjustHeight : function(height){
8000 if(typeof height == "number"){
8001 if(this.autoBoxAdjust && !this.isBorderBox()){
8002 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8012 * Set the width of the element
8013 * @param {Number} width The new width
8014 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8015 * @return {Roo.Element} this
8017 setWidth : function(width, animate){
8018 width = this.adjustWidth(width);
8020 this.dom.style.width = this.addUnits(width);
8022 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8028 * Set the height of the element
8029 * @param {Number} height The new height
8030 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8031 * @return {Roo.Element} this
8033 setHeight : function(height, animate){
8034 height = this.adjustHeight(height);
8036 this.dom.style.height = this.addUnits(height);
8038 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8044 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8045 * @param {Number} width The new width
8046 * @param {Number} height The new height
8047 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8048 * @return {Roo.Element} this
8050 setSize : function(width, height, animate){
8051 if(typeof width == "object"){ // in case of object from getSize()
8052 height = width.height; width = width.width;
8054 width = this.adjustWidth(width); height = this.adjustHeight(height);
8056 this.dom.style.width = this.addUnits(width);
8057 this.dom.style.height = this.addUnits(height);
8059 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8065 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8066 * @param {Number} x X value for new position (coordinates are page-based)
8067 * @param {Number} y Y value for new position (coordinates are page-based)
8068 * @param {Number} width The new width
8069 * @param {Number} height The new height
8070 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8071 * @return {Roo.Element} this
8073 setBounds : function(x, y, width, height, animate){
8075 this.setSize(width, height);
8076 this.setLocation(x, y);
8078 width = this.adjustWidth(width); height = this.adjustHeight(height);
8079 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8080 this.preanim(arguments, 4), 'motion');
8086 * 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.
8087 * @param {Roo.lib.Region} region The region to fill
8088 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8089 * @return {Roo.Element} this
8091 setRegion : function(region, animate){
8092 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8097 * Appends an event handler
8099 * @param {String} eventName The type of event to append
8100 * @param {Function} fn The method the event invokes
8101 * @param {Object} scope (optional) The scope (this object) of the fn
8102 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8104 addListener : function(eventName, fn, scope, options){
8106 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8111 * Removes an event handler from this element
8112 * @param {String} eventName the type of event to remove
8113 * @param {Function} fn the method the event invokes
8114 * @return {Roo.Element} this
8116 removeListener : function(eventName, fn){
8117 Roo.EventManager.removeListener(this.dom, eventName, fn);
8122 * Removes all previous added listeners from this element
8123 * @return {Roo.Element} this
8125 removeAllListeners : function(){
8126 E.purgeElement(this.dom);
8130 relayEvent : function(eventName, observable){
8131 this.on(eventName, function(e){
8132 observable.fireEvent(eventName, e);
8137 * Set the opacity of the element
8138 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8139 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8140 * @return {Roo.Element} this
8142 setOpacity : function(opacity, animate){
8144 var s = this.dom.style;
8147 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8148 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8150 s.opacity = opacity;
8153 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8159 * Gets the left X coordinate
8160 * @param {Boolean} local True to get the local css position instead of page coordinate
8163 getLeft : function(local){
8167 return parseInt(this.getStyle("left"), 10) || 0;
8172 * Gets the right X coordinate of the element (element X position + element width)
8173 * @param {Boolean} local True to get the local css position instead of page coordinate
8176 getRight : function(local){
8178 return this.getX() + this.getWidth();
8180 return (this.getLeft(true) + this.getWidth()) || 0;
8185 * Gets the top Y coordinate
8186 * @param {Boolean} local True to get the local css position instead of page coordinate
8189 getTop : function(local) {
8193 return parseInt(this.getStyle("top"), 10) || 0;
8198 * Gets the bottom Y coordinate of the element (element Y position + element height)
8199 * @param {Boolean} local True to get the local css position instead of page coordinate
8202 getBottom : function(local){
8204 return this.getY() + this.getHeight();
8206 return (this.getTop(true) + this.getHeight()) || 0;
8211 * Initializes positioning on this element. If a desired position is not passed, it will make the
8212 * the element positioned relative IF it is not already positioned.
8213 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8214 * @param {Number} zIndex (optional) The zIndex to apply
8215 * @param {Number} x (optional) Set the page X position
8216 * @param {Number} y (optional) Set the page Y position
8218 position : function(pos, zIndex, x, y){
8220 if(this.getStyle('position') == 'static'){
8221 this.setStyle('position', 'relative');
8224 this.setStyle("position", pos);
8227 this.setStyle("z-index", zIndex);
8229 if(x !== undefined && y !== undefined){
8231 }else if(x !== undefined){
8233 }else if(y !== undefined){
8239 * Clear positioning back to the default when the document was loaded
8240 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8241 * @return {Roo.Element} this
8243 clearPositioning : function(value){
8251 "position" : "static"
8257 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8258 * snapshot before performing an update and then restoring the element.
8261 getPositioning : function(){
8262 var l = this.getStyle("left");
8263 var t = this.getStyle("top");
8265 "position" : this.getStyle("position"),
8267 "right" : l ? "" : this.getStyle("right"),
8269 "bottom" : t ? "" : this.getStyle("bottom"),
8270 "z-index" : this.getStyle("z-index")
8275 * Gets the width of the border(s) for the specified side(s)
8276 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8277 * passing lr would get the border (l)eft width + the border (r)ight width.
8278 * @return {Number} The width of the sides passed added together
8280 getBorderWidth : function(side){
8281 return this.addStyles(side, El.borders);
8285 * Gets the width of the padding(s) for the specified side(s)
8286 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8287 * passing lr would get the padding (l)eft + the padding (r)ight.
8288 * @return {Number} The padding of the sides passed added together
8290 getPadding : function(side){
8291 return this.addStyles(side, El.paddings);
8295 * Set positioning with an object returned by getPositioning().
8296 * @param {Object} posCfg
8297 * @return {Roo.Element} this
8299 setPositioning : function(pc){
8300 this.applyStyles(pc);
8301 if(pc.right == "auto"){
8302 this.dom.style.right = "";
8304 if(pc.bottom == "auto"){
8305 this.dom.style.bottom = "";
8311 fixDisplay : function(){
8312 if(this.getStyle("display") == "none"){
8313 this.setStyle("visibility", "hidden");
8314 this.setStyle("display", this.originalDisplay); // first try reverting to default
8315 if(this.getStyle("display") == "none"){ // if that fails, default to block
8316 this.setStyle("display", "block");
8322 * Quick set left and top adding default units
8323 * @param {String} left The left CSS property value
8324 * @param {String} top The top CSS property value
8325 * @return {Roo.Element} this
8327 setLeftTop : function(left, top){
8328 this.dom.style.left = this.addUnits(left);
8329 this.dom.style.top = this.addUnits(top);
8334 * Move this element relative to its current position.
8335 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8336 * @param {Number} distance How far to move the element in pixels
8337 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8338 * @return {Roo.Element} this
8340 move : function(direction, distance, animate){
8341 var xy = this.getXY();
8342 direction = direction.toLowerCase();
8346 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8350 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8355 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8360 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8367 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8368 * @return {Roo.Element} this
8371 if(!this.isClipped){
8372 this.isClipped = true;
8373 this.originalClip = {
8374 "o": this.getStyle("overflow"),
8375 "x": this.getStyle("overflow-x"),
8376 "y": this.getStyle("overflow-y")
8378 this.setStyle("overflow", "hidden");
8379 this.setStyle("overflow-x", "hidden");
8380 this.setStyle("overflow-y", "hidden");
8386 * Return clipping (overflow) to original clipping before clip() was called
8387 * @return {Roo.Element} this
8389 unclip : function(){
8391 this.isClipped = false;
8392 var o = this.originalClip;
8393 if(o.o){this.setStyle("overflow", o.o);}
8394 if(o.x){this.setStyle("overflow-x", o.x);}
8395 if(o.y){this.setStyle("overflow-y", o.y);}
8402 * Gets the x,y coordinates specified by the anchor position on the element.
8403 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8404 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8405 * {width: (target width), height: (target height)} (defaults to the element's current size)
8406 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8407 * @return {Array} [x, y] An array containing the element's x and y coordinates
8409 getAnchorXY : function(anchor, local, s){
8410 //Passing a different size is useful for pre-calculating anchors,
8411 //especially for anchored animations that change the el size.
8413 var w, h, vp = false;
8416 if(d == document.body || d == document){
8418 w = D.getViewWidth(); h = D.getViewHeight();
8420 w = this.getWidth(); h = this.getHeight();
8423 w = s.width; h = s.height;
8425 var x = 0, y = 0, r = Math.round;
8426 switch((anchor || "tl").toLowerCase()){
8468 var sc = this.getScroll();
8469 return [x + sc.left, y + sc.top];
8471 //Add the element's offset xy
8472 var o = this.getXY();
8473 return [x+o[0], y+o[1]];
8477 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8478 * supported position values.
8479 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8480 * @param {String} position The position to align to.
8481 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8482 * @return {Array} [x, y]
8484 getAlignToXY : function(el, p, o){
8488 throw "Element.alignTo with an element that doesn't exist";
8490 var c = false; //constrain to viewport
8491 var p1 = "", p2 = "";
8498 }else if(p.indexOf("-") == -1){
8501 p = p.toLowerCase();
8502 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8504 throw "Element.alignTo with an invalid alignment " + p;
8506 p1 = m[1]; p2 = m[2]; c = !!m[3];
8508 //Subtract the aligned el's internal xy from the target's offset xy
8509 //plus custom offset to get the aligned el's new offset xy
8510 var a1 = this.getAnchorXY(p1, true);
8511 var a2 = el.getAnchorXY(p2, false);
8512 var x = a2[0] - a1[0] + o[0];
8513 var y = a2[1] - a1[1] + o[1];
8515 //constrain the aligned el to viewport if necessary
8516 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8517 // 5px of margin for ie
8518 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8520 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8521 //perpendicular to the vp border, allow the aligned el to slide on that border,
8522 //otherwise swap the aligned el to the opposite border of the target.
8523 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8524 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8525 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8526 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8529 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8530 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8532 if((x+w) > dw + scrollX){
8533 x = swapX ? r.left-w : dw+scrollX-w;
8536 x = swapX ? r.right : scrollX;
8538 if((y+h) > dh + scrollY){
8539 y = swapY ? r.top-h : dh+scrollY-h;
8542 y = swapY ? r.bottom : scrollY;
8549 getConstrainToXY : function(){
8550 var os = {top:0, left:0, bottom:0, right: 0};
8552 return function(el, local, offsets, proposedXY){
8554 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8556 var vw, vh, vx = 0, vy = 0;
8557 if(el.dom == document.body || el.dom == document){
8558 vw = Roo.lib.Dom.getViewWidth();
8559 vh = Roo.lib.Dom.getViewHeight();
8561 vw = el.dom.clientWidth;
8562 vh = el.dom.clientHeight;
8564 var vxy = el.getXY();
8570 var s = el.getScroll();
8572 vx += offsets.left + s.left;
8573 vy += offsets.top + s.top;
8575 vw -= offsets.right;
8576 vh -= offsets.bottom;
8581 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8582 var x = xy[0], y = xy[1];
8583 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8585 // only move it if it needs it
8588 // first validate right/bottom
8597 // then make sure top/left isn't negative
8606 return moved ? [x, y] : false;
8611 adjustForConstraints : function(xy, parent, offsets){
8612 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8616 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8617 * document it aligns it to the viewport.
8618 * The position parameter is optional, and can be specified in any one of the following formats:
8620 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8621 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8622 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8623 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8624 * <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
8625 * element's anchor point, and the second value is used as the target's anchor point.</li>
8627 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8628 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8629 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8630 * that specified in order to enforce the viewport constraints.
8631 * Following are all of the supported anchor positions:
8634 ----- -----------------------------
8635 tl The top left corner (default)
8636 t The center of the top edge
8637 tr The top right corner
8638 l The center of the left edge
8639 c In the center of the element
8640 r The center of the right edge
8641 bl The bottom left corner
8642 b The center of the bottom edge
8643 br The bottom right corner
8647 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8648 el.alignTo("other-el");
8650 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8651 el.alignTo("other-el", "tr?");
8653 // align the bottom right corner of el with the center left edge of other-el
8654 el.alignTo("other-el", "br-l?");
8656 // align the center of el with the bottom left corner of other-el and
8657 // adjust the x position by -6 pixels (and the y position by 0)
8658 el.alignTo("other-el", "c-bl", [-6, 0]);
8660 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8661 * @param {String} position The position to align to.
8662 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8663 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8664 * @return {Roo.Element} this
8666 alignTo : function(element, position, offsets, animate){
8667 var xy = this.getAlignToXY(element, position, offsets);
8668 this.setXY(xy, this.preanim(arguments, 3));
8673 * Anchors an element to another element and realigns it when the window is resized.
8674 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8675 * @param {String} position The position to align to.
8676 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8677 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8678 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8679 * is a number, it is used as the buffer delay (defaults to 50ms).
8680 * @param {Function} callback The function to call after the animation finishes
8681 * @return {Roo.Element} this
8683 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8684 var action = function(){
8685 this.alignTo(el, alignment, offsets, animate);
8686 Roo.callback(callback, this);
8688 Roo.EventManager.onWindowResize(action, this);
8689 var tm = typeof monitorScroll;
8690 if(tm != 'undefined'){
8691 Roo.EventManager.on(window, 'scroll', action, this,
8692 {buffer: tm == 'number' ? monitorScroll : 50});
8694 action.call(this); // align immediately
8698 * Clears any opacity settings from this element. Required in some cases for IE.
8699 * @return {Roo.Element} this
8701 clearOpacity : function(){
8702 if (window.ActiveXObject) {
8703 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8704 this.dom.style.filter = "";
8707 this.dom.style.opacity = "";
8708 this.dom.style["-moz-opacity"] = "";
8709 this.dom.style["-khtml-opacity"] = "";
8715 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8716 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8717 * @return {Roo.Element} this
8719 hide : function(animate){
8720 this.setVisible(false, this.preanim(arguments, 0));
8725 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8726 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8727 * @return {Roo.Element} this
8729 show : function(animate){
8730 this.setVisible(true, this.preanim(arguments, 0));
8735 * @private Test if size has a unit, otherwise appends the default
8737 addUnits : function(size){
8738 return Roo.Element.addUnits(size, this.defaultUnit);
8742 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8743 * @return {Roo.Element} this
8745 beginMeasure : function(){
8747 if(el.offsetWidth || el.offsetHeight){
8748 return this; // offsets work already
8751 var p = this.dom, b = document.body; // start with this element
8752 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8753 var pe = Roo.get(p);
8754 if(pe.getStyle('display') == 'none'){
8755 changed.push({el: p, visibility: pe.getStyle("visibility")});
8756 p.style.visibility = "hidden";
8757 p.style.display = "block";
8761 this._measureChanged = changed;
8767 * Restores displays to before beginMeasure was called
8768 * @return {Roo.Element} this
8770 endMeasure : function(){
8771 var changed = this._measureChanged;
8773 for(var i = 0, len = changed.length; i < len; i++) {
8775 r.el.style.visibility = r.visibility;
8776 r.el.style.display = "none";
8778 this._measureChanged = null;
8784 * Update the innerHTML of this element, optionally searching for and processing scripts
8785 * @param {String} html The new HTML
8786 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8787 * @param {Function} callback For async script loading you can be noticed when the update completes
8788 * @return {Roo.Element} this
8790 update : function(html, loadScripts, callback){
8791 if(typeof html == "undefined"){
8794 if(loadScripts !== true){
8795 this.dom.innerHTML = html;
8796 if(typeof callback == "function"){
8804 html += '<span id="' + id + '"></span>';
8806 E.onAvailable(id, function(){
8807 var hd = document.getElementsByTagName("head")[0];
8808 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8809 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8810 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8813 while(match = re.exec(html)){
8814 var attrs = match[1];
8815 var srcMatch = attrs ? attrs.match(srcRe) : false;
8816 if(srcMatch && srcMatch[2]){
8817 var s = document.createElement("script");
8818 s.src = srcMatch[2];
8819 var typeMatch = attrs.match(typeRe);
8820 if(typeMatch && typeMatch[2]){
8821 s.type = typeMatch[2];
8824 }else if(match[2] && match[2].length > 0){
8825 if(window.execScript) {
8826 window.execScript(match[2]);
8834 window.eval(match[2]);
8838 var el = document.getElementById(id);
8839 if(el){el.parentNode.removeChild(el);}
8840 if(typeof callback == "function"){
8844 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8849 * Direct access to the UpdateManager update() method (takes the same parameters).
8850 * @param {String/Function} url The url for this request or a function to call to get the url
8851 * @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}
8852 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8853 * @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.
8854 * @return {Roo.Element} this
8857 var um = this.getUpdateManager();
8858 um.update.apply(um, arguments);
8863 * Gets this element's UpdateManager
8864 * @return {Roo.UpdateManager} The UpdateManager
8866 getUpdateManager : function(){
8867 if(!this.updateManager){
8868 this.updateManager = new Roo.UpdateManager(this);
8870 return this.updateManager;
8874 * Disables text selection for this element (normalized across browsers)
8875 * @return {Roo.Element} this
8877 unselectable : function(){
8878 this.dom.unselectable = "on";
8879 this.swallowEvent("selectstart", true);
8880 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8881 this.addClass("x-unselectable");
8886 * Calculates the x, y to center this element on the screen
8887 * @return {Array} The x, y values [x, y]
8889 getCenterXY : function(){
8890 return this.getAlignToXY(document, 'c-c');
8894 * Centers the Element in either the viewport, or another Element.
8895 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8897 center : function(centerIn){
8898 this.alignTo(centerIn || document, 'c-c');
8903 * Tests various css rules/browsers to determine if this element uses a border box
8906 isBorderBox : function(){
8907 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8911 * Return a box {x, y, width, height} that can be used to set another elements
8912 * size/location to match this element.
8913 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8914 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8915 * @return {Object} box An object in the format {x, y, width, height}
8917 getBox : function(contentBox, local){
8922 var left = parseInt(this.getStyle("left"), 10) || 0;
8923 var top = parseInt(this.getStyle("top"), 10) || 0;
8926 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8928 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8930 var l = this.getBorderWidth("l")+this.getPadding("l");
8931 var r = this.getBorderWidth("r")+this.getPadding("r");
8932 var t = this.getBorderWidth("t")+this.getPadding("t");
8933 var b = this.getBorderWidth("b")+this.getPadding("b");
8934 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)};
8936 bx.right = bx.x + bx.width;
8937 bx.bottom = bx.y + bx.height;
8942 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8943 for more information about the sides.
8944 * @param {String} sides
8947 getFrameWidth : function(sides, onlyContentBox){
8948 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8952 * 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.
8953 * @param {Object} box The box to fill {x, y, width, height}
8954 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8955 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8956 * @return {Roo.Element} this
8958 setBox : function(box, adjust, animate){
8959 var w = box.width, h = box.height;
8960 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8961 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8962 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8964 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8969 * Forces the browser to repaint this element
8970 * @return {Roo.Element} this
8972 repaint : function(){
8974 this.addClass("x-repaint");
8975 setTimeout(function(){
8976 Roo.get(dom).removeClass("x-repaint");
8982 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8983 * then it returns the calculated width of the sides (see getPadding)
8984 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8985 * @return {Object/Number}
8987 getMargins : function(side){
8990 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8991 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8992 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8993 right: parseInt(this.getStyle("margin-right"), 10) || 0
8996 return this.addStyles(side, El.margins);
9001 addStyles : function(sides, styles){
9003 for(var i = 0, len = sides.length; i < len; i++){
9004 v = this.getStyle(styles[sides.charAt(i)]);
9006 w = parseInt(v, 10);
9014 * Creates a proxy element of this element
9015 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9016 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9017 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9018 * @return {Roo.Element} The new proxy element
9020 createProxy : function(config, renderTo, matchBox){
9022 renderTo = Roo.getDom(renderTo);
9024 renderTo = document.body;
9026 config = typeof config == "object" ?
9027 config : {tag : "div", cls: config};
9028 var proxy = Roo.DomHelper.append(renderTo, config, true);
9030 proxy.setBox(this.getBox());
9036 * Puts a mask over this element to disable user interaction. Requires core.css.
9037 * This method can only be applied to elements which accept child nodes.
9038 * @param {String} msg (optional) A message to display in the mask
9039 * @param {String} msgCls (optional) A css class to apply to the msg element
9040 * @return {Element} The mask element
9042 mask : function(msg, msgCls)
9044 if(this.getStyle("position") == "static"){
9045 this.setStyle("position", "relative");
9048 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9050 this.addClass("x-masked");
9051 this._mask.setDisplayed(true);
9056 while (dom && dom.style) {
9057 if (!isNaN(parseInt(dom.style.zIndex))) {
9058 z = Math.max(z, parseInt(dom.style.zIndex));
9060 dom = dom.parentNode;
9062 // if we are masking the body - then it hides everything..
9063 if (this.dom == document.body) {
9065 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9066 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9069 if(typeof msg == 'string'){
9071 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9073 var mm = this._maskMsg;
9074 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9075 mm.dom.firstChild.innerHTML = msg;
9076 mm.setDisplayed(true);
9078 mm.setStyle('z-index', z + 102);
9080 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9081 this._mask.setHeight(this.getHeight());
9083 this._mask.setStyle('z-index', z + 100);
9089 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9090 * it is cached for reuse.
9092 unmask : function(removeEl){
9094 if(removeEl === true){
9095 this._mask.remove();
9098 this._maskMsg.remove();
9099 delete this._maskMsg;
9102 this._mask.setDisplayed(false);
9104 this._maskMsg.setDisplayed(false);
9108 this.removeClass("x-masked");
9112 * Returns true if this element is masked
9115 isMasked : function(){
9116 return this._mask && this._mask.isVisible();
9120 * Creates an iframe shim for this element to keep selects and other windowed objects from
9122 * @return {Roo.Element} The new shim element
9124 createShim : function(){
9125 var el = document.createElement('iframe');
9126 el.frameBorder = 'no';
9127 el.className = 'roo-shim';
9128 if(Roo.isIE && Roo.isSecure){
9129 el.src = Roo.SSL_SECURE_URL;
9131 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9132 shim.autoBoxAdjust = false;
9137 * Removes this element from the DOM and deletes it from the cache
9139 remove : function(){
9140 if(this.dom.parentNode){
9141 this.dom.parentNode.removeChild(this.dom);
9143 delete El.cache[this.dom.id];
9147 * Sets up event handlers to add and remove a css class when the mouse is over this element
9148 * @param {String} className
9149 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9150 * mouseout events for children elements
9151 * @return {Roo.Element} this
9153 addClassOnOver : function(className, preventFlicker){
9154 this.on("mouseover", function(){
9155 Roo.fly(this, '_internal').addClass(className);
9157 var removeFn = function(e){
9158 if(preventFlicker !== true || !e.within(this, true)){
9159 Roo.fly(this, '_internal').removeClass(className);
9162 this.on("mouseout", removeFn, this.dom);
9167 * Sets up event handlers to add and remove a css class when this element has the focus
9168 * @param {String} className
9169 * @return {Roo.Element} this
9171 addClassOnFocus : function(className){
9172 this.on("focus", function(){
9173 Roo.fly(this, '_internal').addClass(className);
9175 this.on("blur", function(){
9176 Roo.fly(this, '_internal').removeClass(className);
9181 * 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)
9182 * @param {String} className
9183 * @return {Roo.Element} this
9185 addClassOnClick : function(className){
9187 this.on("mousedown", function(){
9188 Roo.fly(dom, '_internal').addClass(className);
9189 var d = Roo.get(document);
9190 var fn = function(){
9191 Roo.fly(dom, '_internal').removeClass(className);
9192 d.removeListener("mouseup", fn);
9194 d.on("mouseup", fn);
9200 * Stops the specified event from bubbling and optionally prevents the default action
9201 * @param {String} eventName
9202 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9203 * @return {Roo.Element} this
9205 swallowEvent : function(eventName, preventDefault){
9206 var fn = function(e){
9207 e.stopPropagation();
9212 if(eventName instanceof Array){
9213 for(var i = 0, len = eventName.length; i < len; i++){
9214 this.on(eventName[i], fn);
9218 this.on(eventName, fn);
9225 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9228 * Sizes this element to its parent element's dimensions performing
9229 * neccessary box adjustments.
9230 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9231 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9232 * @return {Roo.Element} this
9234 fitToParent : function(monitorResize, targetParent) {
9235 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9236 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9237 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9240 var p = Roo.get(targetParent || this.dom.parentNode);
9241 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9242 if (monitorResize === true) {
9243 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9244 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9250 * Gets the next sibling, skipping text nodes
9251 * @return {HTMLElement} The next sibling or null
9253 getNextSibling : function(){
9254 var n = this.dom.nextSibling;
9255 while(n && n.nodeType != 1){
9262 * Gets the previous sibling, skipping text nodes
9263 * @return {HTMLElement} The previous sibling or null
9265 getPrevSibling : function(){
9266 var n = this.dom.previousSibling;
9267 while(n && n.nodeType != 1){
9268 n = n.previousSibling;
9275 * Appends the passed element(s) to this element
9276 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9277 * @return {Roo.Element} this
9279 appendChild: function(el){
9286 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9287 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9288 * automatically generated with the specified attributes.
9289 * @param {HTMLElement} insertBefore (optional) a child element of this element
9290 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9291 * @return {Roo.Element} The new child element
9293 createChild: function(config, insertBefore, returnDom){
9294 config = config || {tag:'div'};
9296 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9298 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9302 * Appends this element to the passed element
9303 * @param {String/HTMLElement/Element} el The new parent element
9304 * @return {Roo.Element} this
9306 appendTo: function(el){
9307 el = Roo.getDom(el);
9308 el.appendChild(this.dom);
9313 * Inserts this element before the passed element in the DOM
9314 * @param {String/HTMLElement/Element} el The element to insert before
9315 * @return {Roo.Element} this
9317 insertBefore: function(el){
9318 el = Roo.getDom(el);
9319 el.parentNode.insertBefore(this.dom, el);
9324 * Inserts this element after the passed element in the DOM
9325 * @param {String/HTMLElement/Element} el The element to insert after
9326 * @return {Roo.Element} this
9328 insertAfter: function(el){
9329 el = Roo.getDom(el);
9330 el.parentNode.insertBefore(this.dom, el.nextSibling);
9335 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9336 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9337 * @return {Roo.Element} The new child
9339 insertFirst: function(el, returnDom){
9341 if(typeof el == 'object' && !el.nodeType){ // dh config
9342 return this.createChild(el, this.dom.firstChild, returnDom);
9344 el = Roo.getDom(el);
9345 this.dom.insertBefore(el, this.dom.firstChild);
9346 return !returnDom ? Roo.get(el) : el;
9351 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9352 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9353 * @param {String} where (optional) 'before' or 'after' defaults to before
9354 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9355 * @return {Roo.Element} the inserted Element
9357 insertSibling: function(el, where, returnDom){
9358 where = where ? where.toLowerCase() : 'before';
9360 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9362 if(typeof el == 'object' && !el.nodeType){ // dh config
9363 if(where == 'after' && !this.dom.nextSibling){
9364 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9366 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9370 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9371 where == 'before' ? this.dom : this.dom.nextSibling);
9380 * Creates and wraps this element with another element
9381 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9382 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9383 * @return {HTMLElement/Element} The newly created wrapper element
9385 wrap: function(config, returnDom){
9387 config = {tag: "div"};
9389 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9390 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9395 * Replaces the passed element with this element
9396 * @param {String/HTMLElement/Element} el The element to replace
9397 * @return {Roo.Element} this
9399 replace: function(el){
9401 this.insertBefore(el);
9407 * Inserts an html fragment into this element
9408 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9409 * @param {String} html The HTML fragment
9410 * @param {Boolean} returnEl True to return an Roo.Element
9411 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9413 insertHtml : function(where, html, returnEl){
9414 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9415 return returnEl ? Roo.get(el) : el;
9419 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9420 * @param {Object} o The object with the attributes
9421 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9422 * @return {Roo.Element} this
9424 set : function(o, useSet){
9426 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9428 if(attr == "style" || typeof o[attr] == "function") continue;
9430 el.className = o["cls"];
9432 if(useSet) el.setAttribute(attr, o[attr]);
9433 else el[attr] = o[attr];
9437 Roo.DomHelper.applyStyles(el, o.style);
9443 * Convenience method for constructing a KeyMap
9444 * @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:
9445 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9446 * @param {Function} fn The function to call
9447 * @param {Object} scope (optional) The scope of the function
9448 * @return {Roo.KeyMap} The KeyMap created
9450 addKeyListener : function(key, fn, scope){
9452 if(typeof key != "object" || key instanceof Array){
9468 return new Roo.KeyMap(this, config);
9472 * Creates a KeyMap for this element
9473 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9474 * @return {Roo.KeyMap} The KeyMap created
9476 addKeyMap : function(config){
9477 return new Roo.KeyMap(this, config);
9481 * Returns true if this element is scrollable.
9484 isScrollable : function(){
9486 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9490 * 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().
9491 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9492 * @param {Number} value The new scroll value
9493 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9494 * @return {Element} this
9497 scrollTo : function(side, value, animate){
9498 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9500 this.dom[prop] = value;
9502 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9503 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9509 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9510 * within this element's scrollable range.
9511 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9512 * @param {Number} distance How far to scroll the element in pixels
9513 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9514 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9515 * was scrolled as far as it could go.
9517 scroll : function(direction, distance, animate){
9518 if(!this.isScrollable()){
9522 var l = el.scrollLeft, t = el.scrollTop;
9523 var w = el.scrollWidth, h = el.scrollHeight;
9524 var cw = el.clientWidth, ch = el.clientHeight;
9525 direction = direction.toLowerCase();
9526 var scrolled = false;
9527 var a = this.preanim(arguments, 2);
9532 var v = Math.min(l + distance, w-cw);
9533 this.scrollTo("left", v, a);
9540 var v = Math.max(l - distance, 0);
9541 this.scrollTo("left", v, a);
9549 var v = Math.max(t - distance, 0);
9550 this.scrollTo("top", v, a);
9558 var v = Math.min(t + distance, h-ch);
9559 this.scrollTo("top", v, a);
9568 * Translates the passed page coordinates into left/top css values for this element
9569 * @param {Number/Array} x The page x or an array containing [x, y]
9570 * @param {Number} y The page y
9571 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9573 translatePoints : function(x, y){
9574 if(typeof x == 'object' || x instanceof Array){
9577 var p = this.getStyle('position');
9578 var o = this.getXY();
9580 var l = parseInt(this.getStyle('left'), 10);
9581 var t = parseInt(this.getStyle('top'), 10);
9584 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9587 t = (p == "relative") ? 0 : this.dom.offsetTop;
9590 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9594 * Returns the current scroll position of the element.
9595 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9597 getScroll : function(){
9598 var d = this.dom, doc = document;
9599 if(d == doc || d == doc.body){
9600 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9601 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9602 return {left: l, top: t};
9604 return {left: d.scrollLeft, top: d.scrollTop};
9609 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9610 * are convert to standard 6 digit hex color.
9611 * @param {String} attr The css attribute
9612 * @param {String} defaultValue The default value to use when a valid color isn't found
9613 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9616 getColor : function(attr, defaultValue, prefix){
9617 var v = this.getStyle(attr);
9618 if(!v || v == "transparent" || v == "inherit") {
9619 return defaultValue;
9621 var color = typeof prefix == "undefined" ? "#" : prefix;
9622 if(v.substr(0, 4) == "rgb("){
9623 var rvs = v.slice(4, v.length -1).split(",");
9624 for(var i = 0; i < 3; i++){
9625 var h = parseInt(rvs[i]).toString(16);
9632 if(v.substr(0, 1) == "#"){
9634 for(var i = 1; i < 4; i++){
9635 var c = v.charAt(i);
9638 }else if(v.length == 7){
9639 color += v.substr(1);
9643 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9647 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9648 * gradient background, rounded corners and a 4-way shadow.
9649 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9650 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9651 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9652 * @return {Roo.Element} this
9654 boxWrap : function(cls){
9655 cls = cls || 'x-box';
9656 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9657 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9662 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9663 * @param {String} namespace The namespace in which to look for the attribute
9664 * @param {String} name The attribute name
9665 * @return {String} The attribute value
9667 getAttributeNS : Roo.isIE ? function(ns, name){
9669 var type = typeof d[ns+":"+name];
9670 if(type != 'undefined' && type != 'unknown'){
9671 return d[ns+":"+name];
9674 } : function(ns, name){
9676 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9681 * Sets or Returns the value the dom attribute value
9682 * @param {String} name The attribute name
9683 * @param {String} value (optional) The value to set the attribute to
9684 * @return {String} The attribute value
9686 attr : function(name){
9687 if (arguments.length > 1) {
9688 this.dom.setAttribute(name, arguments[1]);
9689 return arguments[1];
9691 if (!this.dom.hasAttribute(name)) {
9694 return this.dom.getAttribute(name);
9701 var ep = El.prototype;
9704 * Appends an event handler (Shorthand for addListener)
9705 * @param {String} eventName The type of event to append
9706 * @param {Function} fn The method the event invokes
9707 * @param {Object} scope (optional) The scope (this object) of the fn
9708 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9711 ep.on = ep.addListener;
9713 ep.mon = ep.addListener;
9716 * Removes an event handler from this element (shorthand for removeListener)
9717 * @param {String} eventName the type of event to remove
9718 * @param {Function} fn the method the event invokes
9719 * @return {Roo.Element} this
9722 ep.un = ep.removeListener;
9725 * true to automatically adjust width and height settings for box-model issues (default to true)
9727 ep.autoBoxAdjust = true;
9730 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9733 El.addUnits = function(v, defaultUnit){
9734 if(v === "" || v == "auto"){
9737 if(v === undefined){
9740 if(typeof v == "number" || !El.unitPattern.test(v)){
9741 return v + (defaultUnit || 'px');
9746 // special markup used throughout Roo when box wrapping elements
9747 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>';
9749 * Visibility mode constant - Use visibility to hide element
9755 * Visibility mode constant - Use display to hide element
9761 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9762 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9763 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9775 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9776 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9777 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9778 * @return {Element} The Element object
9781 El.get = function(el){
9783 if(!el){ return null; }
9784 if(typeof el == "string"){ // element id
9785 if(!(elm = document.getElementById(el))){
9788 if(ex = El.cache[el]){
9791 ex = El.cache[el] = new El(elm);
9794 }else if(el.tagName){ // dom element
9798 if(ex = El.cache[id]){
9801 ex = El.cache[id] = new El(el);
9804 }else if(el instanceof El){
9806 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9807 // catch case where it hasn't been appended
9808 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9811 }else if(el.isComposite){
9813 }else if(el instanceof Array){
9814 return El.select(el);
9815 }else if(el == document){
9816 // create a bogus element object representing the document object
9818 var f = function(){};
9819 f.prototype = El.prototype;
9821 docEl.dom = document;
9829 El.uncache = function(el){
9830 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9832 delete El.cache[a[i].id || a[i]];
9838 // Garbage collection - uncache elements/purge listeners on orphaned elements
9839 // so we don't hold a reference and cause the browser to retain them
9840 El.garbageCollect = function(){
9841 if(!Roo.enableGarbageCollector){
9842 clearInterval(El.collectorThread);
9845 for(var eid in El.cache){
9846 var el = El.cache[eid], d = el.dom;
9847 // -------------------------------------------------------
9848 // Determining what is garbage:
9849 // -------------------------------------------------------
9851 // dom node is null, definitely garbage
9852 // -------------------------------------------------------
9854 // no parentNode == direct orphan, definitely garbage
9855 // -------------------------------------------------------
9856 // !d.offsetParent && !document.getElementById(eid)
9857 // display none elements have no offsetParent so we will
9858 // also try to look it up by it's id. However, check
9859 // offsetParent first so we don't do unneeded lookups.
9860 // This enables collection of elements that are not orphans
9861 // directly, but somewhere up the line they have an orphan
9863 // -------------------------------------------------------
9864 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9865 delete El.cache[eid];
9866 if(d && Roo.enableListenerCollection){
9872 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9876 El.Flyweight = function(dom){
9879 El.Flyweight.prototype = El.prototype;
9881 El._flyweights = {};
9883 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9884 * the dom node can be overwritten by other code.
9885 * @param {String/HTMLElement} el The dom node or id
9886 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9887 * prevent conflicts (e.g. internally Roo uses "_internal")
9889 * @return {Element} The shared Element object
9891 El.fly = function(el, named){
9892 named = named || '_global';
9893 el = Roo.getDom(el);
9897 if(!El._flyweights[named]){
9898 El._flyweights[named] = new El.Flyweight();
9900 El._flyweights[named].dom = el;
9901 return El._flyweights[named];
9905 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9906 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9907 * Shorthand of {@link Roo.Element#get}
9908 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9909 * @return {Element} The Element object
9915 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9916 * the dom node can be overwritten by other code.
9917 * Shorthand of {@link Roo.Element#fly}
9918 * @param {String/HTMLElement} el The dom node or id
9919 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9920 * prevent conflicts (e.g. internally Roo uses "_internal")
9922 * @return {Element} The shared Element object
9928 // speedy lookup for elements never to box adjust
9929 var noBoxAdjust = Roo.isStrict ? {
9932 input:1, select:1, textarea:1
9934 if(Roo.isIE || Roo.isGecko){
9935 noBoxAdjust['button'] = 1;
9939 Roo.EventManager.on(window, 'unload', function(){
9941 delete El._flyweights;
9949 Roo.Element.selectorFunction = Roo.DomQuery.select;
9952 Roo.Element.select = function(selector, unique, root){
9954 if(typeof selector == "string"){
9955 els = Roo.Element.selectorFunction(selector, root);
9956 }else if(selector.length !== undefined){
9959 throw "Invalid selector";
9961 if(unique === true){
9962 return new Roo.CompositeElement(els);
9964 return new Roo.CompositeElementLite(els);
9968 * Selects elements based on the passed CSS selector to enable working on them as 1.
9969 * @param {String/Array} selector The CSS selector or an array of elements
9970 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9971 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9972 * @return {CompositeElementLite/CompositeElement}
9976 Roo.select = Roo.Element.select;
9993 * Ext JS Library 1.1.1
9994 * Copyright(c) 2006-2007, Ext JS, LLC.
9996 * Originally Released Under LGPL - original licence link has changed is not relivant.
9999 * <script type="text/javascript">
10004 //Notifies Element that fx methods are available
10005 Roo.enableFx = true;
10009 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10010 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10011 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10012 * Element effects to work.</p><br/>
10014 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10015 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10016 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10017 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10018 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10019 * expected results and should be done with care.</p><br/>
10021 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10022 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10025 ----- -----------------------------
10026 tl The top left corner
10027 t The center of the top edge
10028 tr The top right corner
10029 l The center of the left edge
10030 r The center of the right edge
10031 bl The bottom left corner
10032 b The center of the bottom edge
10033 br The bottom right corner
10035 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10036 * below are common options that can be passed to any Fx method.</b>
10037 * @cfg {Function} callback A function called when the effect is finished
10038 * @cfg {Object} scope The scope of the effect function
10039 * @cfg {String} easing A valid Easing value for the effect
10040 * @cfg {String} afterCls A css class to apply after the effect
10041 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10042 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10043 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10044 * effects that end with the element being visually hidden, ignored otherwise)
10045 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10046 * a function which returns such a specification that will be applied to the Element after the effect finishes
10047 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10048 * @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
10049 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10053 * Slides the element into view. An anchor point can be optionally passed to set the point of
10054 * origin for the slide effect. This function automatically handles wrapping the element with
10055 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10058 // default: slide the element in from the top
10061 // custom: slide the element in from the right with a 2-second duration
10062 el.slideIn('r', { duration: 2 });
10064 // common config options shown with default values
10070 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10071 * @param {Object} options (optional) Object literal with any of the Fx config options
10072 * @return {Roo.Element} The Element
10074 slideIn : function(anchor, o){
10075 var el = this.getFxEl();
10078 el.queueFx(o, function(){
10080 anchor = anchor || "t";
10082 // fix display to visibility
10085 // restore values after effect
10086 var r = this.getFxRestore();
10087 var b = this.getBox();
10088 // fixed size for slide
10092 var wrap = this.fxWrap(r.pos, o, "hidden");
10094 var st = this.dom.style;
10095 st.visibility = "visible";
10096 st.position = "absolute";
10098 // clear out temp styles after slide and unwrap
10099 var after = function(){
10100 el.fxUnwrap(wrap, r.pos, o);
10101 st.width = r.width;
10102 st.height = r.height;
10105 // time to calc the positions
10106 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10108 switch(anchor.toLowerCase()){
10110 wrap.setSize(b.width, 0);
10111 st.left = st.bottom = "0";
10115 wrap.setSize(0, b.height);
10116 st.right = st.top = "0";
10120 wrap.setSize(0, b.height);
10121 wrap.setX(b.right);
10122 st.left = st.top = "0";
10123 a = {width: bw, points: pt};
10126 wrap.setSize(b.width, 0);
10127 wrap.setY(b.bottom);
10128 st.left = st.top = "0";
10129 a = {height: bh, points: pt};
10132 wrap.setSize(0, 0);
10133 st.right = st.bottom = "0";
10134 a = {width: bw, height: bh};
10137 wrap.setSize(0, 0);
10138 wrap.setY(b.y+b.height);
10139 st.right = st.top = "0";
10140 a = {width: bw, height: bh, points: pt};
10143 wrap.setSize(0, 0);
10144 wrap.setXY([b.right, b.bottom]);
10145 st.left = st.top = "0";
10146 a = {width: bw, height: bh, points: pt};
10149 wrap.setSize(0, 0);
10150 wrap.setX(b.x+b.width);
10151 st.left = st.bottom = "0";
10152 a = {width: bw, height: bh, points: pt};
10155 this.dom.style.visibility = "visible";
10158 arguments.callee.anim = wrap.fxanim(a,
10168 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10169 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10170 * 'hidden') but block elements will still take up space in the document. The element must be removed
10171 * from the DOM using the 'remove' config option if desired. This function automatically handles
10172 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10175 // default: slide the element out to the top
10178 // custom: slide the element out to the right with a 2-second duration
10179 el.slideOut('r', { duration: 2 });
10181 // common config options shown with default values
10189 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10190 * @param {Object} options (optional) Object literal with any of the Fx config options
10191 * @return {Roo.Element} The Element
10193 slideOut : function(anchor, o){
10194 var el = this.getFxEl();
10197 el.queueFx(o, function(){
10199 anchor = anchor || "t";
10201 // restore values after effect
10202 var r = this.getFxRestore();
10204 var b = this.getBox();
10205 // fixed size for slide
10209 var wrap = this.fxWrap(r.pos, o, "visible");
10211 var st = this.dom.style;
10212 st.visibility = "visible";
10213 st.position = "absolute";
10217 var after = function(){
10219 el.setDisplayed(false);
10224 el.fxUnwrap(wrap, r.pos, o);
10226 st.width = r.width;
10227 st.height = r.height;
10232 var a, zero = {to: 0};
10233 switch(anchor.toLowerCase()){
10235 st.left = st.bottom = "0";
10236 a = {height: zero};
10239 st.right = st.top = "0";
10243 st.left = st.top = "0";
10244 a = {width: zero, points: {to:[b.right, b.y]}};
10247 st.left = st.top = "0";
10248 a = {height: zero, points: {to:[b.x, b.bottom]}};
10251 st.right = st.bottom = "0";
10252 a = {width: zero, height: zero};
10255 st.right = st.top = "0";
10256 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10259 st.left = st.top = "0";
10260 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10263 st.left = st.bottom = "0";
10264 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10268 arguments.callee.anim = wrap.fxanim(a,
10278 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10279 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10280 * The element must be removed from the DOM using the 'remove' config option if desired.
10286 // common config options shown with default values
10294 * @param {Object} options (optional) Object literal with any of the Fx config options
10295 * @return {Roo.Element} The Element
10297 puff : function(o){
10298 var el = this.getFxEl();
10301 el.queueFx(o, function(){
10302 this.clearOpacity();
10305 // restore values after effect
10306 var r = this.getFxRestore();
10307 var st = this.dom.style;
10309 var after = function(){
10311 el.setDisplayed(false);
10318 el.setPositioning(r.pos);
10319 st.width = r.width;
10320 st.height = r.height;
10325 var width = this.getWidth();
10326 var height = this.getHeight();
10328 arguments.callee.anim = this.fxanim({
10329 width : {to: this.adjustWidth(width * 2)},
10330 height : {to: this.adjustHeight(height * 2)},
10331 points : {by: [-(width * .5), -(height * .5)]},
10333 fontSize: {to:200, unit: "%"}
10344 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10345 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10346 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10352 // all config options shown with default values
10360 * @param {Object} options (optional) Object literal with any of the Fx config options
10361 * @return {Roo.Element} The Element
10363 switchOff : function(o){
10364 var el = this.getFxEl();
10367 el.queueFx(o, function(){
10368 this.clearOpacity();
10371 // restore values after effect
10372 var r = this.getFxRestore();
10373 var st = this.dom.style;
10375 var after = function(){
10377 el.setDisplayed(false);
10383 el.setPositioning(r.pos);
10384 st.width = r.width;
10385 st.height = r.height;
10390 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10391 this.clearOpacity();
10395 points:{by:[0, this.getHeight() * .5]}
10396 }, o, 'motion', 0.3, 'easeIn', after);
10397 }).defer(100, this);
10404 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10405 * changed using the "attr" config option) and then fading back to the original color. If no original
10406 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10409 // default: highlight background to yellow
10412 // custom: highlight foreground text to blue for 2 seconds
10413 el.highlight("0000ff", { attr: 'color', duration: 2 });
10415 // common config options shown with default values
10416 el.highlight("ffff9c", {
10417 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10418 endColor: (current color) or "ffffff",
10423 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10424 * @param {Object} options (optional) Object literal with any of the Fx config options
10425 * @return {Roo.Element} The Element
10427 highlight : function(color, o){
10428 var el = this.getFxEl();
10431 el.queueFx(o, function(){
10432 color = color || "ffff9c";
10433 attr = o.attr || "backgroundColor";
10435 this.clearOpacity();
10438 var origColor = this.getColor(attr);
10439 var restoreColor = this.dom.style[attr];
10440 endColor = (o.endColor || origColor) || "ffffff";
10442 var after = function(){
10443 el.dom.style[attr] = restoreColor;
10448 a[attr] = {from: color, to: endColor};
10449 arguments.callee.anim = this.fxanim(a,
10459 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10462 // default: a single light blue ripple
10465 // custom: 3 red ripples lasting 3 seconds total
10466 el.frame("ff0000", 3, { duration: 3 });
10468 // common config options shown with default values
10469 el.frame("C3DAF9", 1, {
10470 duration: 1 //duration of entire animation (not each individual ripple)
10471 // Note: Easing is not configurable and will be ignored if included
10474 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10475 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10476 * @param {Object} options (optional) Object literal with any of the Fx config options
10477 * @return {Roo.Element} The Element
10479 frame : function(color, count, o){
10480 var el = this.getFxEl();
10483 el.queueFx(o, function(){
10484 color = color || "#C3DAF9";
10485 if(color.length == 6){
10486 color = "#" + color;
10488 count = count || 1;
10489 duration = o.duration || 1;
10492 var b = this.getBox();
10493 var animFn = function(){
10494 var proxy = this.createProxy({
10497 visbility:"hidden",
10498 position:"absolute",
10499 "z-index":"35000", // yee haw
10500 border:"0px solid " + color
10503 var scale = Roo.isBorderBox ? 2 : 1;
10505 top:{from:b.y, to:b.y - 20},
10506 left:{from:b.x, to:b.x - 20},
10507 borderWidth:{from:0, to:10},
10508 opacity:{from:1, to:0},
10509 height:{from:b.height, to:(b.height + (20*scale))},
10510 width:{from:b.width, to:(b.width + (20*scale))}
10511 }, duration, function(){
10515 animFn.defer((duration/2)*1000, this);
10526 * Creates a pause before any subsequent queued effects begin. If there are
10527 * no effects queued after the pause it will have no effect.
10532 * @param {Number} seconds The length of time to pause (in seconds)
10533 * @return {Roo.Element} The Element
10535 pause : function(seconds){
10536 var el = this.getFxEl();
10539 el.queueFx(o, function(){
10540 setTimeout(function(){
10542 }, seconds * 1000);
10548 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10549 * using the "endOpacity" config option.
10552 // default: fade in from opacity 0 to 100%
10555 // custom: fade in from opacity 0 to 75% over 2 seconds
10556 el.fadeIn({ endOpacity: .75, duration: 2});
10558 // common config options shown with default values
10560 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10565 * @param {Object} options (optional) Object literal with any of the Fx config options
10566 * @return {Roo.Element} The Element
10568 fadeIn : function(o){
10569 var el = this.getFxEl();
10571 el.queueFx(o, function(){
10572 this.setOpacity(0);
10574 this.dom.style.visibility = 'visible';
10575 var to = o.endOpacity || 1;
10576 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10577 o, null, .5, "easeOut", function(){
10579 this.clearOpacity();
10588 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10589 * using the "endOpacity" config option.
10592 // default: fade out from the element's current opacity to 0
10595 // custom: fade out from the element's current opacity to 25% over 2 seconds
10596 el.fadeOut({ endOpacity: .25, duration: 2});
10598 // common config options shown with default values
10600 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10607 * @param {Object} options (optional) Object literal with any of the Fx config options
10608 * @return {Roo.Element} The Element
10610 fadeOut : function(o){
10611 var el = this.getFxEl();
10613 el.queueFx(o, function(){
10614 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10615 o, null, .5, "easeOut", function(){
10616 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10617 this.dom.style.display = "none";
10619 this.dom.style.visibility = "hidden";
10621 this.clearOpacity();
10629 * Animates the transition of an element's dimensions from a starting height/width
10630 * to an ending height/width.
10633 // change height and width to 100x100 pixels
10634 el.scale(100, 100);
10636 // common config options shown with default values. The height and width will default to
10637 // the element's existing values if passed as null.
10640 [element's height], {
10645 * @param {Number} width The new width (pass undefined to keep the original width)
10646 * @param {Number} height The new height (pass undefined to keep the original height)
10647 * @param {Object} options (optional) Object literal with any of the Fx config options
10648 * @return {Roo.Element} The Element
10650 scale : function(w, h, o){
10651 this.shift(Roo.apply({}, o, {
10659 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10660 * Any of these properties not specified in the config object will not be changed. This effect
10661 * requires that at least one new dimension, position or opacity setting must be passed in on
10662 * the config object in order for the function to have any effect.
10665 // slide the element horizontally to x position 200 while changing the height and opacity
10666 el.shift({ x: 200, height: 50, opacity: .8 });
10668 // common config options shown with default values.
10670 width: [element's width],
10671 height: [element's height],
10672 x: [element's x position],
10673 y: [element's y position],
10674 opacity: [element's opacity],
10679 * @param {Object} options Object literal with any of the Fx config options
10680 * @return {Roo.Element} The Element
10682 shift : function(o){
10683 var el = this.getFxEl();
10685 el.queueFx(o, function(){
10686 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10687 if(w !== undefined){
10688 a.width = {to: this.adjustWidth(w)};
10690 if(h !== undefined){
10691 a.height = {to: this.adjustHeight(h)};
10693 if(x !== undefined || y !== undefined){
10695 x !== undefined ? x : this.getX(),
10696 y !== undefined ? y : this.getY()
10699 if(op !== undefined){
10700 a.opacity = {to: op};
10702 if(o.xy !== undefined){
10703 a.points = {to: o.xy};
10705 arguments.callee.anim = this.fxanim(a,
10706 o, 'motion', .35, "easeOut", function(){
10714 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10715 * ending point of the effect.
10718 // default: slide the element downward while fading out
10721 // custom: slide the element out to the right with a 2-second duration
10722 el.ghost('r', { duration: 2 });
10724 // common config options shown with default values
10732 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10733 * @param {Object} options (optional) Object literal with any of the Fx config options
10734 * @return {Roo.Element} The Element
10736 ghost : function(anchor, o){
10737 var el = this.getFxEl();
10740 el.queueFx(o, function(){
10741 anchor = anchor || "b";
10743 // restore values after effect
10744 var r = this.getFxRestore();
10745 var w = this.getWidth(),
10746 h = this.getHeight();
10748 var st = this.dom.style;
10750 var after = function(){
10752 el.setDisplayed(false);
10758 el.setPositioning(r.pos);
10759 st.width = r.width;
10760 st.height = r.height;
10765 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10766 switch(anchor.toLowerCase()){
10793 arguments.callee.anim = this.fxanim(a,
10803 * Ensures that all effects queued after syncFx is called on the element are
10804 * run concurrently. This is the opposite of {@link #sequenceFx}.
10805 * @return {Roo.Element} The Element
10807 syncFx : function(){
10808 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10817 * Ensures that all effects queued after sequenceFx is called on the element are
10818 * run in sequence. This is the opposite of {@link #syncFx}.
10819 * @return {Roo.Element} The Element
10821 sequenceFx : function(){
10822 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10824 concurrent : false,
10831 nextFx : function(){
10832 var ef = this.fxQueue[0];
10839 * Returns true if the element has any effects actively running or queued, else returns false.
10840 * @return {Boolean} True if element has active effects, else false
10842 hasActiveFx : function(){
10843 return this.fxQueue && this.fxQueue[0];
10847 * Stops any running effects and clears the element's internal effects queue if it contains
10848 * any additional effects that haven't started yet.
10849 * @return {Roo.Element} The Element
10851 stopFx : function(){
10852 if(this.hasActiveFx()){
10853 var cur = this.fxQueue[0];
10854 if(cur && cur.anim && cur.anim.isAnimated()){
10855 this.fxQueue = [cur]; // clear out others
10856 cur.anim.stop(true);
10863 beforeFx : function(o){
10864 if(this.hasActiveFx() && !o.concurrent){
10875 * Returns true if the element is currently blocking so that no other effect can be queued
10876 * until this effect is finished, else returns false if blocking is not set. This is commonly
10877 * used to ensure that an effect initiated by a user action runs to completion prior to the
10878 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10879 * @return {Boolean} True if blocking, else false
10881 hasFxBlock : function(){
10882 var q = this.fxQueue;
10883 return q && q[0] && q[0].block;
10887 queueFx : function(o, fn){
10891 if(!this.hasFxBlock()){
10892 Roo.applyIf(o, this.fxDefaults);
10894 var run = this.beforeFx(o);
10895 fn.block = o.block;
10896 this.fxQueue.push(fn);
10908 fxWrap : function(pos, o, vis){
10910 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10913 wrapXY = this.getXY();
10915 var div = document.createElement("div");
10916 div.style.visibility = vis;
10917 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10918 wrap.setPositioning(pos);
10919 if(wrap.getStyle("position") == "static"){
10920 wrap.position("relative");
10922 this.clearPositioning('auto');
10924 wrap.dom.appendChild(this.dom);
10926 wrap.setXY(wrapXY);
10933 fxUnwrap : function(wrap, pos, o){
10934 this.clearPositioning();
10935 this.setPositioning(pos);
10937 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10943 getFxRestore : function(){
10944 var st = this.dom.style;
10945 return {pos: this.getPositioning(), width: st.width, height : st.height};
10949 afterFx : function(o){
10951 this.applyStyles(o.afterStyle);
10954 this.addClass(o.afterCls);
10956 if(o.remove === true){
10959 Roo.callback(o.callback, o.scope, [this]);
10961 this.fxQueue.shift();
10967 getFxEl : function(){ // support for composite element fx
10968 return Roo.get(this.dom);
10972 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10973 animType = animType || 'run';
10975 var anim = Roo.lib.Anim[animType](
10977 (opt.duration || defaultDur) || .35,
10978 (opt.easing || defaultEase) || 'easeOut',
10980 Roo.callback(cb, this);
10989 // backwords compat
10990 Roo.Fx.resize = Roo.Fx.scale;
10992 //When included, Roo.Fx is automatically applied to Element so that all basic
10993 //effects are available directly via the Element API
10994 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10996 * Ext JS Library 1.1.1
10997 * Copyright(c) 2006-2007, Ext JS, LLC.
10999 * Originally Released Under LGPL - original licence link has changed is not relivant.
11002 * <script type="text/javascript">
11007 * @class Roo.CompositeElement
11008 * Standard composite class. Creates a Roo.Element for every element in the collection.
11010 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11011 * actions will be performed on all the elements in this collection.</b>
11013 * All methods return <i>this</i> and can be chained.
11015 var els = Roo.select("#some-el div.some-class", true);
11016 // or select directly from an existing element
11017 var el = Roo.get('some-el');
11018 el.select('div.some-class', true);
11020 els.setWidth(100); // all elements become 100 width
11021 els.hide(true); // all elements fade out and hide
11023 els.setWidth(100).hide(true);
11026 Roo.CompositeElement = function(els){
11027 this.elements = [];
11028 this.addElements(els);
11030 Roo.CompositeElement.prototype = {
11032 addElements : function(els){
11033 if(!els) return this;
11034 if(typeof els == "string"){
11035 els = Roo.Element.selectorFunction(els);
11037 var yels = this.elements;
11038 var index = yels.length-1;
11039 for(var i = 0, len = els.length; i < len; i++) {
11040 yels[++index] = Roo.get(els[i]);
11046 * Clears this composite and adds the elements returned by the passed selector.
11047 * @param {String/Array} els A string CSS selector, an array of elements or an element
11048 * @return {CompositeElement} this
11050 fill : function(els){
11051 this.elements = [];
11057 * Filters this composite to only elements that match the passed selector.
11058 * @param {String} selector A string CSS selector
11059 * @return {CompositeElement} this
11061 filter : function(selector){
11063 this.each(function(el){
11064 if(el.is(selector)){
11065 els[els.length] = el.dom;
11072 invoke : function(fn, args){
11073 var els = this.elements;
11074 for(var i = 0, len = els.length; i < len; i++) {
11075 Roo.Element.prototype[fn].apply(els[i], args);
11080 * Adds elements to this composite.
11081 * @param {String/Array} els A string CSS selector, an array of elements or an element
11082 * @return {CompositeElement} this
11084 add : function(els){
11085 if(typeof els == "string"){
11086 this.addElements(Roo.Element.selectorFunction(els));
11087 }else if(els.length !== undefined){
11088 this.addElements(els);
11090 this.addElements([els]);
11095 * Calls the passed function passing (el, this, index) for each element in this composite.
11096 * @param {Function} fn The function to call
11097 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11098 * @return {CompositeElement} this
11100 each : function(fn, scope){
11101 var els = this.elements;
11102 for(var i = 0, len = els.length; i < len; i++){
11103 if(fn.call(scope || els[i], els[i], this, i) === false) {
11111 * Returns the Element object at the specified index
11112 * @param {Number} index
11113 * @return {Roo.Element}
11115 item : function(index){
11116 return this.elements[index] || null;
11120 * Returns the first Element
11121 * @return {Roo.Element}
11123 first : function(){
11124 return this.item(0);
11128 * Returns the last Element
11129 * @return {Roo.Element}
11132 return this.item(this.elements.length-1);
11136 * Returns the number of elements in this composite
11139 getCount : function(){
11140 return this.elements.length;
11144 * Returns true if this composite contains the passed element
11147 contains : function(el){
11148 return this.indexOf(el) !== -1;
11152 * Returns true if this composite contains the passed element
11155 indexOf : function(el){
11156 return this.elements.indexOf(Roo.get(el));
11161 * Removes the specified element(s).
11162 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11163 * or an array of any of those.
11164 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11165 * @return {CompositeElement} this
11167 removeElement : function(el, removeDom){
11168 if(el instanceof Array){
11169 for(var i = 0, len = el.length; i < len; i++){
11170 this.removeElement(el[i]);
11174 var index = typeof el == 'number' ? el : this.indexOf(el);
11177 var d = this.elements[index];
11181 d.parentNode.removeChild(d);
11184 this.elements.splice(index, 1);
11190 * Replaces the specified element with the passed element.
11191 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11193 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11194 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11195 * @return {CompositeElement} this
11197 replaceElement : function(el, replacement, domReplace){
11198 var index = typeof el == 'number' ? el : this.indexOf(el);
11201 this.elements[index].replaceWith(replacement);
11203 this.elements.splice(index, 1, Roo.get(replacement))
11210 * Removes all elements.
11212 clear : function(){
11213 this.elements = [];
11217 Roo.CompositeElement.createCall = function(proto, fnName){
11218 if(!proto[fnName]){
11219 proto[fnName] = function(){
11220 return this.invoke(fnName, arguments);
11224 for(var fnName in Roo.Element.prototype){
11225 if(typeof Roo.Element.prototype[fnName] == "function"){
11226 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11232 * Ext JS Library 1.1.1
11233 * Copyright(c) 2006-2007, Ext JS, LLC.
11235 * Originally Released Under LGPL - original licence link has changed is not relivant.
11238 * <script type="text/javascript">
11242 * @class Roo.CompositeElementLite
11243 * @extends Roo.CompositeElement
11244 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11246 var els = Roo.select("#some-el div.some-class");
11247 // or select directly from an existing element
11248 var el = Roo.get('some-el');
11249 el.select('div.some-class');
11251 els.setWidth(100); // all elements become 100 width
11252 els.hide(true); // all elements fade out and hide
11254 els.setWidth(100).hide(true);
11255 </code></pre><br><br>
11256 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11257 * actions will be performed on all the elements in this collection.</b>
11259 Roo.CompositeElementLite = function(els){
11260 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11261 this.el = new Roo.Element.Flyweight();
11263 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11264 addElements : function(els){
11266 if(els instanceof Array){
11267 this.elements = this.elements.concat(els);
11269 var yels = this.elements;
11270 var index = yels.length-1;
11271 for(var i = 0, len = els.length; i < len; i++) {
11272 yels[++index] = els[i];
11278 invoke : function(fn, args){
11279 var els = this.elements;
11281 for(var i = 0, len = els.length; i < len; i++) {
11283 Roo.Element.prototype[fn].apply(el, args);
11288 * Returns a flyweight Element of the dom element object at the specified index
11289 * @param {Number} index
11290 * @return {Roo.Element}
11292 item : function(index){
11293 if(!this.elements[index]){
11296 this.el.dom = this.elements[index];
11300 // fixes scope with flyweight
11301 addListener : function(eventName, handler, scope, opt){
11302 var els = this.elements;
11303 for(var i = 0, len = els.length; i < len; i++) {
11304 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11310 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11311 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11312 * a reference to the dom node, use el.dom.</b>
11313 * @param {Function} fn The function to call
11314 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11315 * @return {CompositeElement} this
11317 each : function(fn, scope){
11318 var els = this.elements;
11320 for(var i = 0, len = els.length; i < len; i++){
11322 if(fn.call(scope || el, el, this, i) === false){
11329 indexOf : function(el){
11330 return this.elements.indexOf(Roo.getDom(el));
11333 replaceElement : function(el, replacement, domReplace){
11334 var index = typeof el == 'number' ? el : this.indexOf(el);
11336 replacement = Roo.getDom(replacement);
11338 var d = this.elements[index];
11339 d.parentNode.insertBefore(replacement, d);
11340 d.parentNode.removeChild(d);
11342 this.elements.splice(index, 1, replacement);
11347 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11351 * Ext JS Library 1.1.1
11352 * Copyright(c) 2006-2007, Ext JS, LLC.
11354 * Originally Released Under LGPL - original licence link has changed is not relivant.
11357 * <script type="text/javascript">
11363 * @class Roo.data.Connection
11364 * @extends Roo.util.Observable
11365 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11366 * either to a configured URL, or to a URL specified at request time.<br><br>
11368 * Requests made by this class are asynchronous, and will return immediately. No data from
11369 * the server will be available to the statement immediately following the {@link #request} call.
11370 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11372 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11373 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11374 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11375 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11376 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11377 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11378 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11379 * standard DOM methods.
11381 * @param {Object} config a configuration object.
11383 Roo.data.Connection = function(config){
11384 Roo.apply(this, config);
11387 * @event beforerequest
11388 * Fires before a network request is made to retrieve a data object.
11389 * @param {Connection} conn This Connection object.
11390 * @param {Object} options The options config object passed to the {@link #request} method.
11392 "beforerequest" : true,
11394 * @event requestcomplete
11395 * Fires if the request was successfully completed.
11396 * @param {Connection} conn This Connection object.
11397 * @param {Object} response The XHR object containing the response data.
11398 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11399 * @param {Object} options The options config object passed to the {@link #request} method.
11401 "requestcomplete" : true,
11403 * @event requestexception
11404 * Fires if an error HTTP status was returned from the server.
11405 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11406 * @param {Connection} conn This Connection object.
11407 * @param {Object} response The XHR object containing the response data.
11408 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11409 * @param {Object} options The options config object passed to the {@link #request} method.
11411 "requestexception" : true
11413 Roo.data.Connection.superclass.constructor.call(this);
11416 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11418 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11421 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11422 * extra parameters to each request made by this object. (defaults to undefined)
11425 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11426 * to each request made by this object. (defaults to undefined)
11429 * @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)
11432 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11436 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11442 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11445 disableCaching: true,
11448 * Sends an HTTP request to a remote server.
11449 * @param {Object} options An object which may contain the following properties:<ul>
11450 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11451 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11452 * request, a url encoded string or a function to call to get either.</li>
11453 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11454 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11455 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11456 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11457 * <li>options {Object} The parameter to the request call.</li>
11458 * <li>success {Boolean} True if the request succeeded.</li>
11459 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11461 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11462 * The callback is passed the following parameters:<ul>
11463 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11464 * <li>options {Object} The parameter to the request call.</li>
11466 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11467 * The callback is passed the following parameters:<ul>
11468 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11469 * <li>options {Object} The parameter to the request call.</li>
11471 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11472 * for the callback function. Defaults to the browser window.</li>
11473 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11474 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11475 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11476 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11477 * params for the post data. Any params will be appended to the URL.</li>
11478 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11480 * @return {Number} transactionId
11482 request : function(o){
11483 if(this.fireEvent("beforerequest", this, o) !== false){
11486 if(typeof p == "function"){
11487 p = p.call(o.scope||window, o);
11489 if(typeof p == "object"){
11490 p = Roo.urlEncode(o.params);
11492 if(this.extraParams){
11493 var extras = Roo.urlEncode(this.extraParams);
11494 p = p ? (p + '&' + extras) : extras;
11497 var url = o.url || this.url;
11498 if(typeof url == 'function'){
11499 url = url.call(o.scope||window, o);
11503 var form = Roo.getDom(o.form);
11504 url = url || form.action;
11506 var enctype = form.getAttribute("enctype");
11507 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11508 return this.doFormUpload(o, p, url);
11510 var f = Roo.lib.Ajax.serializeForm(form);
11511 p = p ? (p + '&' + f) : f;
11514 var hs = o.headers;
11515 if(this.defaultHeaders){
11516 hs = Roo.apply(hs || {}, this.defaultHeaders);
11523 success: this.handleResponse,
11524 failure: this.handleFailure,
11526 argument: {options: o},
11527 timeout : o.timeout || this.timeout
11530 var method = o.method||this.method||(p ? "POST" : "GET");
11532 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11533 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11536 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11540 }else if(this.autoAbort !== false){
11544 if((method == 'GET' && p) || o.xmlData){
11545 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11548 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11549 return this.transId;
11551 Roo.callback(o.callback, o.scope, [o, null, null]);
11557 * Determine whether this object has a request outstanding.
11558 * @param {Number} transactionId (Optional) defaults to the last transaction
11559 * @return {Boolean} True if there is an outstanding request.
11561 isLoading : function(transId){
11563 return Roo.lib.Ajax.isCallInProgress(transId);
11565 return this.transId ? true : false;
11570 * Aborts any outstanding request.
11571 * @param {Number} transactionId (Optional) defaults to the last transaction
11573 abort : function(transId){
11574 if(transId || this.isLoading()){
11575 Roo.lib.Ajax.abort(transId || this.transId);
11580 handleResponse : function(response){
11581 this.transId = false;
11582 var options = response.argument.options;
11583 response.argument = options ? options.argument : null;
11584 this.fireEvent("requestcomplete", this, response, options);
11585 Roo.callback(options.success, options.scope, [response, options]);
11586 Roo.callback(options.callback, options.scope, [options, true, response]);
11590 handleFailure : function(response, e){
11591 this.transId = false;
11592 var options = response.argument.options;
11593 response.argument = options ? options.argument : null;
11594 this.fireEvent("requestexception", this, response, options, e);
11595 Roo.callback(options.failure, options.scope, [response, options]);
11596 Roo.callback(options.callback, options.scope, [options, false, response]);
11600 doFormUpload : function(o, ps, url){
11602 var frame = document.createElement('iframe');
11605 frame.className = 'x-hidden';
11607 frame.src = Roo.SSL_SECURE_URL;
11609 document.body.appendChild(frame);
11612 document.frames[id].name = id;
11615 var form = Roo.getDom(o.form);
11617 form.method = 'POST';
11618 form.enctype = form.encoding = 'multipart/form-data';
11624 if(ps){ // add dynamic params
11626 ps = Roo.urlDecode(ps, false);
11628 if(ps.hasOwnProperty(k)){
11629 hd = document.createElement('input');
11630 hd.type = 'hidden';
11633 form.appendChild(hd);
11640 var r = { // bogus response object
11645 r.argument = o ? o.argument : null;
11650 doc = frame.contentWindow.document;
11652 doc = (frame.contentDocument || window.frames[id].document);
11654 if(doc && doc.body){
11655 r.responseText = doc.body.innerHTML;
11657 if(doc && doc.XMLDocument){
11658 r.responseXML = doc.XMLDocument;
11660 r.responseXML = doc;
11667 Roo.EventManager.removeListener(frame, 'load', cb, this);
11669 this.fireEvent("requestcomplete", this, r, o);
11670 Roo.callback(o.success, o.scope, [r, o]);
11671 Roo.callback(o.callback, o.scope, [o, true, r]);
11673 setTimeout(function(){document.body.removeChild(frame);}, 100);
11676 Roo.EventManager.on(frame, 'load', cb, this);
11679 if(hiddens){ // remove dynamic params
11680 for(var i = 0, len = hiddens.length; i < len; i++){
11681 form.removeChild(hiddens[i]);
11688 * Ext JS Library 1.1.1
11689 * Copyright(c) 2006-2007, Ext JS, LLC.
11691 * Originally Released Under LGPL - original licence link has changed is not relivant.
11694 * <script type="text/javascript">
11698 * Global Ajax request class.
11701 * @extends Roo.data.Connection
11704 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11705 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11706 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11707 * @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)
11708 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11709 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11710 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11712 Roo.Ajax = new Roo.data.Connection({
11721 * Serialize the passed form into a url encoded string
11723 * @param {String/HTMLElement} form
11726 serializeForm : function(form){
11727 return Roo.lib.Ajax.serializeForm(form);
11731 * Ext JS Library 1.1.1
11732 * Copyright(c) 2006-2007, Ext JS, LLC.
11734 * Originally Released Under LGPL - original licence link has changed is not relivant.
11737 * <script type="text/javascript">
11742 * @class Roo.UpdateManager
11743 * @extends Roo.util.Observable
11744 * Provides AJAX-style update for Element object.<br><br>
11747 * // Get it from a Roo.Element object
11748 * var el = Roo.get("foo");
11749 * var mgr = el.getUpdateManager();
11750 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11752 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11754 * // or directly (returns the same UpdateManager instance)
11755 * var mgr = new Roo.UpdateManager("myElementId");
11756 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11757 * mgr.on("update", myFcnNeedsToKnow);
11759 // short handed call directly from the element object
11760 Roo.get("foo").load({
11764 text: "Loading Foo..."
11768 * Create new UpdateManager directly.
11769 * @param {String/HTMLElement/Roo.Element} el The element to update
11770 * @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).
11772 Roo.UpdateManager = function(el, forceNew){
11774 if(!forceNew && el.updateManager){
11775 return el.updateManager;
11778 * The Element object
11779 * @type Roo.Element
11783 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11786 this.defaultUrl = null;
11790 * @event beforeupdate
11791 * Fired before an update is made, return false from your handler and the update is cancelled.
11792 * @param {Roo.Element} el
11793 * @param {String/Object/Function} url
11794 * @param {String/Object} params
11796 "beforeupdate": true,
11799 * Fired after successful update is made.
11800 * @param {Roo.Element} el
11801 * @param {Object} oResponseObject The response Object
11806 * Fired on update failure.
11807 * @param {Roo.Element} el
11808 * @param {Object} oResponseObject The response Object
11812 var d = Roo.UpdateManager.defaults;
11814 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11817 this.sslBlankUrl = d.sslBlankUrl;
11819 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11822 this.disableCaching = d.disableCaching;
11824 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11827 this.indicatorText = d.indicatorText;
11829 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11832 this.showLoadIndicator = d.showLoadIndicator;
11834 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11837 this.timeout = d.timeout;
11840 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11843 this.loadScripts = d.loadScripts;
11846 * Transaction object of current executing transaction
11848 this.transaction = null;
11853 this.autoRefreshProcId = null;
11855 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11858 this.refreshDelegate = this.refresh.createDelegate(this);
11860 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11863 this.updateDelegate = this.update.createDelegate(this);
11865 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11868 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11872 this.successDelegate = this.processSuccess.createDelegate(this);
11876 this.failureDelegate = this.processFailure.createDelegate(this);
11878 if(!this.renderer){
11880 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11882 this.renderer = new Roo.UpdateManager.BasicRenderer();
11885 Roo.UpdateManager.superclass.constructor.call(this);
11888 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11890 * Get the Element this UpdateManager is bound to
11891 * @return {Roo.Element} The element
11893 getEl : function(){
11897 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11898 * @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:
11901 url: "your-url.php",<br/>
11902 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11903 callback: yourFunction,<br/>
11904 scope: yourObject, //(optional scope) <br/>
11905 discardUrl: false, <br/>
11906 nocache: false,<br/>
11907 text: "Loading...",<br/>
11909 scripts: false<br/>
11912 * The only required property is url. The optional properties nocache, text and scripts
11913 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11914 * @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}
11915 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11916 * @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.
11918 update : function(url, params, callback, discardUrl){
11919 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11920 var method = this.method,
11922 if(typeof url == "object"){ // must be config object
11925 params = params || cfg.params;
11926 callback = callback || cfg.callback;
11927 discardUrl = discardUrl || cfg.discardUrl;
11928 if(callback && cfg.scope){
11929 callback = callback.createDelegate(cfg.scope);
11931 if(typeof cfg.method != "undefined"){method = cfg.method;};
11932 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11933 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11934 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11935 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11937 this.showLoading();
11939 this.defaultUrl = url;
11941 if(typeof url == "function"){
11942 url = url.call(this);
11945 method = method || (params ? "POST" : "GET");
11946 if(method == "GET"){
11947 url = this.prepareUrl(url);
11950 var o = Roo.apply(cfg ||{}, {
11953 success: this.successDelegate,
11954 failure: this.failureDelegate,
11955 callback: undefined,
11956 timeout: (this.timeout*1000),
11957 argument: {"url": url, "form": null, "callback": callback, "params": params}
11959 Roo.log("updated manager called with timeout of " + o.timeout);
11960 this.transaction = Roo.Ajax.request(o);
11965 * 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.
11966 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11967 * @param {String/HTMLElement} form The form Id or form element
11968 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11969 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11970 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11972 formUpdate : function(form, url, reset, callback){
11973 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11974 if(typeof url == "function"){
11975 url = url.call(this);
11977 form = Roo.getDom(form);
11978 this.transaction = Roo.Ajax.request({
11981 success: this.successDelegate,
11982 failure: this.failureDelegate,
11983 timeout: (this.timeout*1000),
11984 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11986 this.showLoading.defer(1, this);
11991 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11992 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11994 refresh : function(callback){
11995 if(this.defaultUrl == null){
11998 this.update(this.defaultUrl, null, callback, true);
12002 * Set this element to auto refresh.
12003 * @param {Number} interval How often to update (in seconds).
12004 * @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)
12005 * @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}
12006 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12007 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12009 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12011 this.update(url || this.defaultUrl, params, callback, true);
12013 if(this.autoRefreshProcId){
12014 clearInterval(this.autoRefreshProcId);
12016 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12020 * Stop auto refresh on this element.
12022 stopAutoRefresh : function(){
12023 if(this.autoRefreshProcId){
12024 clearInterval(this.autoRefreshProcId);
12025 delete this.autoRefreshProcId;
12029 isAutoRefreshing : function(){
12030 return this.autoRefreshProcId ? true : false;
12033 * Called to update the element to "Loading" state. Override to perform custom action.
12035 showLoading : function(){
12036 if(this.showLoadIndicator){
12037 this.el.update(this.indicatorText);
12042 * Adds unique parameter to query string if disableCaching = true
12045 prepareUrl : function(url){
12046 if(this.disableCaching){
12047 var append = "_dc=" + (new Date().getTime());
12048 if(url.indexOf("?") !== -1){
12049 url += "&" + append;
12051 url += "?" + append;
12060 processSuccess : function(response){
12061 this.transaction = null;
12062 if(response.argument.form && response.argument.reset){
12063 try{ // put in try/catch since some older FF releases had problems with this
12064 response.argument.form.reset();
12067 if(this.loadScripts){
12068 this.renderer.render(this.el, response, this,
12069 this.updateComplete.createDelegate(this, [response]));
12071 this.renderer.render(this.el, response, this);
12072 this.updateComplete(response);
12076 updateComplete : function(response){
12077 this.fireEvent("update", this.el, response);
12078 if(typeof response.argument.callback == "function"){
12079 response.argument.callback(this.el, true, response);
12086 processFailure : function(response){
12087 this.transaction = null;
12088 this.fireEvent("failure", this.el, response);
12089 if(typeof response.argument.callback == "function"){
12090 response.argument.callback(this.el, false, response);
12095 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12096 * @param {Object} renderer The object implementing the render() method
12098 setRenderer : function(renderer){
12099 this.renderer = renderer;
12102 getRenderer : function(){
12103 return this.renderer;
12107 * Set the defaultUrl used for updates
12108 * @param {String/Function} defaultUrl The url or a function to call to get the url
12110 setDefaultUrl : function(defaultUrl){
12111 this.defaultUrl = defaultUrl;
12115 * Aborts the executing transaction
12117 abort : function(){
12118 if(this.transaction){
12119 Roo.Ajax.abort(this.transaction);
12124 * Returns true if an update is in progress
12125 * @return {Boolean}
12127 isUpdating : function(){
12128 if(this.transaction){
12129 return Roo.Ajax.isLoading(this.transaction);
12136 * @class Roo.UpdateManager.defaults
12137 * @static (not really - but it helps the doc tool)
12138 * The defaults collection enables customizing the default properties of UpdateManager
12140 Roo.UpdateManager.defaults = {
12142 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12148 * True to process scripts by default (Defaults to false).
12151 loadScripts : false,
12154 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12157 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12159 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12162 disableCaching : false,
12164 * Whether to show indicatorText when loading (Defaults to true).
12167 showLoadIndicator : true,
12169 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12172 indicatorText : '<div class="loading-indicator">Loading...</div>'
12176 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12178 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12179 * @param {String/HTMLElement/Roo.Element} el The element to update
12180 * @param {String} url The url
12181 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12182 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12185 * @member Roo.UpdateManager
12187 Roo.UpdateManager.updateElement = function(el, url, params, options){
12188 var um = Roo.get(el, true).getUpdateManager();
12189 Roo.apply(um, options);
12190 um.update(url, params, options ? options.callback : null);
12192 // alias for backwards compat
12193 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12195 * @class Roo.UpdateManager.BasicRenderer
12196 * Default Content renderer. Updates the elements innerHTML with the responseText.
12198 Roo.UpdateManager.BasicRenderer = function(){};
12200 Roo.UpdateManager.BasicRenderer.prototype = {
12202 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12203 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12204 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12205 * @param {Roo.Element} el The element being rendered
12206 * @param {Object} response The YUI Connect response object
12207 * @param {UpdateManager} updateManager The calling update manager
12208 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12210 render : function(el, response, updateManager, callback){
12211 el.update(response.responseText, updateManager.loadScripts, callback);
12217 * (c)) Alan Knowles
12223 * @class Roo.DomTemplate
12224 * @extends Roo.Template
12225 * An effort at a dom based template engine..
12227 * Similar to XTemplate, except it uses dom parsing to create the template..
12229 * Supported features:
12234 {a_variable} - output encoded.
12235 {a_variable.format:("Y-m-d")} - call a method on the variable
12236 {a_variable:raw} - unencoded output
12237 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12238 {a_variable:this.method_on_template(...)} - call a method on the template object.
12243 <div roo-for="a_variable or condition.."></div>
12244 <div roo-if="a_variable or condition"></div>
12245 <div roo-exec="some javascript"></div>
12246 <div roo-name="named_template"></div>
12251 Roo.DomTemplate = function()
12253 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12260 Roo.extend(Roo.DomTemplate, Roo.Template, {
12262 * id counter for sub templates.
12266 * flag to indicate if dom parser is inside a pre,
12267 * it will strip whitespace if not.
12272 * The various sub templates
12280 * basic tag replacing syntax
12283 * // you can fake an object call by doing this
12287 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12288 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12290 iterChild : function (node, method) {
12292 var oldPre = this.inPre;
12293 if (node.tagName == 'PRE') {
12296 for( var i = 0; i < node.childNodes.length; i++) {
12297 method.call(this, node.childNodes[i]);
12299 this.inPre = oldPre;
12305 * compile the template
12307 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12310 compile: function()
12314 // covert the html into DOM...
12318 doc = document.implementation.createHTMLDocument("");
12319 doc.documentElement.innerHTML = this.html ;
12320 div = doc.documentElement;
12322 // old IE... - nasty -- it causes all sorts of issues.. with
12323 // images getting pulled from server..
12324 div = document.createElement('div');
12325 div.innerHTML = this.html;
12327 //doc.documentElement.innerHTML = htmlBody
12333 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12335 var tpls = this.tpls;
12337 // create a top level template from the snippet..
12339 //Roo.log(div.innerHTML);
12346 body : div.innerHTML,
12359 Roo.each(tpls, function(tp){
12360 this.compileTpl(tp);
12361 this.tpls[tp.id] = tp;
12364 this.master = tpls[0];
12370 compileNode : function(node, istop) {
12375 // skip anything not a tag..
12376 if (node.nodeType != 1) {
12377 if (node.nodeType == 3 && !this.inPre) {
12378 // reduce white space..
12379 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12402 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12403 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12404 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12405 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12411 // just itterate children..
12412 this.iterChild(node,this.compileNode);
12415 tpl.uid = this.id++;
12416 tpl.value = node.getAttribute('roo-' + tpl.attr);
12417 node.removeAttribute('roo-'+ tpl.attr);
12418 if (tpl.attr != 'name') {
12419 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12420 node.parentNode.replaceChild(placeholder, node);
12423 var placeholder = document.createElement('span');
12424 placeholder.className = 'roo-tpl-' + tpl.value;
12425 node.parentNode.replaceChild(placeholder, node);
12428 // parent now sees '{domtplXXXX}
12429 this.iterChild(node,this.compileNode);
12431 // we should now have node body...
12432 var div = document.createElement('div');
12433 div.appendChild(node);
12435 // this has the unfortunate side effect of converting tagged attributes
12436 // eg. href="{...}" into %7C...%7D
12437 // this has been fixed by searching for those combo's although it's a bit hacky..
12440 tpl.body = div.innerHTML;
12447 switch (tpl.value) {
12448 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12449 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12450 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12455 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12459 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12463 tpl.id = tpl.value; // replace non characters???
12469 this.tpls.push(tpl);
12479 * Compile a segment of the template into a 'sub-template'
12485 compileTpl : function(tpl)
12487 var fm = Roo.util.Format;
12488 var useF = this.disableFormats !== true;
12490 var sep = Roo.isGecko ? "+\n" : ",\n";
12492 var undef = function(str) {
12493 Roo.debug && Roo.log("Property not found :" + str);
12497 //Roo.log(tpl.body);
12501 var fn = function(m, lbrace, name, format, args)
12504 //Roo.log(arguments);
12505 args = args ? args.replace(/\\'/g,"'") : args;
12506 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12507 if (typeof(format) == 'undefined') {
12508 format = 'htmlEncode';
12510 if (format == 'raw' ) {
12514 if(name.substr(0, 6) == 'domtpl'){
12515 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12518 // build an array of options to determine if value is undefined..
12520 // basically get 'xxxx.yyyy' then do
12521 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12522 // (function () { Roo.log("Property not found"); return ''; })() :
12527 Roo.each(name.split('.'), function(st) {
12528 lookfor += (lookfor.length ? '.': '') + st;
12529 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12532 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12535 if(format && useF){
12537 args = args ? ',' + args : "";
12539 if(format.substr(0, 5) != "this."){
12540 format = "fm." + format + '(';
12542 format = 'this.call("'+ format.substr(5) + '", ';
12546 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12549 if (args && args.length) {
12550 // called with xxyx.yuu:(test,test)
12552 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12554 // raw.. - :raw modifier..
12555 return "'"+ sep + udef_st + name + ")"+sep+"'";
12559 // branched to use + in gecko and [].join() in others
12561 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12562 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12565 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12566 body.push(tpl.body.replace(/(\r\n|\n)/g,
12567 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12568 body.push("'].join('');};};");
12569 body = body.join('');
12572 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12574 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12581 * same as applyTemplate, except it's done to one of the subTemplates
12582 * when using named templates, you can do:
12584 * var str = pl.applySubTemplate('your-name', values);
12587 * @param {Number} id of the template
12588 * @param {Object} values to apply to template
12589 * @param {Object} parent (normaly the instance of this object)
12591 applySubTemplate : function(id, values, parent)
12595 var t = this.tpls[id];
12599 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12600 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12604 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12611 if(t.execCall && t.execCall.call(this, values, parent)){
12615 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12621 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12622 parent = t.target ? values : parent;
12623 if(t.forCall && vs instanceof Array){
12625 for(var i = 0, len = vs.length; i < len; i++){
12627 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12629 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12631 //Roo.log(t.compiled);
12635 return buf.join('');
12638 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12643 return t.compiled.call(this, vs, parent);
12645 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12647 //Roo.log(t.compiled);
12655 applyTemplate : function(values){
12656 return this.master.compiled.call(this, values, {});
12657 //var s = this.subs;
12660 apply : function(){
12661 return this.applyTemplate.apply(this, arguments);
12666 Roo.DomTemplate.from = function(el){
12667 el = Roo.getDom(el);
12668 return new Roo.Domtemplate(el.value || el.innerHTML);
12671 * Ext JS Library 1.1.1
12672 * Copyright(c) 2006-2007, Ext JS, LLC.
12674 * Originally Released Under LGPL - original licence link has changed is not relivant.
12677 * <script type="text/javascript">
12681 * @class Roo.util.DelayedTask
12682 * Provides a convenient method of performing setTimeout where a new
12683 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12684 * You can use this class to buffer
12685 * the keypress events for a certain number of milliseconds, and perform only if they stop
12686 * for that amount of time.
12687 * @constructor The parameters to this constructor serve as defaults and are not required.
12688 * @param {Function} fn (optional) The default function to timeout
12689 * @param {Object} scope (optional) The default scope of that timeout
12690 * @param {Array} args (optional) The default Array of arguments
12692 Roo.util.DelayedTask = function(fn, scope, args){
12693 var id = null, d, t;
12695 var call = function(){
12696 var now = new Date().getTime();
12700 fn.apply(scope, args || []);
12704 * Cancels any pending timeout and queues a new one
12705 * @param {Number} delay The milliseconds to delay
12706 * @param {Function} newFn (optional) Overrides function passed to constructor
12707 * @param {Object} newScope (optional) Overrides scope passed to constructor
12708 * @param {Array} newArgs (optional) Overrides args passed to constructor
12710 this.delay = function(delay, newFn, newScope, newArgs){
12711 if(id && delay != d){
12715 t = new Date().getTime();
12717 scope = newScope || scope;
12718 args = newArgs || args;
12720 id = setInterval(call, d);
12725 * Cancel the last queued timeout
12727 this.cancel = function(){
12735 * Ext JS Library 1.1.1
12736 * Copyright(c) 2006-2007, Ext JS, LLC.
12738 * Originally Released Under LGPL - original licence link has changed is not relivant.
12741 * <script type="text/javascript">
12745 Roo.util.TaskRunner = function(interval){
12746 interval = interval || 10;
12747 var tasks = [], removeQueue = [];
12749 var running = false;
12751 var stopThread = function(){
12757 var startThread = function(){
12760 id = setInterval(runTasks, interval);
12764 var removeTask = function(task){
12765 removeQueue.push(task);
12771 var runTasks = function(){
12772 if(removeQueue.length > 0){
12773 for(var i = 0, len = removeQueue.length; i < len; i++){
12774 tasks.remove(removeQueue[i]);
12777 if(tasks.length < 1){
12782 var now = new Date().getTime();
12783 for(var i = 0, len = tasks.length; i < len; ++i){
12785 var itime = now - t.taskRunTime;
12786 if(t.interval <= itime){
12787 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12788 t.taskRunTime = now;
12789 if(rt === false || t.taskRunCount === t.repeat){
12794 if(t.duration && t.duration <= (now - t.taskStartTime)){
12801 * Queues a new task.
12802 * @param {Object} task
12804 this.start = function(task){
12806 task.taskStartTime = new Date().getTime();
12807 task.taskRunTime = 0;
12808 task.taskRunCount = 0;
12813 this.stop = function(task){
12818 this.stopAll = function(){
12820 for(var i = 0, len = tasks.length; i < len; i++){
12821 if(tasks[i].onStop){
12830 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12832 * Ext JS Library 1.1.1
12833 * Copyright(c) 2006-2007, Ext JS, LLC.
12835 * Originally Released Under LGPL - original licence link has changed is not relivant.
12838 * <script type="text/javascript">
12843 * @class Roo.util.MixedCollection
12844 * @extends Roo.util.Observable
12845 * A Collection class that maintains both numeric indexes and keys and exposes events.
12847 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12848 * collection (defaults to false)
12849 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12850 * and return the key value for that item. This is used when available to look up the key on items that
12851 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12852 * equivalent to providing an implementation for the {@link #getKey} method.
12854 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12862 * Fires when the collection is cleared.
12867 * Fires when an item is added to the collection.
12868 * @param {Number} index The index at which the item was added.
12869 * @param {Object} o The item added.
12870 * @param {String} key The key associated with the added item.
12875 * Fires when an item is replaced in the collection.
12876 * @param {String} key he key associated with the new added.
12877 * @param {Object} old The item being replaced.
12878 * @param {Object} new The new item.
12883 * Fires when an item is removed from the collection.
12884 * @param {Object} o The item being removed.
12885 * @param {String} key (optional) The key associated with the removed item.
12890 this.allowFunctions = allowFunctions === true;
12892 this.getKey = keyFn;
12894 Roo.util.MixedCollection.superclass.constructor.call(this);
12897 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12898 allowFunctions : false,
12901 * Adds an item to the collection.
12902 * @param {String} key The key to associate with the item
12903 * @param {Object} o The item to add.
12904 * @return {Object} The item added.
12906 add : function(key, o){
12907 if(arguments.length == 1){
12909 key = this.getKey(o);
12911 if(typeof key == "undefined" || key === null){
12913 this.items.push(o);
12914 this.keys.push(null);
12916 var old = this.map[key];
12918 return this.replace(key, o);
12921 this.items.push(o);
12923 this.keys.push(key);
12925 this.fireEvent("add", this.length-1, o, key);
12930 * MixedCollection has a generic way to fetch keys if you implement getKey.
12933 var mc = new Roo.util.MixedCollection();
12934 mc.add(someEl.dom.id, someEl);
12935 mc.add(otherEl.dom.id, otherEl);
12939 var mc = new Roo.util.MixedCollection();
12940 mc.getKey = function(el){
12946 // or via the constructor
12947 var mc = new Roo.util.MixedCollection(false, function(el){
12953 * @param o {Object} The item for which to find the key.
12954 * @return {Object} The key for the passed item.
12956 getKey : function(o){
12961 * Replaces an item in the collection.
12962 * @param {String} key The key associated with the item to replace, or the item to replace.
12963 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12964 * @return {Object} The new item.
12966 replace : function(key, o){
12967 if(arguments.length == 1){
12969 key = this.getKey(o);
12971 var old = this.item(key);
12972 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12973 return this.add(key, o);
12975 var index = this.indexOfKey(key);
12976 this.items[index] = o;
12978 this.fireEvent("replace", key, old, o);
12983 * Adds all elements of an Array or an Object to the collection.
12984 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12985 * an Array of values, each of which are added to the collection.
12987 addAll : function(objs){
12988 if(arguments.length > 1 || objs instanceof Array){
12989 var args = arguments.length > 1 ? arguments : objs;
12990 for(var i = 0, len = args.length; i < len; i++){
12994 for(var key in objs){
12995 if(this.allowFunctions || typeof objs[key] != "function"){
12996 this.add(key, objs[key]);
13003 * Executes the specified function once for every item in the collection, passing each
13004 * item as the first and only parameter. returning false from the function will stop the iteration.
13005 * @param {Function} fn The function to execute for each item.
13006 * @param {Object} scope (optional) The scope in which to execute the function.
13008 each : function(fn, scope){
13009 var items = [].concat(this.items); // each safe for removal
13010 for(var i = 0, len = items.length; i < len; i++){
13011 if(fn.call(scope || items[i], items[i], i, len) === false){
13018 * Executes the specified function once for every key in the collection, passing each
13019 * key, and its associated item as the first two parameters.
13020 * @param {Function} fn The function to execute for each item.
13021 * @param {Object} scope (optional) The scope in which to execute the function.
13023 eachKey : function(fn, scope){
13024 for(var i = 0, len = this.keys.length; i < len; i++){
13025 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13030 * Returns the first item in the collection which elicits a true return value from the
13031 * passed selection function.
13032 * @param {Function} fn The selection function to execute for each item.
13033 * @param {Object} scope (optional) The scope in which to execute the function.
13034 * @return {Object} The first item in the collection which returned true from the selection function.
13036 find : function(fn, scope){
13037 for(var i = 0, len = this.items.length; i < len; i++){
13038 if(fn.call(scope || window, this.items[i], this.keys[i])){
13039 return this.items[i];
13046 * Inserts an item at the specified index in the collection.
13047 * @param {Number} index The index to insert the item at.
13048 * @param {String} key The key to associate with the new item, or the item itself.
13049 * @param {Object} o (optional) If the second parameter was a key, the new item.
13050 * @return {Object} The item inserted.
13052 insert : function(index, key, o){
13053 if(arguments.length == 2){
13055 key = this.getKey(o);
13057 if(index >= this.length){
13058 return this.add(key, o);
13061 this.items.splice(index, 0, o);
13062 if(typeof key != "undefined" && key != null){
13065 this.keys.splice(index, 0, key);
13066 this.fireEvent("add", index, o, key);
13071 * Removed an item from the collection.
13072 * @param {Object} o The item to remove.
13073 * @return {Object} The item removed.
13075 remove : function(o){
13076 return this.removeAt(this.indexOf(o));
13080 * Remove an item from a specified index in the collection.
13081 * @param {Number} index The index within the collection of the item to remove.
13083 removeAt : function(index){
13084 if(index < this.length && index >= 0){
13086 var o = this.items[index];
13087 this.items.splice(index, 1);
13088 var key = this.keys[index];
13089 if(typeof key != "undefined"){
13090 delete this.map[key];
13092 this.keys.splice(index, 1);
13093 this.fireEvent("remove", o, key);
13098 * Removed an item associated with the passed key fom the collection.
13099 * @param {String} key The key of the item to remove.
13101 removeKey : function(key){
13102 return this.removeAt(this.indexOfKey(key));
13106 * Returns the number of items in the collection.
13107 * @return {Number} the number of items in the collection.
13109 getCount : function(){
13110 return this.length;
13114 * Returns index within the collection of the passed Object.
13115 * @param {Object} o The item to find the index of.
13116 * @return {Number} index of the item.
13118 indexOf : function(o){
13119 if(!this.items.indexOf){
13120 for(var i = 0, len = this.items.length; i < len; i++){
13121 if(this.items[i] == o) return i;
13125 return this.items.indexOf(o);
13130 * Returns index within the collection of the passed key.
13131 * @param {String} key The key to find the index of.
13132 * @return {Number} index of the key.
13134 indexOfKey : function(key){
13135 if(!this.keys.indexOf){
13136 for(var i = 0, len = this.keys.length; i < len; i++){
13137 if(this.keys[i] == key) return i;
13141 return this.keys.indexOf(key);
13146 * Returns the item associated with the passed key OR index. Key has priority over index.
13147 * @param {String/Number} key The key or index of the item.
13148 * @return {Object} The item associated with the passed key.
13150 item : function(key){
13151 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13152 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13156 * Returns the item at the specified index.
13157 * @param {Number} index The index of the item.
13160 itemAt : function(index){
13161 return this.items[index];
13165 * Returns the item associated with the passed key.
13166 * @param {String/Number} key The key of the item.
13167 * @return {Object} The item associated with the passed key.
13169 key : function(key){
13170 return this.map[key];
13174 * Returns true if the collection contains the passed Object as an item.
13175 * @param {Object} o The Object to look for in the collection.
13176 * @return {Boolean} True if the collection contains the Object as an item.
13178 contains : function(o){
13179 return this.indexOf(o) != -1;
13183 * Returns true if the collection contains the passed Object as a key.
13184 * @param {String} key The key to look for in the collection.
13185 * @return {Boolean} True if the collection contains the Object as a key.
13187 containsKey : function(key){
13188 return typeof this.map[key] != "undefined";
13192 * Removes all items from the collection.
13194 clear : function(){
13199 this.fireEvent("clear");
13203 * Returns the first item in the collection.
13204 * @return {Object} the first item in the collection..
13206 first : function(){
13207 return this.items[0];
13211 * Returns the last item in the collection.
13212 * @return {Object} the last item in the collection..
13215 return this.items[this.length-1];
13218 _sort : function(property, dir, fn){
13219 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13220 fn = fn || function(a, b){
13223 var c = [], k = this.keys, items = this.items;
13224 for(var i = 0, len = items.length; i < len; i++){
13225 c[c.length] = {key: k[i], value: items[i], index: i};
13227 c.sort(function(a, b){
13228 var v = fn(a[property], b[property]) * dsc;
13230 v = (a.index < b.index ? -1 : 1);
13234 for(var i = 0, len = c.length; i < len; i++){
13235 items[i] = c[i].value;
13238 this.fireEvent("sort", this);
13242 * Sorts this collection with the passed comparison function
13243 * @param {String} direction (optional) "ASC" or "DESC"
13244 * @param {Function} fn (optional) comparison function
13246 sort : function(dir, fn){
13247 this._sort("value", dir, fn);
13251 * Sorts this collection by keys
13252 * @param {String} direction (optional) "ASC" or "DESC"
13253 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13255 keySort : function(dir, fn){
13256 this._sort("key", dir, fn || function(a, b){
13257 return String(a).toUpperCase()-String(b).toUpperCase();
13262 * Returns a range of items in this collection
13263 * @param {Number} startIndex (optional) defaults to 0
13264 * @param {Number} endIndex (optional) default to the last item
13265 * @return {Array} An array of items
13267 getRange : function(start, end){
13268 var items = this.items;
13269 if(items.length < 1){
13272 start = start || 0;
13273 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13276 for(var i = start; i <= end; i++) {
13277 r[r.length] = items[i];
13280 for(var i = start; i >= end; i--) {
13281 r[r.length] = items[i];
13288 * Filter the <i>objects</i> in this collection by a specific property.
13289 * Returns a new collection that has been filtered.
13290 * @param {String} property A property on your objects
13291 * @param {String/RegExp} value Either string that the property values
13292 * should start with or a RegExp to test against the property
13293 * @return {MixedCollection} The new filtered collection
13295 filter : function(property, value){
13296 if(!value.exec){ // not a regex
13297 value = String(value);
13298 if(value.length == 0){
13299 return this.clone();
13301 value = new RegExp("^" + Roo.escapeRe(value), "i");
13303 return this.filterBy(function(o){
13304 return o && value.test(o[property]);
13309 * Filter by a function. * Returns a new collection that has been filtered.
13310 * The passed function will be called with each
13311 * object in the collection. If the function returns true, the value is included
13312 * otherwise it is filtered.
13313 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13314 * @param {Object} scope (optional) The scope of the function (defaults to this)
13315 * @return {MixedCollection} The new filtered collection
13317 filterBy : function(fn, scope){
13318 var r = new Roo.util.MixedCollection();
13319 r.getKey = this.getKey;
13320 var k = this.keys, it = this.items;
13321 for(var i = 0, len = it.length; i < len; i++){
13322 if(fn.call(scope||this, it[i], k[i])){
13323 r.add(k[i], it[i]);
13330 * Creates a duplicate of this collection
13331 * @return {MixedCollection}
13333 clone : function(){
13334 var r = new Roo.util.MixedCollection();
13335 var k = this.keys, it = this.items;
13336 for(var i = 0, len = it.length; i < len; i++){
13337 r.add(k[i], it[i]);
13339 r.getKey = this.getKey;
13344 * Returns the item associated with the passed key or index.
13346 * @param {String/Number} key The key or index of the item.
13347 * @return {Object} The item associated with the passed key.
13349 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13351 * Ext JS Library 1.1.1
13352 * Copyright(c) 2006-2007, Ext JS, LLC.
13354 * Originally Released Under LGPL - original licence link has changed is not relivant.
13357 * <script type="text/javascript">
13360 * @class Roo.util.JSON
13361 * Modified version of Douglas Crockford"s json.js that doesn"t
13362 * mess with the Object prototype
13363 * http://www.json.org/js.html
13366 Roo.util.JSON = new (function(){
13367 var useHasOwn = {}.hasOwnProperty ? true : false;
13369 // crashes Safari in some instances
13370 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13372 var pad = function(n) {
13373 return n < 10 ? "0" + n : n;
13386 var encodeString = function(s){
13387 if (/["\\\x00-\x1f]/.test(s)) {
13388 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13393 c = b.charCodeAt();
13395 Math.floor(c / 16).toString(16) +
13396 (c % 16).toString(16);
13399 return '"' + s + '"';
13402 var encodeArray = function(o){
13403 var a = ["["], b, i, l = o.length, v;
13404 for (i = 0; i < l; i += 1) {
13406 switch (typeof v) {
13415 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13423 var encodeDate = function(o){
13424 return '"' + o.getFullYear() + "-" +
13425 pad(o.getMonth() + 1) + "-" +
13426 pad(o.getDate()) + "T" +
13427 pad(o.getHours()) + ":" +
13428 pad(o.getMinutes()) + ":" +
13429 pad(o.getSeconds()) + '"';
13433 * Encodes an Object, Array or other value
13434 * @param {Mixed} o The variable to encode
13435 * @return {String} The JSON string
13437 this.encode = function(o)
13439 // should this be extended to fully wrap stringify..
13441 if(typeof o == "undefined" || o === null){
13443 }else if(o instanceof Array){
13444 return encodeArray(o);
13445 }else if(o instanceof Date){
13446 return encodeDate(o);
13447 }else if(typeof o == "string"){
13448 return encodeString(o);
13449 }else if(typeof o == "number"){
13450 return isFinite(o) ? String(o) : "null";
13451 }else if(typeof o == "boolean"){
13454 var a = ["{"], b, i, v;
13456 if(!useHasOwn || o.hasOwnProperty(i)) {
13458 switch (typeof v) {
13467 a.push(this.encode(i), ":",
13468 v === null ? "null" : this.encode(v));
13479 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13480 * @param {String} json The JSON string
13481 * @return {Object} The resulting object
13483 this.decode = function(json){
13485 return /** eval:var:json */ eval("(" + json + ')');
13489 * Shorthand for {@link Roo.util.JSON#encode}
13490 * @member Roo encode
13492 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13494 * Shorthand for {@link Roo.util.JSON#decode}
13495 * @member Roo decode
13497 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13500 * Ext JS Library 1.1.1
13501 * Copyright(c) 2006-2007, Ext JS, LLC.
13503 * Originally Released Under LGPL - original licence link has changed is not relivant.
13506 * <script type="text/javascript">
13510 * @class Roo.util.Format
13511 * Reusable data formatting functions
13514 Roo.util.Format = function(){
13515 var trimRe = /^\s+|\s+$/g;
13518 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13519 * @param {String} value The string to truncate
13520 * @param {Number} length The maximum length to allow before truncating
13521 * @return {String} The converted text
13523 ellipsis : function(value, len){
13524 if(value && value.length > len){
13525 return value.substr(0, len-3)+"...";
13531 * Checks a reference and converts it to empty string if it is undefined
13532 * @param {Mixed} value Reference to check
13533 * @return {Mixed} Empty string if converted, otherwise the original value
13535 undef : function(value){
13536 return typeof value != "undefined" ? value : "";
13540 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13541 * @param {String} value The string to encode
13542 * @return {String} The encoded text
13544 htmlEncode : function(value){
13545 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13549 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13550 * @param {String} value The string to decode
13551 * @return {String} The decoded text
13553 htmlDecode : function(value){
13554 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13558 * Trims any whitespace from either side of a string
13559 * @param {String} value The text to trim
13560 * @return {String} The trimmed text
13562 trim : function(value){
13563 return String(value).replace(trimRe, "");
13567 * Returns a substring from within an original string
13568 * @param {String} value The original text
13569 * @param {Number} start The start index of the substring
13570 * @param {Number} length The length of the substring
13571 * @return {String} The substring
13573 substr : function(value, start, length){
13574 return String(value).substr(start, length);
13578 * Converts a string to all lower case letters
13579 * @param {String} value The text to convert
13580 * @return {String} The converted text
13582 lowercase : function(value){
13583 return String(value).toLowerCase();
13587 * Converts a string to all upper case letters
13588 * @param {String} value The text to convert
13589 * @return {String} The converted text
13591 uppercase : function(value){
13592 return String(value).toUpperCase();
13596 * Converts the first character only of a string to upper case
13597 * @param {String} value The text to convert
13598 * @return {String} The converted text
13600 capitalize : function(value){
13601 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13605 call : function(value, fn){
13606 if(arguments.length > 2){
13607 var args = Array.prototype.slice.call(arguments, 2);
13608 args.unshift(value);
13610 return /** eval:var:value */ eval(fn).apply(window, args);
13612 /** eval:var:value */
13613 return /** eval:var:value */ eval(fn).call(window, value);
13619 * safer version of Math.toFixed..??/
13620 * @param {Number/String} value The numeric value to format
13621 * @param {Number/String} value Decimal places
13622 * @return {String} The formatted currency string
13624 toFixed : function(v, n)
13626 // why not use to fixed - precision is buggered???
13628 return Math.round(v-0);
13630 var fact = Math.pow(10,n+1);
13631 v = (Math.round((v-0)*fact))/fact;
13632 var z = (''+fact).substring(2);
13633 if (v == Math.floor(v)) {
13634 return Math.floor(v) + '.' + z;
13637 // now just padd decimals..
13638 var ps = String(v).split('.');
13639 var fd = (ps[1] + z);
13640 var r = fd.substring(0,n);
13641 var rm = fd.substring(n);
13643 return ps[0] + '.' + r;
13645 r*=1; // turn it into a number;
13647 if (String(r).length != n) {
13650 r = String(r).substring(1); // chop the end off.
13653 return ps[0] + '.' + r;
13658 * Format a number as US currency
13659 * @param {Number/String} value The numeric value to format
13660 * @return {String} The formatted currency string
13662 usMoney : function(v){
13663 return '$' + Roo.util.Format.number(v);
13668 * eventually this should probably emulate php's number_format
13669 * @param {Number/String} value The numeric value to format
13670 * @param {Number} decimals number of decimal places
13671 * @return {String} The formatted currency string
13673 number : function(v,decimals)
13675 // multiply and round.
13676 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13677 var mul = Math.pow(10, decimals);
13678 var zero = String(mul).substring(1);
13679 v = (Math.round((v-0)*mul))/mul;
13681 // if it's '0' number.. then
13683 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13685 var ps = v.split('.');
13689 var r = /(\d+)(\d{3})/;
13691 while (r.test(whole)) {
13692 whole = whole.replace(r, '$1' + ',' + '$2');
13698 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13699 // does not have decimals
13700 (decimals ? ('.' + zero) : '');
13703 return whole + sub ;
13707 * Parse a value into a formatted date using the specified format pattern.
13708 * @param {Mixed} value The value to format
13709 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13710 * @return {String} The formatted date string
13712 date : function(v, format){
13716 if(!(v instanceof Date)){
13717 v = new Date(Date.parse(v));
13719 return v.dateFormat(format || "m/d/Y");
13723 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13724 * @param {String} format Any valid date format string
13725 * @return {Function} The date formatting function
13727 dateRenderer : function(format){
13728 return function(v){
13729 return Roo.util.Format.date(v, format);
13734 stripTagsRE : /<\/?[^>]+>/gi,
13737 * Strips all HTML tags
13738 * @param {Mixed} value The text from which to strip tags
13739 * @return {String} The stripped text
13741 stripTags : function(v){
13742 return !v ? v : String(v).replace(this.stripTagsRE, "");
13747 * Ext JS Library 1.1.1
13748 * Copyright(c) 2006-2007, Ext JS, LLC.
13750 * Originally Released Under LGPL - original licence link has changed is not relivant.
13753 * <script type="text/javascript">
13760 * @class Roo.MasterTemplate
13761 * @extends Roo.Template
13762 * Provides a template that can have child templates. The syntax is:
13764 var t = new Roo.MasterTemplate(
13765 '<select name="{name}">',
13766 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13769 t.add('options', {value: 'foo', text: 'bar'});
13770 // or you can add multiple child elements in one shot
13771 t.addAll('options', [
13772 {value: 'foo', text: 'bar'},
13773 {value: 'foo2', text: 'bar2'},
13774 {value: 'foo3', text: 'bar3'}
13776 // then append, applying the master template values
13777 t.append('my-form', {name: 'my-select'});
13779 * A name attribute for the child template is not required if you have only one child
13780 * template or you want to refer to them by index.
13782 Roo.MasterTemplate = function(){
13783 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13784 this.originalHtml = this.html;
13786 var m, re = this.subTemplateRe;
13789 while(m = re.exec(this.html)){
13790 var name = m[1], content = m[2];
13795 tpl : new Roo.Template(content)
13798 st[name] = st[subIndex];
13800 st[subIndex].tpl.compile();
13801 st[subIndex].tpl.call = this.call.createDelegate(this);
13804 this.subCount = subIndex;
13807 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13809 * The regular expression used to match sub templates
13813 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13816 * Applies the passed values to a child template.
13817 * @param {String/Number} name (optional) The name or index of the child template
13818 * @param {Array/Object} values The values to be applied to the template
13819 * @return {MasterTemplate} this
13821 add : function(name, values){
13822 if(arguments.length == 1){
13823 values = arguments[0];
13826 var s = this.subs[name];
13827 s.buffer[s.buffer.length] = s.tpl.apply(values);
13832 * Applies all the passed values to a child template.
13833 * @param {String/Number} name (optional) The name or index of the child template
13834 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13835 * @param {Boolean} reset (optional) True to reset the template first
13836 * @return {MasterTemplate} this
13838 fill : function(name, values, reset){
13840 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13848 for(var i = 0, len = values.length; i < len; i++){
13849 this.add(name, values[i]);
13855 * Resets the template for reuse
13856 * @return {MasterTemplate} this
13858 reset : function(){
13860 for(var i = 0; i < this.subCount; i++){
13866 applyTemplate : function(values){
13868 var replaceIndex = -1;
13869 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13870 return s[++replaceIndex].buffer.join("");
13872 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13875 apply : function(){
13876 return this.applyTemplate.apply(this, arguments);
13879 compile : function(){return this;}
13883 * Alias for fill().
13886 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13888 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13889 * var tpl = Roo.MasterTemplate.from('element-id');
13890 * @param {String/HTMLElement} el
13891 * @param {Object} config
13894 Roo.MasterTemplate.from = function(el, config){
13895 el = Roo.getDom(el);
13896 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13899 * Ext JS Library 1.1.1
13900 * Copyright(c) 2006-2007, Ext JS, LLC.
13902 * Originally Released Under LGPL - original licence link has changed is not relivant.
13905 * <script type="text/javascript">
13910 * @class Roo.util.CSS
13911 * Utility class for manipulating CSS rules
13914 Roo.util.CSS = function(){
13916 var doc = document;
13918 var camelRe = /(-[a-z])/gi;
13919 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13923 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13924 * tag and appended to the HEAD of the document.
13925 * @param {String|Object} cssText The text containing the css rules
13926 * @param {String} id An id to add to the stylesheet for later removal
13927 * @return {StyleSheet}
13929 createStyleSheet : function(cssText, id){
13931 var head = doc.getElementsByTagName("head")[0];
13932 var nrules = doc.createElement("style");
13933 nrules.setAttribute("type", "text/css");
13935 nrules.setAttribute("id", id);
13937 if (typeof(cssText) != 'string') {
13938 // support object maps..
13939 // not sure if this a good idea..
13940 // perhaps it should be merged with the general css handling
13941 // and handle js style props.
13942 var cssTextNew = [];
13943 for(var n in cssText) {
13945 for(var k in cssText[n]) {
13946 citems.push( k + ' : ' +cssText[n][k] + ';' );
13948 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13951 cssText = cssTextNew.join("\n");
13957 head.appendChild(nrules);
13958 ss = nrules.styleSheet;
13959 ss.cssText = cssText;
13962 nrules.appendChild(doc.createTextNode(cssText));
13964 nrules.cssText = cssText;
13966 head.appendChild(nrules);
13967 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13969 this.cacheStyleSheet(ss);
13974 * Removes a style or link tag by id
13975 * @param {String} id The id of the tag
13977 removeStyleSheet : function(id){
13978 var existing = doc.getElementById(id);
13980 existing.parentNode.removeChild(existing);
13985 * Dynamically swaps an existing stylesheet reference for a new one
13986 * @param {String} id The id of an existing link tag to remove
13987 * @param {String} url The href of the new stylesheet to include
13989 swapStyleSheet : function(id, url){
13990 this.removeStyleSheet(id);
13991 var ss = doc.createElement("link");
13992 ss.setAttribute("rel", "stylesheet");
13993 ss.setAttribute("type", "text/css");
13994 ss.setAttribute("id", id);
13995 ss.setAttribute("href", url);
13996 doc.getElementsByTagName("head")[0].appendChild(ss);
14000 * Refresh the rule cache if you have dynamically added stylesheets
14001 * @return {Object} An object (hash) of rules indexed by selector
14003 refreshCache : function(){
14004 return this.getRules(true);
14008 cacheStyleSheet : function(stylesheet){
14012 try{// try catch for cross domain access issue
14013 var ssRules = stylesheet.cssRules || stylesheet.rules;
14014 for(var j = ssRules.length-1; j >= 0; --j){
14015 rules[ssRules[j].selectorText] = ssRules[j];
14021 * Gets all css rules for the document
14022 * @param {Boolean} refreshCache true to refresh the internal cache
14023 * @return {Object} An object (hash) of rules indexed by selector
14025 getRules : function(refreshCache){
14026 if(rules == null || refreshCache){
14028 var ds = doc.styleSheets;
14029 for(var i =0, len = ds.length; i < len; i++){
14031 this.cacheStyleSheet(ds[i]);
14039 * Gets an an individual CSS rule by selector(s)
14040 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14041 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14042 * @return {CSSRule} The CSS rule or null if one is not found
14044 getRule : function(selector, refreshCache){
14045 var rs = this.getRules(refreshCache);
14046 if(!(selector instanceof Array)){
14047 return rs[selector];
14049 for(var i = 0; i < selector.length; i++){
14050 if(rs[selector[i]]){
14051 return rs[selector[i]];
14059 * Updates a rule property
14060 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14061 * @param {String} property The css property
14062 * @param {String} value The new value for the property
14063 * @return {Boolean} true If a rule was found and updated
14065 updateRule : function(selector, property, value){
14066 if(!(selector instanceof Array)){
14067 var rule = this.getRule(selector);
14069 rule.style[property.replace(camelRe, camelFn)] = value;
14073 for(var i = 0; i < selector.length; i++){
14074 if(this.updateRule(selector[i], property, value)){
14084 * Ext JS Library 1.1.1
14085 * Copyright(c) 2006-2007, Ext JS, LLC.
14087 * Originally Released Under LGPL - original licence link has changed is not relivant.
14090 * <script type="text/javascript">
14096 * @class Roo.util.ClickRepeater
14097 * @extends Roo.util.Observable
14099 * A wrapper class which can be applied to any element. Fires a "click" event while the
14100 * mouse is pressed. The interval between firings may be specified in the config but
14101 * defaults to 10 milliseconds.
14103 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14105 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14106 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14107 * Similar to an autorepeat key delay.
14108 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14109 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14110 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14111 * "interval" and "delay" are ignored. "immediate" is honored.
14112 * @cfg {Boolean} preventDefault True to prevent the default click event
14113 * @cfg {Boolean} stopDefault True to stop the default click event
14116 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14117 * 2007-02-02 jvs Renamed to ClickRepeater
14118 * 2007-02-03 jvs Modifications for FF Mac and Safari
14121 * @param {String/HTMLElement/Element} el The element to listen on
14122 * @param {Object} config
14124 Roo.util.ClickRepeater = function(el, config)
14126 this.el = Roo.get(el);
14127 this.el.unselectable();
14129 Roo.apply(this, config);
14134 * Fires when the mouse button is depressed.
14135 * @param {Roo.util.ClickRepeater} this
14137 "mousedown" : true,
14140 * Fires on a specified interval during the time the element is pressed.
14141 * @param {Roo.util.ClickRepeater} this
14146 * Fires when the mouse key is released.
14147 * @param {Roo.util.ClickRepeater} this
14152 this.el.on("mousedown", this.handleMouseDown, this);
14153 if(this.preventDefault || this.stopDefault){
14154 this.el.on("click", function(e){
14155 if(this.preventDefault){
14156 e.preventDefault();
14158 if(this.stopDefault){
14164 // allow inline handler
14166 this.on("click", this.handler, this.scope || this);
14169 Roo.util.ClickRepeater.superclass.constructor.call(this);
14172 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14175 preventDefault : true,
14176 stopDefault : false,
14180 handleMouseDown : function(){
14181 clearTimeout(this.timer);
14183 if(this.pressClass){
14184 this.el.addClass(this.pressClass);
14186 this.mousedownTime = new Date();
14188 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14189 this.el.on("mouseout", this.handleMouseOut, this);
14191 this.fireEvent("mousedown", this);
14192 this.fireEvent("click", this);
14194 this.timer = this.click.defer(this.delay || this.interval, this);
14198 click : function(){
14199 this.fireEvent("click", this);
14200 this.timer = this.click.defer(this.getInterval(), this);
14204 getInterval: function(){
14205 if(!this.accelerate){
14206 return this.interval;
14208 var pressTime = this.mousedownTime.getElapsed();
14209 if(pressTime < 500){
14211 }else if(pressTime < 1700){
14213 }else if(pressTime < 2600){
14215 }else if(pressTime < 3500){
14217 }else if(pressTime < 4400){
14219 }else if(pressTime < 5300){
14221 }else if(pressTime < 6200){
14229 handleMouseOut : function(){
14230 clearTimeout(this.timer);
14231 if(this.pressClass){
14232 this.el.removeClass(this.pressClass);
14234 this.el.on("mouseover", this.handleMouseReturn, this);
14238 handleMouseReturn : function(){
14239 this.el.un("mouseover", this.handleMouseReturn);
14240 if(this.pressClass){
14241 this.el.addClass(this.pressClass);
14247 handleMouseUp : function(){
14248 clearTimeout(this.timer);
14249 this.el.un("mouseover", this.handleMouseReturn);
14250 this.el.un("mouseout", this.handleMouseOut);
14251 Roo.get(document).un("mouseup", this.handleMouseUp);
14252 this.el.removeClass(this.pressClass);
14253 this.fireEvent("mouseup", this);
14257 * Ext JS Library 1.1.1
14258 * Copyright(c) 2006-2007, Ext JS, LLC.
14260 * Originally Released Under LGPL - original licence link has changed is not relivant.
14263 * <script type="text/javascript">
14268 * @class Roo.KeyNav
14269 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14270 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14271 * way to implement custom navigation schemes for any UI component.</p>
14272 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14273 * pageUp, pageDown, del, home, end. Usage:</p>
14275 var nav = new Roo.KeyNav("my-element", {
14276 "left" : function(e){
14277 this.moveLeft(e.ctrlKey);
14279 "right" : function(e){
14280 this.moveRight(e.ctrlKey);
14282 "enter" : function(e){
14289 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14290 * @param {Object} config The config
14292 Roo.KeyNav = function(el, config){
14293 this.el = Roo.get(el);
14294 Roo.apply(this, config);
14295 if(!this.disabled){
14296 this.disabled = true;
14301 Roo.KeyNav.prototype = {
14303 * @cfg {Boolean} disabled
14304 * True to disable this KeyNav instance (defaults to false)
14308 * @cfg {String} defaultEventAction
14309 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14310 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14311 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14313 defaultEventAction: "stopEvent",
14315 * @cfg {Boolean} forceKeyDown
14316 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14317 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14318 * handle keydown instead of keypress.
14320 forceKeyDown : false,
14323 prepareEvent : function(e){
14324 var k = e.getKey();
14325 var h = this.keyToHandler[k];
14326 //if(h && this[h]){
14327 // e.stopPropagation();
14329 if(Roo.isSafari && h && k >= 37 && k <= 40){
14335 relay : function(e){
14336 var k = e.getKey();
14337 var h = this.keyToHandler[k];
14339 if(this.doRelay(e, this[h], h) !== true){
14340 e[this.defaultEventAction]();
14346 doRelay : function(e, h, hname){
14347 return h.call(this.scope || this, e);
14350 // possible handlers
14364 // quick lookup hash
14381 * Enable this KeyNav
14383 enable: function(){
14385 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14386 // the EventObject will normalize Safari automatically
14387 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14388 this.el.on("keydown", this.relay, this);
14390 this.el.on("keydown", this.prepareEvent, this);
14391 this.el.on("keypress", this.relay, this);
14393 this.disabled = false;
14398 * Disable this KeyNav
14400 disable: function(){
14401 if(!this.disabled){
14402 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14403 this.el.un("keydown", this.relay);
14405 this.el.un("keydown", this.prepareEvent);
14406 this.el.un("keypress", this.relay);
14408 this.disabled = true;
14413 * Ext JS Library 1.1.1
14414 * Copyright(c) 2006-2007, Ext JS, LLC.
14416 * Originally Released Under LGPL - original licence link has changed is not relivant.
14419 * <script type="text/javascript">
14424 * @class Roo.KeyMap
14425 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14426 * The constructor accepts the same config object as defined by {@link #addBinding}.
14427 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14428 * combination it will call the function with this signature (if the match is a multi-key
14429 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14430 * A KeyMap can also handle a string representation of keys.<br />
14433 // map one key by key code
14434 var map = new Roo.KeyMap("my-element", {
14435 key: 13, // or Roo.EventObject.ENTER
14440 // map multiple keys to one action by string
14441 var map = new Roo.KeyMap("my-element", {
14447 // map multiple keys to multiple actions by strings and array of codes
14448 var map = new Roo.KeyMap("my-element", [
14451 fn: function(){ alert("Return was pressed"); }
14454 fn: function(){ alert('a, b or c was pressed'); }
14459 fn: function(){ alert('Control + shift + tab was pressed.'); }
14463 * <b>Note: A KeyMap starts enabled</b>
14465 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14466 * @param {Object} config The config (see {@link #addBinding})
14467 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14469 Roo.KeyMap = function(el, config, eventName){
14470 this.el = Roo.get(el);
14471 this.eventName = eventName || "keydown";
14472 this.bindings = [];
14474 this.addBinding(config);
14479 Roo.KeyMap.prototype = {
14481 * True to stop the event from bubbling and prevent the default browser action if the
14482 * key was handled by the KeyMap (defaults to false)
14488 * Add a new binding to this KeyMap. The following config object properties are supported:
14490 Property Type Description
14491 ---------- --------------- ----------------------------------------------------------------------
14492 key String/Array A single keycode or an array of keycodes to handle
14493 shift Boolean True to handle key only when shift is pressed (defaults to false)
14494 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14495 alt Boolean True to handle key only when alt is pressed (defaults to false)
14496 fn Function The function to call when KeyMap finds the expected key combination
14497 scope Object The scope of the callback function
14503 var map = new Roo.KeyMap(document, {
14504 key: Roo.EventObject.ENTER,
14509 //Add a new binding to the existing KeyMap later
14517 * @param {Object/Array} config A single KeyMap config or an array of configs
14519 addBinding : function(config){
14520 if(config instanceof Array){
14521 for(var i = 0, len = config.length; i < len; i++){
14522 this.addBinding(config[i]);
14526 var keyCode = config.key,
14527 shift = config.shift,
14528 ctrl = config.ctrl,
14531 scope = config.scope;
14532 if(typeof keyCode == "string"){
14534 var keyString = keyCode.toUpperCase();
14535 for(var j = 0, len = keyString.length; j < len; j++){
14536 ks.push(keyString.charCodeAt(j));
14540 var keyArray = keyCode instanceof Array;
14541 var handler = function(e){
14542 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14543 var k = e.getKey();
14545 for(var i = 0, len = keyCode.length; i < len; i++){
14546 if(keyCode[i] == k){
14547 if(this.stopEvent){
14550 fn.call(scope || window, k, e);
14556 if(this.stopEvent){
14559 fn.call(scope || window, k, e);
14564 this.bindings.push(handler);
14568 * Shorthand for adding a single key listener
14569 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14570 * following options:
14571 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14572 * @param {Function} fn The function to call
14573 * @param {Object} scope (optional) The scope of the function
14575 on : function(key, fn, scope){
14576 var keyCode, shift, ctrl, alt;
14577 if(typeof key == "object" && !(key instanceof Array)){
14596 handleKeyDown : function(e){
14597 if(this.enabled){ //just in case
14598 var b = this.bindings;
14599 for(var i = 0, len = b.length; i < len; i++){
14600 b[i].call(this, e);
14606 * Returns true if this KeyMap is enabled
14607 * @return {Boolean}
14609 isEnabled : function(){
14610 return this.enabled;
14614 * Enables this KeyMap
14616 enable: function(){
14618 this.el.on(this.eventName, this.handleKeyDown, this);
14619 this.enabled = true;
14624 * Disable this KeyMap
14626 disable: function(){
14628 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14629 this.enabled = false;
14634 * Ext JS Library 1.1.1
14635 * Copyright(c) 2006-2007, Ext JS, LLC.
14637 * Originally Released Under LGPL - original licence link has changed is not relivant.
14640 * <script type="text/javascript">
14645 * @class Roo.util.TextMetrics
14646 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14647 * wide, in pixels, a given block of text will be.
14650 Roo.util.TextMetrics = function(){
14654 * Measures the size of the specified text
14655 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14656 * that can affect the size of the rendered text
14657 * @param {String} text The text to measure
14658 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14659 * in order to accurately measure the text height
14660 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14662 measure : function(el, text, fixedWidth){
14664 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14667 shared.setFixedWidth(fixedWidth || 'auto');
14668 return shared.getSize(text);
14672 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14673 * the overhead of multiple calls to initialize the style properties on each measurement.
14674 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14675 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14676 * in order to accurately measure the text height
14677 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14679 createInstance : function(el, fixedWidth){
14680 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14687 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14688 var ml = new Roo.Element(document.createElement('div'));
14689 document.body.appendChild(ml.dom);
14690 ml.position('absolute');
14691 ml.setLeftTop(-1000, -1000);
14695 ml.setWidth(fixedWidth);
14700 * Returns the size of the specified text based on the internal element's style and width properties
14701 * @memberOf Roo.util.TextMetrics.Instance#
14702 * @param {String} text The text to measure
14703 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14705 getSize : function(text){
14707 var s = ml.getSize();
14713 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14714 * that can affect the size of the rendered text
14715 * @memberOf Roo.util.TextMetrics.Instance#
14716 * @param {String/HTMLElement} el The element, dom node or id
14718 bind : function(el){
14720 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14725 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14726 * to set a fixed width in order to accurately measure the text height.
14727 * @memberOf Roo.util.TextMetrics.Instance#
14728 * @param {Number} width The width to set on the element
14730 setFixedWidth : function(width){
14731 ml.setWidth(width);
14735 * Returns the measured width of the specified text
14736 * @memberOf Roo.util.TextMetrics.Instance#
14737 * @param {String} text The text to measure
14738 * @return {Number} width The width in pixels
14740 getWidth : function(text){
14741 ml.dom.style.width = 'auto';
14742 return this.getSize(text).width;
14746 * Returns the measured height of the specified text. For multiline text, be sure to call
14747 * {@link #setFixedWidth} if necessary.
14748 * @memberOf Roo.util.TextMetrics.Instance#
14749 * @param {String} text The text to measure
14750 * @return {Number} height The height in pixels
14752 getHeight : function(text){
14753 return this.getSize(text).height;
14757 instance.bind(bindTo);
14762 // backwards compat
14763 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14765 * Ext JS Library 1.1.1
14766 * Copyright(c) 2006-2007, Ext JS, LLC.
14768 * Originally Released Under LGPL - original licence link has changed is not relivant.
14771 * <script type="text/javascript">
14775 * @class Roo.state.Provider
14776 * Abstract base class for state provider implementations. This class provides methods
14777 * for encoding and decoding <b>typed</b> variables including dates and defines the
14778 * Provider interface.
14780 Roo.state.Provider = function(){
14782 * @event statechange
14783 * Fires when a state change occurs.
14784 * @param {Provider} this This state provider
14785 * @param {String} key The state key which was changed
14786 * @param {String} value The encoded value for the state
14789 "statechange": true
14792 Roo.state.Provider.superclass.constructor.call(this);
14794 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14796 * Returns the current value for a key
14797 * @param {String} name The key name
14798 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14799 * @return {Mixed} The state data
14801 get : function(name, defaultValue){
14802 return typeof this.state[name] == "undefined" ?
14803 defaultValue : this.state[name];
14807 * Clears a value from the state
14808 * @param {String} name The key name
14810 clear : function(name){
14811 delete this.state[name];
14812 this.fireEvent("statechange", this, name, null);
14816 * Sets the value for a key
14817 * @param {String} name The key name
14818 * @param {Mixed} value The value to set
14820 set : function(name, value){
14821 this.state[name] = value;
14822 this.fireEvent("statechange", this, name, value);
14826 * Decodes a string previously encoded with {@link #encodeValue}.
14827 * @param {String} value The value to decode
14828 * @return {Mixed} The decoded value
14830 decodeValue : function(cookie){
14831 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14832 var matches = re.exec(unescape(cookie));
14833 if(!matches || !matches[1]) return; // non state cookie
14834 var type = matches[1];
14835 var v = matches[2];
14838 return parseFloat(v);
14840 return new Date(Date.parse(v));
14845 var values = v.split("^");
14846 for(var i = 0, len = values.length; i < len; i++){
14847 all.push(this.decodeValue(values[i]));
14852 var values = v.split("^");
14853 for(var i = 0, len = values.length; i < len; i++){
14854 var kv = values[i].split("=");
14855 all[kv[0]] = this.decodeValue(kv[1]);
14864 * Encodes a value including type information. Decode with {@link #decodeValue}.
14865 * @param {Mixed} value The value to encode
14866 * @return {String} The encoded value
14868 encodeValue : function(v){
14870 if(typeof v == "number"){
14872 }else if(typeof v == "boolean"){
14873 enc = "b:" + (v ? "1" : "0");
14874 }else if(v instanceof Date){
14875 enc = "d:" + v.toGMTString();
14876 }else if(v instanceof Array){
14878 for(var i = 0, len = v.length; i < len; i++){
14879 flat += this.encodeValue(v[i]);
14880 if(i != len-1) flat += "^";
14883 }else if(typeof v == "object"){
14886 if(typeof v[key] != "function"){
14887 flat += key + "=" + this.encodeValue(v[key]) + "^";
14890 enc = "o:" + flat.substring(0, flat.length-1);
14894 return escape(enc);
14900 * Ext JS Library 1.1.1
14901 * Copyright(c) 2006-2007, Ext JS, LLC.
14903 * Originally Released Under LGPL - original licence link has changed is not relivant.
14906 * <script type="text/javascript">
14909 * @class Roo.state.Manager
14910 * This is the global state manager. By default all components that are "state aware" check this class
14911 * for state information if you don't pass them a custom state provider. In order for this class
14912 * to be useful, it must be initialized with a provider when your application initializes.
14914 // in your initialization function
14916 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14918 // supposed you have a {@link Roo.BorderLayout}
14919 var layout = new Roo.BorderLayout(...);
14920 layout.restoreState();
14921 // or a {Roo.BasicDialog}
14922 var dialog = new Roo.BasicDialog(...);
14923 dialog.restoreState();
14927 Roo.state.Manager = function(){
14928 var provider = new Roo.state.Provider();
14932 * Configures the default state provider for your application
14933 * @param {Provider} stateProvider The state provider to set
14935 setProvider : function(stateProvider){
14936 provider = stateProvider;
14940 * Returns the current value for a key
14941 * @param {String} name The key name
14942 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14943 * @return {Mixed} The state data
14945 get : function(key, defaultValue){
14946 return provider.get(key, defaultValue);
14950 * Sets the value for a key
14951 * @param {String} name The key name
14952 * @param {Mixed} value The state data
14954 set : function(key, value){
14955 provider.set(key, value);
14959 * Clears a value from the state
14960 * @param {String} name The key name
14962 clear : function(key){
14963 provider.clear(key);
14967 * Gets the currently configured state provider
14968 * @return {Provider} The state provider
14970 getProvider : function(){
14977 * Ext JS Library 1.1.1
14978 * Copyright(c) 2006-2007, Ext JS, LLC.
14980 * Originally Released Under LGPL - original licence link has changed is not relivant.
14983 * <script type="text/javascript">
14986 * @class Roo.state.CookieProvider
14987 * @extends Roo.state.Provider
14988 * The default Provider implementation which saves state via cookies.
14991 var cp = new Roo.state.CookieProvider({
14993 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14994 domain: "roojs.com"
14996 Roo.state.Manager.setProvider(cp);
14998 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14999 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15000 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15001 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15002 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15003 * domain the page is running on including the 'www' like 'www.roojs.com')
15004 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15006 * Create a new CookieProvider
15007 * @param {Object} config The configuration object
15009 Roo.state.CookieProvider = function(config){
15010 Roo.state.CookieProvider.superclass.constructor.call(this);
15012 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15013 this.domain = null;
15014 this.secure = false;
15015 Roo.apply(this, config);
15016 this.state = this.readCookies();
15019 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15021 set : function(name, value){
15022 if(typeof value == "undefined" || value === null){
15026 this.setCookie(name, value);
15027 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15031 clear : function(name){
15032 this.clearCookie(name);
15033 Roo.state.CookieProvider.superclass.clear.call(this, name);
15037 readCookies : function(){
15039 var c = document.cookie + ";";
15040 var re = /\s?(.*?)=(.*?);/g;
15042 while((matches = re.exec(c)) != null){
15043 var name = matches[1];
15044 var value = matches[2];
15045 if(name && name.substring(0,3) == "ys-"){
15046 cookies[name.substr(3)] = this.decodeValue(value);
15053 setCookie : function(name, value){
15054 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15055 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15056 ((this.path == null) ? "" : ("; path=" + this.path)) +
15057 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15058 ((this.secure == true) ? "; secure" : "");
15062 clearCookie : function(name){
15063 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15064 ((this.path == null) ? "" : ("; path=" + this.path)) +
15065 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15066 ((this.secure == true) ? "; secure" : "");
15070 * Ext JS Library 1.1.1
15071 * Copyright(c) 2006-2007, Ext JS, LLC.
15073 * Originally Released Under LGPL - original licence link has changed is not relivant.
15076 * <script type="text/javascript">
15082 * These classes are derivatives of the similarly named classes in the YUI Library.
15083 * The original license:
15084 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
15085 * Code licensed under the BSD License:
15086 * http://developer.yahoo.net/yui/license.txt
15091 var Event=Roo.EventManager;
15092 var Dom=Roo.lib.Dom;
15095 * @class Roo.dd.DragDrop
15096 * @extends Roo.util.Observable
15097 * Defines the interface and base operation of items that that can be
15098 * dragged or can be drop targets. It was designed to be extended, overriding
15099 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
15100 * Up to three html elements can be associated with a DragDrop instance:
15102 * <li>linked element: the element that is passed into the constructor.
15103 * This is the element which defines the boundaries for interaction with
15104 * other DragDrop objects.</li>
15105 * <li>handle element(s): The drag operation only occurs if the element that
15106 * was clicked matches a handle element. By default this is the linked
15107 * element, but there are times that you will want only a portion of the
15108 * linked element to initiate the drag operation, and the setHandleElId()
15109 * method provides a way to define this.</li>
15110 * <li>drag element: this represents the element that would be moved along
15111 * with the cursor during a drag operation. By default, this is the linked
15112 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
15113 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
15116 * This class should not be instantiated until the onload event to ensure that
15117 * the associated elements are available.
15118 * The following would define a DragDrop obj that would interact with any
15119 * other DragDrop obj in the "group1" group:
15121 * dd = new Roo.dd.DragDrop("div1", "group1");
15123 * Since none of the event handlers have been implemented, nothing would
15124 * actually happen if you were to run the code above. Normally you would
15125 * override this class or one of the default implementations, but you can
15126 * also override the methods you want on an instance of the class...
15128 * dd.onDragDrop = function(e, id) {
15129 * alert("dd was dropped on " + id);
15133 * @param {String} id of the element that is linked to this instance
15134 * @param {String} sGroup the group of related DragDrop objects
15135 * @param {object} config an object containing configurable attributes
15136 * Valid properties for DragDrop:
15137 * padding, isTarget, maintainOffset, primaryButtonOnly
15139 Roo.dd.DragDrop = function(id, sGroup, config) {
15141 this.init(id, sGroup, config);
15146 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
15149 * The id of the element associated with this object. This is what we
15150 * refer to as the "linked element" because the size and position of
15151 * this element is used to determine when the drag and drop objects have
15159 * Configuration attributes passed into the constructor
15166 * The id of the element that will be dragged. By default this is same
15167 * as the linked element , but could be changed to another element. Ex:
15169 * @property dragElId
15176 * the id of the element that initiates the drag operation. By default
15177 * this is the linked element, but could be changed to be a child of this
15178 * element. This lets us do things like only starting the drag when the
15179 * header element within the linked html element is clicked.
15180 * @property handleElId
15187 * An associative array of HTML tags that will be ignored if clicked.
15188 * @property invalidHandleTypes
15189 * @type {string: string}
15191 invalidHandleTypes: null,
15194 * An associative array of ids for elements that will be ignored if clicked
15195 * @property invalidHandleIds
15196 * @type {string: string}
15198 invalidHandleIds: null,
15201 * An indexted array of css class names for elements that will be ignored
15203 * @property invalidHandleClasses
15206 invalidHandleClasses: null,
15209 * The linked element's absolute X position at the time the drag was
15211 * @property startPageX
15218 * The linked element's absolute X position at the time the drag was
15220 * @property startPageY
15227 * The group defines a logical collection of DragDrop objects that are
15228 * related. Instances only get events when interacting with other
15229 * DragDrop object in the same group. This lets us define multiple
15230 * groups using a single DragDrop subclass if we want.
15232 * @type {string: string}
15237 * Individual drag/drop instances can be locked. This will prevent
15238 * onmousedown start drag.
15246 * Lock this instance
15249 lock: function() { this.locked = true; },
15252 * Unlock this instace
15255 unlock: function() { this.locked = false; },
15258 * By default, all insances can be a drop target. This can be disabled by
15259 * setting isTarget to false.
15266 * The padding configured for this drag and drop object for calculating
15267 * the drop zone intersection with this object.
15274 * Cached reference to the linked element
15275 * @property _domRef
15281 * Internal typeof flag
15282 * @property __ygDragDrop
15285 __ygDragDrop: true,
15288 * Set to true when horizontal contraints are applied
15289 * @property constrainX
15296 * Set to true when vertical contraints are applied
15297 * @property constrainY
15304 * The left constraint
15312 * The right constraint
15320 * The up constraint
15329 * The down constraint
15337 * Maintain offsets when we resetconstraints. Set to true when you want
15338 * the position of the element relative to its parent to stay the same
15339 * when the page changes
15341 * @property maintainOffset
15344 maintainOffset: false,
15347 * Array of pixel locations the element will snap to if we specified a
15348 * horizontal graduation/interval. This array is generated automatically
15349 * when you define a tick interval.
15356 * Array of pixel locations the element will snap to if we specified a
15357 * vertical graduation/interval. This array is generated automatically
15358 * when you define a tick interval.
15365 * By default the drag and drop instance will only respond to the primary
15366 * button click (left button for a right-handed mouse). Set to true to
15367 * allow drag and drop to start with any mouse click that is propogated
15369 * @property primaryButtonOnly
15372 primaryButtonOnly: true,
15375 * The availabe property is false until the linked dom element is accessible.
15376 * @property available
15382 * By default, drags can only be initiated if the mousedown occurs in the
15383 * region the linked element is. This is done in part to work around a
15384 * bug in some browsers that mis-report the mousedown if the previous
15385 * mouseup happened outside of the window. This property is set to true
15386 * if outer handles are defined.
15388 * @property hasOuterHandles
15392 hasOuterHandles: false,
15395 * Code that executes immediately before the startDrag event
15396 * @method b4StartDrag
15399 b4StartDrag: function(x, y) { },
15402 * Abstract method called after a drag/drop object is clicked
15403 * and the drag or mousedown time thresholds have beeen met.
15404 * @method startDrag
15405 * @param {int} X click location
15406 * @param {int} Y click location
15408 startDrag: function(x, y) { /* override this */ },
15411 * Code that executes immediately before the onDrag event
15415 b4Drag: function(e) { },
15418 * Abstract method called during the onMouseMove event while dragging an
15421 * @param {Event} e the mousemove event
15423 onDrag: function(e) { /* override this */ },
15426 * Abstract method called when this element fist begins hovering over
15427 * another DragDrop obj
15428 * @method onDragEnter
15429 * @param {Event} e the mousemove event
15430 * @param {String|DragDrop[]} id In POINT mode, the element
15431 * id this is hovering over. In INTERSECT mode, an array of one or more
15432 * dragdrop items being hovered over.
15434 onDragEnter: function(e, id) { /* override this */ },
15437 * Code that executes immediately before the onDragOver event
15438 * @method b4DragOver
15441 b4DragOver: function(e) { },
15444 * Abstract method called when this element is hovering over another
15446 * @method onDragOver
15447 * @param {Event} e the mousemove event
15448 * @param {String|DragDrop[]} id In POINT mode, the element
15449 * id this is hovering over. In INTERSECT mode, an array of dd items
15450 * being hovered over.
15452 onDragOver: function(e, id) { /* override this */ },
15455 * Code that executes immediately before the onDragOut event
15456 * @method b4DragOut
15459 b4DragOut: function(e) { },
15462 * Abstract method called when we are no longer hovering over an element
15463 * @method onDragOut
15464 * @param {Event} e the mousemove event
15465 * @param {String|DragDrop[]} id In POINT mode, the element
15466 * id this was hovering over. In INTERSECT mode, an array of dd items
15467 * that the mouse is no longer over.
15469 onDragOut: function(e, id) { /* override this */ },
15472 * Code that executes immediately before the onDragDrop event
15473 * @method b4DragDrop
15476 b4DragDrop: function(e) { },
15479 * Abstract method called when this item is dropped on another DragDrop
15481 * @method onDragDrop
15482 * @param {Event} e the mouseup event
15483 * @param {String|DragDrop[]} id In POINT mode, the element
15484 * id this was dropped on. In INTERSECT mode, an array of dd items this
15487 onDragDrop: function(e, id) { /* override this */ },
15490 * Abstract method called when this item is dropped on an area with no
15492 * @method onInvalidDrop
15493 * @param {Event} e the mouseup event
15495 onInvalidDrop: function(e) { /* override this */ },
15498 * Code that executes immediately before the endDrag event
15499 * @method b4EndDrag
15502 b4EndDrag: function(e) { },
15505 * Fired when we are done dragging the object
15507 * @param {Event} e the mouseup event
15509 endDrag: function(e) { /* override this */ },
15512 * Code executed immediately before the onMouseDown event
15513 * @method b4MouseDown
15514 * @param {Event} e the mousedown event
15517 b4MouseDown: function(e) { },
15520 * Event handler that fires when a drag/drop obj gets a mousedown
15521 * @method onMouseDown
15522 * @param {Event} e the mousedown event
15524 onMouseDown: function(e) { /* override this */ },
15527 * Event handler that fires when a drag/drop obj gets a mouseup
15528 * @method onMouseUp
15529 * @param {Event} e the mouseup event
15531 onMouseUp: function(e) { /* override this */ },
15534 * Override the onAvailable method to do what is needed after the initial
15535 * position was determined.
15536 * @method onAvailable
15538 onAvailable: function () {
15542 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
15545 defaultPadding : {left:0, right:0, top:0, bottom:0},
15548 * Initializes the drag drop object's constraints to restrict movement to a certain element.
15552 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
15553 { dragElId: "existingProxyDiv" });
15554 dd.startDrag = function(){
15555 this.constrainTo("parent-id");
15558 * Or you can initalize it using the {@link Roo.Element} object:
15560 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
15561 startDrag : function(){
15562 this.constrainTo("parent-id");
15566 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
15567 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
15568 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
15569 * an object containing the sides to pad. For example: {right:10, bottom:10}
15570 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
15572 constrainTo : function(constrainTo, pad, inContent){
15573 if(typeof pad == "number"){
15574 pad = {left: pad, right:pad, top:pad, bottom:pad};
15576 pad = pad || this.defaultPadding;
15577 var b = Roo.get(this.getEl()).getBox();
15578 var ce = Roo.get(constrainTo);
15579 var s = ce.getScroll();
15580 var c, cd = ce.dom;
15581 if(cd == document.body){
15582 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
15585 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
15589 var topSpace = b.y - c.y;
15590 var leftSpace = b.x - c.x;
15592 this.resetConstraints();
15593 this.setXConstraint(leftSpace - (pad.left||0), // left
15594 c.width - leftSpace - b.width - (pad.right||0) //right
15596 this.setYConstraint(topSpace - (pad.top||0), //top
15597 c.height - topSpace - b.height - (pad.bottom||0) //bottom
15602 * Returns a reference to the linked element
15604 * @return {HTMLElement} the html element
15606 getEl: function() {
15607 if (!this._domRef) {
15608 this._domRef = Roo.getDom(this.id);
15611 return this._domRef;
15615 * Returns a reference to the actual element to drag. By default this is
15616 * the same as the html element, but it can be assigned to another
15617 * element. An example of this can be found in Roo.dd.DDProxy
15618 * @method getDragEl
15619 * @return {HTMLElement} the html element
15621 getDragEl: function() {
15622 return Roo.getDom(this.dragElId);
15626 * Sets up the DragDrop object. Must be called in the constructor of any
15627 * Roo.dd.DragDrop subclass
15629 * @param id the id of the linked element
15630 * @param {String} sGroup the group of related items
15631 * @param {object} config configuration attributes
15633 init: function(id, sGroup, config) {
15634 this.initTarget(id, sGroup, config);
15635 Event.on(this.id, "mousedown", this.handleMouseDown, this);
15636 // Event.on(this.id, "selectstart", Event.preventDefault);
15640 * Initializes Targeting functionality only... the object does not
15641 * get a mousedown handler.
15642 * @method initTarget
15643 * @param id the id of the linked element
15644 * @param {String} sGroup the group of related items
15645 * @param {object} config configuration attributes
15647 initTarget: function(id, sGroup, config) {
15649 // configuration attributes
15650 this.config = config || {};
15652 // create a local reference to the drag and drop manager
15653 this.DDM = Roo.dd.DDM;
15654 // initialize the groups array
15657 // assume that we have an element reference instead of an id if the
15658 // parameter is not a string
15659 if (typeof id !== "string") {
15666 // add to an interaction group
15667 this.addToGroup((sGroup) ? sGroup : "default");
15669 // We don't want to register this as the handle with the manager
15670 // so we just set the id rather than calling the setter.
15671 this.handleElId = id;
15673 // the linked element is the element that gets dragged by default
15674 this.setDragElId(id);
15676 // by default, clicked anchors will not start drag operations.
15677 this.invalidHandleTypes = { A: "A" };
15678 this.invalidHandleIds = {};
15679 this.invalidHandleClasses = [];
15681 this.applyConfig();
15683 this.handleOnAvailable();
15687 * Applies the configuration parameters that were passed into the constructor.
15688 * This is supposed to happen at each level through the inheritance chain. So
15689 * a DDProxy implentation will execute apply config on DDProxy, DD, and
15690 * DragDrop in order to get all of the parameters that are available in
15692 * @method applyConfig
15694 applyConfig: function() {
15696 // configurable properties:
15697 // padding, isTarget, maintainOffset, primaryButtonOnly
15698 this.padding = this.config.padding || [0, 0, 0, 0];
15699 this.isTarget = (this.config.isTarget !== false);
15700 this.maintainOffset = (this.config.maintainOffset);
15701 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
15706 * Executed when the linked element is available
15707 * @method handleOnAvailable
15710 handleOnAvailable: function() {
15711 this.available = true;
15712 this.resetConstraints();
15713 this.onAvailable();
15717 * Configures the padding for the target zone in px. Effectively expands
15718 * (or reduces) the virtual object size for targeting calculations.
15719 * Supports css-style shorthand; if only one parameter is passed, all sides
15720 * will have that padding, and if only two are passed, the top and bottom
15721 * will have the first param, the left and right the second.
15722 * @method setPadding
15723 * @param {int} iTop Top pad
15724 * @param {int} iRight Right pad
15725 * @param {int} iBot Bot pad
15726 * @param {int} iLeft Left pad
15728 setPadding: function(iTop, iRight, iBot, iLeft) {
15729 // this.padding = [iLeft, iRight, iTop, iBot];
15730 if (!iRight && 0 !== iRight) {
15731 this.padding = [iTop, iTop, iTop, iTop];
15732 } else if (!iBot && 0 !== iBot) {
15733 this.padding = [iTop, iRight, iTop, iRight];
15735 this.padding = [iTop, iRight, iBot, iLeft];
15740 * Stores the initial placement of the linked element.
15741 * @method setInitialPosition
15742 * @param {int} diffX the X offset, default 0
15743 * @param {int} diffY the Y offset, default 0
15745 setInitPosition: function(diffX, diffY) {
15746 var el = this.getEl();
15748 if (!this.DDM.verifyEl(el)) {
15752 var dx = diffX || 0;
15753 var dy = diffY || 0;
15755 var p = Dom.getXY( el );
15757 this.initPageX = p[0] - dx;
15758 this.initPageY = p[1] - dy;
15760 this.lastPageX = p[0];
15761 this.lastPageY = p[1];
15764 this.setStartPosition(p);
15768 * Sets the start position of the element. This is set when the obj
15769 * is initialized, the reset when a drag is started.
15770 * @method setStartPosition
15771 * @param pos current position (from previous lookup)
15774 setStartPosition: function(pos) {
15775 var p = pos || Dom.getXY( this.getEl() );
15776 this.deltaSetXY = null;
15778 this.startPageX = p[0];
15779 this.startPageY = p[1];
15783 * Add this instance to a group of related drag/drop objects. All
15784 * instances belong to at least one group, and can belong to as many
15785 * groups as needed.
15786 * @method addToGroup
15787 * @param sGroup {string} the name of the group
15789 addToGroup: function(sGroup) {
15790 this.groups[sGroup] = true;
15791 this.DDM.regDragDrop(this, sGroup);
15795 * Remove's this instance from the supplied interaction group
15796 * @method removeFromGroup
15797 * @param {string} sGroup The group to drop
15799 removeFromGroup: function(sGroup) {
15800 if (this.groups[sGroup]) {
15801 delete this.groups[sGroup];
15804 this.DDM.removeDDFromGroup(this, sGroup);
15808 * Allows you to specify that an element other than the linked element
15809 * will be moved with the cursor during a drag
15810 * @method setDragElId
15811 * @param id {string} the id of the element that will be used to initiate the drag
15813 setDragElId: function(id) {
15814 this.dragElId = id;
15818 * Allows you to specify a child of the linked element that should be
15819 * used to initiate the drag operation. An example of this would be if
15820 * you have a content div with text and links. Clicking anywhere in the
15821 * content area would normally start the drag operation. Use this method
15822 * to specify that an element inside of the content div is the element
15823 * that starts the drag operation.
15824 * @method setHandleElId
15825 * @param id {string} the id of the element that will be used to
15826 * initiate the drag.
15828 setHandleElId: function(id) {
15829 if (typeof id !== "string") {
15832 this.handleElId = id;
15833 this.DDM.regHandle(this.id, id);
15837 * Allows you to set an element outside of the linked element as a drag
15839 * @method setOuterHandleElId
15840 * @param id the id of the element that will be used to initiate the drag
15842 setOuterHandleElId: function(id) {
15843 if (typeof id !== "string") {
15846 Event.on(id, "mousedown",
15847 this.handleMouseDown, this);
15848 this.setHandleElId(id);
15850 this.hasOuterHandles = true;
15854 * Remove all drag and drop hooks for this element
15857 unreg: function() {
15858 Event.un(this.id, "mousedown",
15859 this.handleMouseDown);
15860 this._domRef = null;
15861 this.DDM._remove(this);
15864 destroy : function(){
15869 * Returns true if this instance is locked, or the drag drop mgr is locked
15870 * (meaning that all drag/drop is disabled on the page.)
15872 * @return {boolean} true if this obj or all drag/drop is locked, else
15875 isLocked: function() {
15876 return (this.DDM.isLocked() || this.locked);
15880 * Fired when this object is clicked
15881 * @method handleMouseDown
15883 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
15886 handleMouseDown: function(e, oDD){
15887 if (this.primaryButtonOnly && e.button != 0) {
15891 if (this.isLocked()) {
15895 this.DDM.refreshCache(this.groups);
15897 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
15898 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
15900 if (this.clickValidator(e)) {
15902 // set the initial element position
15903 this.setStartPosition();
15906 this.b4MouseDown(e);
15907 this.onMouseDown(e);
15909 this.DDM.handleMouseDown(e, this);
15911 this.DDM.stopEvent(e);
15919 clickValidator: function(e) {
15920 var target = e.getTarget();
15921 return ( this.isValidHandleChild(target) &&
15922 (this.id == this.handleElId ||
15923 this.DDM.handleWasClicked(target, this.id)) );
15927 * Allows you to specify a tag name that should not start a drag operation
15928 * when clicked. This is designed to facilitate embedding links within a
15929 * drag handle that do something other than start the drag.
15930 * @method addInvalidHandleType
15931 * @param {string} tagName the type of element to exclude
15933 addInvalidHandleType: function(tagName) {
15934 var type = tagName.toUpperCase();
15935 this.invalidHandleTypes[type] = type;
15939 * Lets you to specify an element id for a child of a drag handle
15940 * that should not initiate a drag
15941 * @method addInvalidHandleId
15942 * @param {string} id the element id of the element you wish to ignore
15944 addInvalidHandleId: function(id) {
15945 if (typeof id !== "string") {
15948 this.invalidHandleIds[id] = id;
15952 * Lets you specify a css class of elements that will not initiate a drag
15953 * @method addInvalidHandleClass
15954 * @param {string} cssClass the class of the elements you wish to ignore
15956 addInvalidHandleClass: function(cssClass) {
15957 this.invalidHandleClasses.push(cssClass);
15961 * Unsets an excluded tag name set by addInvalidHandleType
15962 * @method removeInvalidHandleType
15963 * @param {string} tagName the type of element to unexclude
15965 removeInvalidHandleType: function(tagName) {
15966 var type = tagName.toUpperCase();
15967 // this.invalidHandleTypes[type] = null;
15968 delete this.invalidHandleTypes[type];
15972 * Unsets an invalid handle id
15973 * @method removeInvalidHandleId
15974 * @param {string} id the id of the element to re-enable
15976 removeInvalidHandleId: function(id) {
15977 if (typeof id !== "string") {
15980 delete this.invalidHandleIds[id];
15984 * Unsets an invalid css class
15985 * @method removeInvalidHandleClass
15986 * @param {string} cssClass the class of the element(s) you wish to
15989 removeInvalidHandleClass: function(cssClass) {
15990 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
15991 if (this.invalidHandleClasses[i] == cssClass) {
15992 delete this.invalidHandleClasses[i];
15998 * Checks the tag exclusion list to see if this click should be ignored
15999 * @method isValidHandleChild
16000 * @param {HTMLElement} node the HTMLElement to evaluate
16001 * @return {boolean} true if this is a valid tag type, false if not
16003 isValidHandleChild: function(node) {
16006 // var n = (node.nodeName == "#text") ? node.parentNode : node;
16009 nodeName = node.nodeName.toUpperCase();
16011 nodeName = node.nodeName;
16013 valid = valid && !this.invalidHandleTypes[nodeName];
16014 valid = valid && !this.invalidHandleIds[node.id];
16016 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
16017 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
16026 * Create the array of horizontal tick marks if an interval was specified
16027 * in setXConstraint().
16028 * @method setXTicks
16031 setXTicks: function(iStartX, iTickSize) {
16033 this.xTickSize = iTickSize;
16037 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
16039 this.xTicks[this.xTicks.length] = i;
16044 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
16046 this.xTicks[this.xTicks.length] = i;
16051 this.xTicks.sort(this.DDM.numericSort) ;
16055 * Create the array of vertical tick marks if an interval was specified in
16056 * setYConstraint().
16057 * @method setYTicks
16060 setYTicks: function(iStartY, iTickSize) {
16062 this.yTickSize = iTickSize;
16066 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
16068 this.yTicks[this.yTicks.length] = i;
16073 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
16075 this.yTicks[this.yTicks.length] = i;
16080 this.yTicks.sort(this.DDM.numericSort) ;
16084 * By default, the element can be dragged any place on the screen. Use
16085 * this method to limit the horizontal travel of the element. Pass in
16086 * 0,0 for the parameters if you want to lock the drag to the y axis.
16087 * @method setXConstraint
16088 * @param {int} iLeft the number of pixels the element can move to the left
16089 * @param {int} iRight the number of pixels the element can move to the
16091 * @param {int} iTickSize optional parameter for specifying that the
16093 * should move iTickSize pixels at a time.
16095 setXConstraint: function(iLeft, iRight, iTickSize) {
16096 this.leftConstraint = iLeft;
16097 this.rightConstraint = iRight;
16099 this.minX = this.initPageX - iLeft;
16100 this.maxX = this.initPageX + iRight;
16101 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
16103 this.constrainX = true;
16107 * Clears any constraints applied to this instance. Also clears ticks
16108 * since they can't exist independent of a constraint at this time.
16109 * @method clearConstraints
16111 clearConstraints: function() {
16112 this.constrainX = false;
16113 this.constrainY = false;
16118 * Clears any tick interval defined for this instance
16119 * @method clearTicks
16121 clearTicks: function() {
16122 this.xTicks = null;
16123 this.yTicks = null;
16124 this.xTickSize = 0;
16125 this.yTickSize = 0;
16129 * By default, the element can be dragged any place on the screen. Set
16130 * this to limit the vertical travel of the element. Pass in 0,0 for the
16131 * parameters if you want to lock the drag to the x axis.
16132 * @method setYConstraint
16133 * @param {int} iUp the number of pixels the element can move up
16134 * @param {int} iDown the number of pixels the element can move down
16135 * @param {int} iTickSize optional parameter for specifying that the
16136 * element should move iTickSize pixels at a time.
16138 setYConstraint: function(iUp, iDown, iTickSize) {
16139 this.topConstraint = iUp;
16140 this.bottomConstraint = iDown;
16142 this.minY = this.initPageY - iUp;
16143 this.maxY = this.initPageY + iDown;
16144 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
16146 this.constrainY = true;
16151 * resetConstraints must be called if you manually reposition a dd element.
16152 * @method resetConstraints
16153 * @param {boolean} maintainOffset
16155 resetConstraints: function() {
16158 // Maintain offsets if necessary
16159 if (this.initPageX || this.initPageX === 0) {
16160 // figure out how much this thing has moved
16161 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
16162 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
16164 this.setInitPosition(dx, dy);
16166 // This is the first time we have detected the element's position
16168 this.setInitPosition();
16171 if (this.constrainX) {
16172 this.setXConstraint( this.leftConstraint,
16173 this.rightConstraint,
16177 if (this.constrainY) {
16178 this.setYConstraint( this.topConstraint,
16179 this.bottomConstraint,
16185 * Normally the drag element is moved pixel by pixel, but we can specify
16186 * that it move a number of pixels at a time. This method resolves the
16187 * location when we have it set up like this.
16189 * @param {int} val where we want to place the object
16190 * @param {int[]} tickArray sorted array of valid points
16191 * @return {int} the closest tick
16194 getTick: function(val, tickArray) {
16197 // If tick interval is not defined, it is effectively 1 pixel,
16198 // so we return the value passed to us.
16200 } else if (tickArray[0] >= val) {
16201 // The value is lower than the first tick, so we return the first
16203 return tickArray[0];
16205 for (var i=0, len=tickArray.length; i<len; ++i) {
16207 if (tickArray[next] && tickArray[next] >= val) {
16208 var diff1 = val - tickArray[i];
16209 var diff2 = tickArray[next] - val;
16210 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
16214 // The value is larger than the last tick, so we return the last
16216 return tickArray[tickArray.length - 1];
16223 * @return {string} string representation of the dd obj
16225 toString: function() {
16226 return ("DragDrop " + this.id);
16234 * Ext JS Library 1.1.1
16235 * Copyright(c) 2006-2007, Ext JS, LLC.
16237 * Originally Released Under LGPL - original licence link has changed is not relivant.
16240 * <script type="text/javascript">
16245 * The drag and drop utility provides a framework for building drag and drop
16246 * applications. In addition to enabling drag and drop for specific elements,
16247 * the drag and drop elements are tracked by the manager class, and the
16248 * interactions between the various elements are tracked during the drag and
16249 * the implementing code is notified about these important moments.
16252 // Only load the library once. Rewriting the manager class would orphan
16253 // existing drag and drop instances.
16254 if (!Roo.dd.DragDropMgr) {
16257 * @class Roo.dd.DragDropMgr
16258 * DragDropMgr is a singleton that tracks the element interaction for
16259 * all DragDrop items in the window. Generally, you will not call
16260 * this class directly, but it does have helper methods that could
16261 * be useful in your DragDrop implementations.
16264 Roo.dd.DragDropMgr = function() {
16266 var Event = Roo.EventManager;
16271 * Two dimensional Array of registered DragDrop objects. The first
16272 * dimension is the DragDrop item group, the second the DragDrop
16275 * @type {string: string}
16282 * Array of element ids defined as drag handles. Used to determine
16283 * if the element that generated the mousedown event is actually the
16284 * handle and not the html element itself.
16285 * @property handleIds
16286 * @type {string: string}
16293 * the DragDrop object that is currently being dragged
16294 * @property dragCurrent
16302 * the DragDrop object(s) that are being hovered over
16303 * @property dragOvers
16311 * the X distance between the cursor and the object being dragged
16320 * the Y distance between the cursor and the object being dragged
16329 * Flag to determine if we should prevent the default behavior of the
16330 * events we define. By default this is true, but this can be set to
16331 * false if you need the default behavior (not recommended)
16332 * @property preventDefault
16336 preventDefault: true,
16339 * Flag to determine if we should stop the propagation of the events
16340 * we generate. This is true by default but you may want to set it to
16341 * false if the html element contains other features that require the
16343 * @property stopPropagation
16347 stopPropagation: true,
16350 * Internal flag that is set to true when drag and drop has been
16352 * @property initialized
16359 * All drag and drop can be disabled.
16367 * Called the first time an element is registered.
16373 this.initialized = true;
16377 * In point mode, drag and drop interaction is defined by the
16378 * location of the cursor during the drag/drop
16386 * In intersect mode, drag and drop interactio nis defined by the
16387 * overlap of two or more drag and drop objects.
16388 * @property INTERSECT
16395 * The current drag and drop mode. Default: POINT
16403 * Runs method on all drag and drop objects
16404 * @method _execOnAll
16408 _execOnAll: function(sMethod, args) {
16409 for (var i in this.ids) {
16410 for (var j in this.ids[i]) {
16411 var oDD = this.ids[i][j];
16412 if (! this.isTypeOfDD(oDD)) {
16415 oDD[sMethod].apply(oDD, args);
16421 * Drag and drop initialization. Sets up the global event handlers
16426 _onLoad: function() {
16431 Event.on(document, "mouseup", this.handleMouseUp, this, true);
16432 Event.on(document, "mousemove", this.handleMouseMove, this, true);
16433 Event.on(window, "unload", this._onUnload, this, true);
16434 Event.on(window, "resize", this._onResize, this, true);
16435 // Event.on(window, "mouseout", this._test);
16440 * Reset constraints on all drag and drop objs
16441 * @method _onResize
16445 _onResize: function(e) {
16446 this._execOnAll("resetConstraints", []);
16450 * Lock all drag and drop functionality
16454 lock: function() { this.locked = true; },
16457 * Unlock all drag and drop functionality
16461 unlock: function() { this.locked = false; },
16464 * Is drag and drop locked?
16466 * @return {boolean} True if drag and drop is locked, false otherwise.
16469 isLocked: function() { return this.locked; },
16472 * Location cache that is set for all drag drop objects when a drag is
16473 * initiated, cleared when the drag is finished.
16474 * @property locationCache
16481 * Set useCache to false if you want to force object the lookup of each
16482 * drag and drop linked element constantly during a drag.
16483 * @property useCache
16490 * The number of pixels that the mouse needs to move after the
16491 * mousedown before the drag is initiated. Default=3;
16492 * @property clickPixelThresh
16496 clickPixelThresh: 3,
16499 * The number of milliseconds after the mousedown event to initiate the
16500 * drag if we don't get a mouseup event. Default=1000
16501 * @property clickTimeThresh
16505 clickTimeThresh: 350,
16508 * Flag that indicates that either the drag pixel threshold or the
16509 * mousdown time threshold has been met
16510 * @property dragThreshMet
16515 dragThreshMet: false,
16518 * Timeout used for the click time threshold
16519 * @property clickTimeout
16524 clickTimeout: null,
16527 * The X position of the mousedown event stored for later use when a
16528 * drag threshold is met.
16537 * The Y position of the mousedown event stored for later use when a
16538 * drag threshold is met.
16547 * Each DragDrop instance must be registered with the DragDropMgr.
16548 * This is executed in DragDrop.init()
16549 * @method regDragDrop
16550 * @param {DragDrop} oDD the DragDrop object to register
16551 * @param {String} sGroup the name of the group this element belongs to
16554 regDragDrop: function(oDD, sGroup) {
16555 if (!this.initialized) { this.init(); }
16557 if (!this.ids[sGroup]) {
16558 this.ids[sGroup] = {};
16560 this.ids[sGroup][oDD.id] = oDD;
16564 * Removes the supplied dd instance from the supplied group. Executed
16565 * by DragDrop.removeFromGroup, so don't call this function directly.
16566 * @method removeDDFromGroup
16570 removeDDFromGroup: function(oDD, sGroup) {
16571 if (!this.ids[sGroup]) {
16572 this.ids[sGroup] = {};
16575 var obj = this.ids[sGroup];
16576 if (obj && obj[oDD.id]) {
16577 delete obj[oDD.id];
16582 * Unregisters a drag and drop item. This is executed in
16583 * DragDrop.unreg, use that method instead of calling this directly.
16588 _remove: function(oDD) {
16589 for (var g in oDD.groups) {
16590 if (g && this.ids[g][oDD.id]) {
16591 delete this.ids[g][oDD.id];
16594 delete this.handleIds[oDD.id];
16598 * Each DragDrop handle element must be registered. This is done
16599 * automatically when executing DragDrop.setHandleElId()
16600 * @method regHandle
16601 * @param {String} sDDId the DragDrop id this element is a handle for
16602 * @param {String} sHandleId the id of the element that is the drag
16606 regHandle: function(sDDId, sHandleId) {
16607 if (!this.handleIds[sDDId]) {
16608 this.handleIds[sDDId] = {};
16610 this.handleIds[sDDId][sHandleId] = sHandleId;
16614 * Utility function to determine if a given element has been
16615 * registered as a drag drop item.
16616 * @method isDragDrop
16617 * @param {String} id the element id to check
16618 * @return {boolean} true if this element is a DragDrop item,
16622 isDragDrop: function(id) {
16623 return ( this.getDDById(id) ) ? true : false;
16627 * Returns the drag and drop instances that are in all groups the
16628 * passed in instance belongs to.
16629 * @method getRelated
16630 * @param {DragDrop} p_oDD the obj to get related data for
16631 * @param {boolean} bTargetsOnly if true, only return targetable objs
16632 * @return {DragDrop[]} the related instances
16635 getRelated: function(p_oDD, bTargetsOnly) {
16637 for (var i in p_oDD.groups) {
16638 for (j in this.ids[i]) {
16639 var dd = this.ids[i][j];
16640 if (! this.isTypeOfDD(dd)) {
16643 if (!bTargetsOnly || dd.isTarget) {
16644 oDDs[oDDs.length] = dd;
16653 * Returns true if the specified dd target is a legal target for
16654 * the specifice drag obj
16655 * @method isLegalTarget
16656 * @param {DragDrop} the drag obj
16657 * @param {DragDrop} the target
16658 * @return {boolean} true if the target is a legal target for the
16662 isLegalTarget: function (oDD, oTargetDD) {
16663 var targets = this.getRelated(oDD, true);
16664 for (var i=0, len=targets.length;i<len;++i) {
16665 if (targets[i].id == oTargetDD.id) {
16674 * My goal is to be able to transparently determine if an object is
16675 * typeof DragDrop, and the exact subclass of DragDrop. typeof
16676 * returns "object", oDD.constructor.toString() always returns
16677 * "DragDrop" and not the name of the subclass. So for now it just
16678 * evaluates a well-known variable in DragDrop.
16679 * @method isTypeOfDD
16680 * @param {Object} the object to evaluate
16681 * @return {boolean} true if typeof oDD = DragDrop
16684 isTypeOfDD: function (oDD) {
16685 return (oDD && oDD.__ygDragDrop);
16689 * Utility function to determine if a given element has been
16690 * registered as a drag drop handle for the given Drag Drop object.
16692 * @param {String} id the element id to check
16693 * @return {boolean} true if this element is a DragDrop handle, false
16697 isHandle: function(sDDId, sHandleId) {
16698 return ( this.handleIds[sDDId] &&
16699 this.handleIds[sDDId][sHandleId] );
16703 * Returns the DragDrop instance for a given id
16704 * @method getDDById
16705 * @param {String} id the id of the DragDrop object
16706 * @return {DragDrop} the drag drop object, null if it is not found
16709 getDDById: function(id) {
16710 for (var i in this.ids) {
16711 if (this.ids[i][id]) {
16712 return this.ids[i][id];
16719 * Fired after a registered DragDrop object gets the mousedown event.
16720 * Sets up the events required to track the object being dragged
16721 * @method handleMouseDown
16722 * @param {Event} e the event
16723 * @param oDD the DragDrop object being dragged
16727 handleMouseDown: function(e, oDD) {
16729 Roo.QuickTips.disable();
16731 this.currentTarget = e.getTarget();
16733 this.dragCurrent = oDD;
16735 var el = oDD.getEl();
16737 // track start position
16738 this.startX = e.getPageX();
16739 this.startY = e.getPageY();
16741 this.deltaX = this.startX - el.offsetLeft;
16742 this.deltaY = this.startY - el.offsetTop;
16744 this.dragThreshMet = false;
16746 this.clickTimeout = setTimeout(
16748 var DDM = Roo.dd.DDM;
16749 DDM.startDrag(DDM.startX, DDM.startY);
16751 this.clickTimeThresh );
16755 * Fired when either the drag pixel threshol or the mousedown hold
16756 * time threshold has been met.
16757 * @method startDrag
16758 * @param x {int} the X position of the original mousedown
16759 * @param y {int} the Y position of the original mousedown
16762 startDrag: function(x, y) {
16763 clearTimeout(this.clickTimeout);
16764 if (this.dragCurrent) {
16765 this.dragCurrent.b4StartDrag(x, y);
16766 this.dragCurrent.startDrag(x, y);
16768 this.dragThreshMet = true;
16772 * Internal function to handle the mouseup event. Will be invoked
16773 * from the context of the document.
16774 * @method handleMouseUp
16775 * @param {Event} e the event
16779 handleMouseUp: function(e) {
16782 Roo.QuickTips.enable();
16784 if (! this.dragCurrent) {
16788 clearTimeout(this.clickTimeout);
16790 if (this.dragThreshMet) {
16791 this.fireEvents(e, true);
16801 * Utility to stop event propagation and event default, if these
16802 * features are turned on.
16803 * @method stopEvent
16804 * @param {Event} e the event as returned by this.getEvent()
16807 stopEvent: function(e){
16808 if(this.stopPropagation) {
16809 e.stopPropagation();
16812 if (this.preventDefault) {
16813 e.preventDefault();
16818 * Internal function to clean up event handlers after the drag
16819 * operation is complete
16821 * @param {Event} e the event
16825 stopDrag: function(e) {
16826 // Fire the drag end event for the item that was dragged
16827 if (this.dragCurrent) {
16828 if (this.dragThreshMet) {
16829 this.dragCurrent.b4EndDrag(e);
16830 this.dragCurrent.endDrag(e);
16833 this.dragCurrent.onMouseUp(e);
16836 this.dragCurrent = null;
16837 this.dragOvers = {};
16841 * Internal function to handle the mousemove event. Will be invoked
16842 * from the context of the html element.
16844 * @TODO figure out what we can do about mouse events lost when the
16845 * user drags objects beyond the window boundary. Currently we can
16846 * detect this in internet explorer by verifying that the mouse is
16847 * down during the mousemove event. Firefox doesn't give us the
16848 * button state on the mousemove event.
16849 * @method handleMouseMove
16850 * @param {Event} e the event
16854 handleMouseMove: function(e) {
16855 if (! this.dragCurrent) {
16859 // var button = e.which || e.button;
16861 // check for IE mouseup outside of page boundary
16862 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
16864 return this.handleMouseUp(e);
16867 if (!this.dragThreshMet) {
16868 var diffX = Math.abs(this.startX - e.getPageX());
16869 var diffY = Math.abs(this.startY - e.getPageY());
16870 if (diffX > this.clickPixelThresh ||
16871 diffY > this.clickPixelThresh) {
16872 this.startDrag(this.startX, this.startY);
16876 if (this.dragThreshMet) {
16877 this.dragCurrent.b4Drag(e);
16878 this.dragCurrent.onDrag(e);
16879 if(!this.dragCurrent.moveOnly){
16880 this.fireEvents(e, false);
16890 * Iterates over all of the DragDrop elements to find ones we are
16891 * hovering over or dropping on
16892 * @method fireEvents
16893 * @param {Event} e the event
16894 * @param {boolean} isDrop is this a drop op or a mouseover op?
16898 fireEvents: function(e, isDrop) {
16899 var dc = this.dragCurrent;
16901 // If the user did the mouse up outside of the window, we could
16902 // get here even though we have ended the drag.
16903 if (!dc || dc.isLocked()) {
16907 var pt = e.getPoint();
16909 // cache the previous dragOver array
16915 var enterEvts = [];
16917 // Check to see if the object(s) we were hovering over is no longer
16918 // being hovered over so we can fire the onDragOut event
16919 for (var i in this.dragOvers) {
16921 var ddo = this.dragOvers[i];
16923 if (! this.isTypeOfDD(ddo)) {
16927 if (! this.isOverTarget(pt, ddo, this.mode)) {
16928 outEvts.push( ddo );
16931 oldOvers[i] = true;
16932 delete this.dragOvers[i];
16935 for (var sGroup in dc.groups) {
16937 if ("string" != typeof sGroup) {
16941 for (i in this.ids[sGroup]) {
16942 var oDD = this.ids[sGroup][i];
16943 if (! this.isTypeOfDD(oDD)) {
16947 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
16948 if (this.isOverTarget(pt, oDD, this.mode)) {
16949 // look for drop interactions
16951 dropEvts.push( oDD );
16952 // look for drag enter and drag over interactions
16955 // initial drag over: dragEnter fires
16956 if (!oldOvers[oDD.id]) {
16957 enterEvts.push( oDD );
16958 // subsequent drag overs: dragOver fires
16960 overEvts.push( oDD );
16963 this.dragOvers[oDD.id] = oDD;
16971 if (outEvts.length) {
16972 dc.b4DragOut(e, outEvts);
16973 dc.onDragOut(e, outEvts);
16976 if (enterEvts.length) {
16977 dc.onDragEnter(e, enterEvts);
16980 if (overEvts.length) {
16981 dc.b4DragOver(e, overEvts);
16982 dc.onDragOver(e, overEvts);
16985 if (dropEvts.length) {
16986 dc.b4DragDrop(e, dropEvts);
16987 dc.onDragDrop(e, dropEvts);
16991 // fire dragout events
16993 for (i=0, len=outEvts.length; i<len; ++i) {
16994 dc.b4DragOut(e, outEvts[i].id);
16995 dc.onDragOut(e, outEvts[i].id);
16998 // fire enter events
16999 for (i=0,len=enterEvts.length; i<len; ++i) {
17000 // dc.b4DragEnter(e, oDD.id);
17001 dc.onDragEnter(e, enterEvts[i].id);
17004 // fire over events
17005 for (i=0,len=overEvts.length; i<len; ++i) {
17006 dc.b4DragOver(e, overEvts[i].id);
17007 dc.onDragOver(e, overEvts[i].id);
17010 // fire drop events
17011 for (i=0, len=dropEvts.length; i<len; ++i) {
17012 dc.b4DragDrop(e, dropEvts[i].id);
17013 dc.onDragDrop(e, dropEvts[i].id);
17018 // notify about a drop that did not find a target
17019 if (isDrop && !dropEvts.length) {
17020 dc.onInvalidDrop(e);
17026 * Helper function for getting the best match from the list of drag
17027 * and drop objects returned by the drag and drop events when we are
17028 * in INTERSECT mode. It returns either the first object that the
17029 * cursor is over, or the object that has the greatest overlap with
17030 * the dragged element.
17031 * @method getBestMatch
17032 * @param {DragDrop[]} dds The array of drag and drop objects
17034 * @return {DragDrop} The best single match
17037 getBestMatch: function(dds) {
17039 // Return null if the input is not what we expect
17040 //if (!dds || !dds.length || dds.length == 0) {
17042 // If there is only one item, it wins
17043 //} else if (dds.length == 1) {
17045 var len = dds.length;
17050 // Loop through the targeted items
17051 for (var i=0; i<len; ++i) {
17053 // If the cursor is over the object, it wins. If the
17054 // cursor is over multiple matches, the first one we come
17056 if (dd.cursorIsOver) {
17059 // Otherwise the object with the most overlap wins
17062 winner.overlap.getArea() < dd.overlap.getArea()) {
17073 * Refreshes the cache of the top-left and bottom-right points of the
17074 * drag and drop objects in the specified group(s). This is in the
17075 * format that is stored in the drag and drop instance, so typical
17078 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
17082 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
17084 * @TODO this really should be an indexed array. Alternatively this
17085 * method could accept both.
17086 * @method refreshCache
17087 * @param {Object} groups an associative array of groups to refresh
17090 refreshCache: function(groups) {
17091 for (var sGroup in groups) {
17092 if ("string" != typeof sGroup) {
17095 for (var i in this.ids[sGroup]) {
17096 var oDD = this.ids[sGroup][i];
17098 if (this.isTypeOfDD(oDD)) {
17099 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
17100 var loc = this.getLocation(oDD);
17102 this.locationCache[oDD.id] = loc;
17104 delete this.locationCache[oDD.id];
17105 // this will unregister the drag and drop object if
17106 // the element is not in a usable state
17115 * This checks to make sure an element exists and is in the DOM. The
17116 * main purpose is to handle cases where innerHTML is used to remove
17117 * drag and drop objects from the DOM. IE provides an 'unspecified
17118 * error' when trying to access the offsetParent of such an element
17120 * @param {HTMLElement} el the element to check
17121 * @return {boolean} true if the element looks usable
17124 verifyEl: function(el) {
17129 parent = el.offsetParent;
17132 parent = el.offsetParent;
17143 * Returns a Region object containing the drag and drop element's position
17144 * and size, including the padding configured for it
17145 * @method getLocation
17146 * @param {DragDrop} oDD the drag and drop object to get the
17148 * @return {Roo.lib.Region} a Region object representing the total area
17149 * the element occupies, including any padding
17150 * the instance is configured for.
17153 getLocation: function(oDD) {
17154 if (! this.isTypeOfDD(oDD)) {
17158 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
17161 pos= Roo.lib.Dom.getXY(el);
17169 x2 = x1 + el.offsetWidth;
17171 y2 = y1 + el.offsetHeight;
17173 t = y1 - oDD.padding[0];
17174 r = x2 + oDD.padding[1];
17175 b = y2 + oDD.padding[2];
17176 l = x1 - oDD.padding[3];
17178 return new Roo.lib.Region( t, r, b, l );
17182 * Checks the cursor location to see if it over the target
17183 * @method isOverTarget
17184 * @param {Roo.lib.Point} pt The point to evaluate
17185 * @param {DragDrop} oTarget the DragDrop object we are inspecting
17186 * @return {boolean} true if the mouse is over the target
17190 isOverTarget: function(pt, oTarget, intersect) {
17191 // use cache if available
17192 var loc = this.locationCache[oTarget.id];
17193 if (!loc || !this.useCache) {
17194 loc = this.getLocation(oTarget);
17195 this.locationCache[oTarget.id] = loc;
17203 oTarget.cursorIsOver = loc.contains( pt );
17205 // DragDrop is using this as a sanity check for the initial mousedown
17206 // in this case we are done. In POINT mode, if the drag obj has no
17207 // contraints, we are also done. Otherwise we need to evaluate the
17208 // location of the target as related to the actual location of the
17209 // dragged element.
17210 var dc = this.dragCurrent;
17211 if (!dc || !dc.getTargetCoord ||
17212 (!intersect && !dc.constrainX && !dc.constrainY)) {
17213 return oTarget.cursorIsOver;
17216 oTarget.overlap = null;
17218 // Get the current location of the drag element, this is the
17219 // location of the mouse event less the delta that represents
17220 // where the original mousedown happened on the element. We
17221 // need to consider constraints and ticks as well.
17222 var pos = dc.getTargetCoord(pt.x, pt.y);
17224 var el = dc.getDragEl();
17225 var curRegion = new Roo.lib.Region( pos.y,
17226 pos.x + el.offsetWidth,
17227 pos.y + el.offsetHeight,
17230 var overlap = curRegion.intersect(loc);
17233 oTarget.overlap = overlap;
17234 return (intersect) ? true : oTarget.cursorIsOver;
17241 * unload event handler
17242 * @method _onUnload
17246 _onUnload: function(e, me) {
17247 Roo.dd.DragDropMgr.unregAll();
17251 * Cleans up the drag and drop events and objects.
17256 unregAll: function() {
17258 if (this.dragCurrent) {
17260 this.dragCurrent = null;
17263 this._execOnAll("unreg", []);
17265 for (i in this.elementCache) {
17266 delete this.elementCache[i];
17269 this.elementCache = {};
17274 * A cache of DOM elements
17275 * @property elementCache
17282 * Get the wrapper for the DOM element specified
17283 * @method getElWrapper
17284 * @param {String} id the id of the element to get
17285 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
17287 * @deprecated This wrapper isn't that useful
17290 getElWrapper: function(id) {
17291 var oWrapper = this.elementCache[id];
17292 if (!oWrapper || !oWrapper.el) {
17293 oWrapper = this.elementCache[id] =
17294 new this.ElementWrapper(Roo.getDom(id));
17300 * Returns the actual DOM element
17301 * @method getElement
17302 * @param {String} id the id of the elment to get
17303 * @return {Object} The element
17304 * @deprecated use Roo.getDom instead
17307 getElement: function(id) {
17308 return Roo.getDom(id);
17312 * Returns the style property for the DOM element (i.e.,
17313 * document.getElById(id).style)
17315 * @param {String} id the id of the elment to get
17316 * @return {Object} The style property of the element
17317 * @deprecated use Roo.getDom instead
17320 getCss: function(id) {
17321 var el = Roo.getDom(id);
17322 return (el) ? el.style : null;
17326 * Inner class for cached elements
17327 * @class DragDropMgr.ElementWrapper
17332 ElementWrapper: function(el) {
17337 this.el = el || null;
17342 this.id = this.el && el.id;
17344 * A reference to the style property
17347 this.css = this.el && el.style;
17351 * Returns the X position of an html element
17353 * @param el the element for which to get the position
17354 * @return {int} the X coordinate
17356 * @deprecated use Roo.lib.Dom.getX instead
17359 getPosX: function(el) {
17360 return Roo.lib.Dom.getX(el);
17364 * Returns the Y position of an html element
17366 * @param el the element for which to get the position
17367 * @return {int} the Y coordinate
17368 * @deprecated use Roo.lib.Dom.getY instead
17371 getPosY: function(el) {
17372 return Roo.lib.Dom.getY(el);
17376 * Swap two nodes. In IE, we use the native method, for others we
17377 * emulate the IE behavior
17379 * @param n1 the first node to swap
17380 * @param n2 the other node to swap
17383 swapNode: function(n1, n2) {
17387 var p = n2.parentNode;
17388 var s = n2.nextSibling;
17391 p.insertBefore(n1, n2);
17392 } else if (n2 == n1.nextSibling) {
17393 p.insertBefore(n2, n1);
17395 n1.parentNode.replaceChild(n2, n1);
17396 p.insertBefore(n1, s);
17402 * Returns the current scroll position
17403 * @method getScroll
17407 getScroll: function () {
17408 var t, l, dde=document.documentElement, db=document.body;
17409 if (dde && (dde.scrollTop || dde.scrollLeft)) {
17411 l = dde.scrollLeft;
17418 return { top: t, left: l };
17422 * Returns the specified element style property
17424 * @param {HTMLElement} el the element
17425 * @param {string} styleProp the style property
17426 * @return {string} The value of the style property
17427 * @deprecated use Roo.lib.Dom.getStyle
17430 getStyle: function(el, styleProp) {
17431 return Roo.fly(el).getStyle(styleProp);
17435 * Gets the scrollTop
17436 * @method getScrollTop
17437 * @return {int} the document's scrollTop
17440 getScrollTop: function () { return this.getScroll().top; },
17443 * Gets the scrollLeft
17444 * @method getScrollLeft
17445 * @return {int} the document's scrollTop
17448 getScrollLeft: function () { return this.getScroll().left; },
17451 * Sets the x/y position of an element to the location of the
17454 * @param {HTMLElement} moveEl The element to move
17455 * @param {HTMLElement} targetEl The position reference element
17458 moveToEl: function (moveEl, targetEl) {
17459 var aCoord = Roo.lib.Dom.getXY(targetEl);
17460 Roo.lib.Dom.setXY(moveEl, aCoord);
17464 * Numeric array sort function
17465 * @method numericSort
17468 numericSort: function(a, b) { return (a - b); },
17472 * @property _timeoutCount
17479 * Trying to make the load order less important. Without this we get
17480 * an error if this file is loaded before the Event Utility.
17481 * @method _addListeners
17485 _addListeners: function() {
17486 var DDM = Roo.dd.DDM;
17487 if ( Roo.lib.Event && document ) {
17490 if (DDM._timeoutCount > 2000) {
17492 setTimeout(DDM._addListeners, 10);
17493 if (document && document.body) {
17494 DDM._timeoutCount += 1;
17501 * Recursively searches the immediate parent and all child nodes for
17502 * the handle element in order to determine wheter or not it was
17504 * @method handleWasClicked
17505 * @param node the html element to inspect
17508 handleWasClicked: function(node, id) {
17509 if (this.isHandle(id, node.id)) {
17512 // check to see if this is a text node child of the one we want
17513 var p = node.parentNode;
17516 if (this.isHandle(id, p.id)) {
17531 // shorter alias, save a few bytes
17532 Roo.dd.DDM = Roo.dd.DragDropMgr;
17533 Roo.dd.DDM._addListeners();
17537 * Ext JS Library 1.1.1
17538 * Copyright(c) 2006-2007, Ext JS, LLC.
17540 * Originally Released Under LGPL - original licence link has changed is not relivant.
17543 * <script type="text/javascript">
17548 * A DragDrop implementation where the linked element follows the
17549 * mouse cursor during a drag.
17550 * @extends Roo.dd.DragDrop
17552 * @param {String} id the id of the linked element
17553 * @param {String} sGroup the group of related DragDrop items
17554 * @param {object} config an object containing configurable attributes
17555 * Valid properties for DD:
17558 Roo.dd.DD = function(id, sGroup, config) {
17560 this.init(id, sGroup, config);
17564 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
17567 * When set to true, the utility automatically tries to scroll the browser
17568 * window wehn a drag and drop element is dragged near the viewport boundary.
17569 * Defaults to true.
17576 * Sets the pointer offset to the distance between the linked element's top
17577 * left corner and the location the element was clicked
17578 * @method autoOffset
17579 * @param {int} iPageX the X coordinate of the click
17580 * @param {int} iPageY the Y coordinate of the click
17582 autoOffset: function(iPageX, iPageY) {
17583 var x = iPageX - this.startPageX;
17584 var y = iPageY - this.startPageY;
17585 this.setDelta(x, y);
17589 * Sets the pointer offset. You can call this directly to force the
17590 * offset to be in a particular location (e.g., pass in 0,0 to set it
17591 * to the center of the object)
17593 * @param {int} iDeltaX the distance from the left
17594 * @param {int} iDeltaY the distance from the top
17596 setDelta: function(iDeltaX, iDeltaY) {
17597 this.deltaX = iDeltaX;
17598 this.deltaY = iDeltaY;
17602 * Sets the drag element to the location of the mousedown or click event,
17603 * maintaining the cursor location relative to the location on the element
17604 * that was clicked. Override this if you want to place the element in a
17605 * location other than where the cursor is.
17606 * @method setDragElPos
17607 * @param {int} iPageX the X coordinate of the mousedown or drag event
17608 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17610 setDragElPos: function(iPageX, iPageY) {
17611 // the first time we do this, we are going to check to make sure
17612 // the element has css positioning
17614 var el = this.getDragEl();
17615 this.alignElWithMouse(el, iPageX, iPageY);
17619 * Sets the element to the location of the mousedown or click event,
17620 * maintaining the cursor location relative to the location on the element
17621 * that was clicked. Override this if you want to place the element in a
17622 * location other than where the cursor is.
17623 * @method alignElWithMouse
17624 * @param {HTMLElement} el the element to move
17625 * @param {int} iPageX the X coordinate of the mousedown or drag event
17626 * @param {int} iPageY the Y coordinate of the mousedown or drag event
17628 alignElWithMouse: function(el, iPageX, iPageY) {
17629 var oCoord = this.getTargetCoord(iPageX, iPageY);
17630 var fly = el.dom ? el : Roo.fly(el);
17631 if (!this.deltaSetXY) {
17632 var aCoord = [oCoord.x, oCoord.y];
17634 var newLeft = fly.getLeft(true);
17635 var newTop = fly.getTop(true);
17636 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
17638 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
17641 this.cachePosition(oCoord.x, oCoord.y);
17642 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
17647 * Saves the most recent position so that we can reset the constraints and
17648 * tick marks on-demand. We need to know this so that we can calculate the
17649 * number of pixels the element is offset from its original position.
17650 * @method cachePosition
17651 * @param iPageX the current x position (optional, this just makes it so we
17652 * don't have to look it up again)
17653 * @param iPageY the current y position (optional, this just makes it so we
17654 * don't have to look it up again)
17656 cachePosition: function(iPageX, iPageY) {
17658 this.lastPageX = iPageX;
17659 this.lastPageY = iPageY;
17661 var aCoord = Roo.lib.Dom.getXY(this.getEl());
17662 this.lastPageX = aCoord[0];
17663 this.lastPageY = aCoord[1];
17668 * Auto-scroll the window if the dragged object has been moved beyond the
17669 * visible window boundary.
17670 * @method autoScroll
17671 * @param {int} x the drag element's x position
17672 * @param {int} y the drag element's y position
17673 * @param {int} h the height of the drag element
17674 * @param {int} w the width of the drag element
17677 autoScroll: function(x, y, h, w) {
17680 // The client height
17681 var clientH = Roo.lib.Dom.getViewWidth();
17683 // The client width
17684 var clientW = Roo.lib.Dom.getViewHeight();
17686 // The amt scrolled down
17687 var st = this.DDM.getScrollTop();
17689 // The amt scrolled right
17690 var sl = this.DDM.getScrollLeft();
17692 // Location of the bottom of the element
17695 // Location of the right of the element
17698 // The distance from the cursor to the bottom of the visible area,
17699 // adjusted so that we don't scroll if the cursor is beyond the
17700 // element drag constraints
17701 var toBot = (clientH + st - y - this.deltaY);
17703 // The distance from the cursor to the right of the visible area
17704 var toRight = (clientW + sl - x - this.deltaX);
17707 // How close to the edge the cursor must be before we scroll
17708 // var thresh = (document.all) ? 100 : 40;
17711 // How many pixels to scroll per autoscroll op. This helps to reduce
17712 // clunky scrolling. IE is more sensitive about this ... it needs this
17713 // value to be higher.
17714 var scrAmt = (document.all) ? 80 : 30;
17716 // Scroll down if we are near the bottom of the visible page and the
17717 // obj extends below the crease
17718 if ( bot > clientH && toBot < thresh ) {
17719 window.scrollTo(sl, st + scrAmt);
17722 // Scroll up if the window is scrolled down and the top of the object
17723 // goes above the top border
17724 if ( y < st && st > 0 && y - st < thresh ) {
17725 window.scrollTo(sl, st - scrAmt);
17728 // Scroll right if the obj is beyond the right border and the cursor is
17729 // near the border.
17730 if ( right > clientW && toRight < thresh ) {
17731 window.scrollTo(sl + scrAmt, st);
17734 // Scroll left if the window has been scrolled to the right and the obj
17735 // extends past the left border
17736 if ( x < sl && sl > 0 && x - sl < thresh ) {
17737 window.scrollTo(sl - scrAmt, st);
17743 * Finds the location the element should be placed if we want to move
17744 * it to where the mouse location less the click offset would place us.
17745 * @method getTargetCoord
17746 * @param {int} iPageX the X coordinate of the click
17747 * @param {int} iPageY the Y coordinate of the click
17748 * @return an object that contains the coordinates (Object.x and Object.y)
17751 getTargetCoord: function(iPageX, iPageY) {
17754 var x = iPageX - this.deltaX;
17755 var y = iPageY - this.deltaY;
17757 if (this.constrainX) {
17758 if (x < this.minX) { x = this.minX; }
17759 if (x > this.maxX) { x = this.maxX; }
17762 if (this.constrainY) {
17763 if (y < this.minY) { y = this.minY; }
17764 if (y > this.maxY) { y = this.maxY; }
17767 x = this.getTick(x, this.xTicks);
17768 y = this.getTick(y, this.yTicks);
17775 * Sets up config options specific to this class. Overrides
17776 * Roo.dd.DragDrop, but all versions of this method through the
17777 * inheritance chain are called
17779 applyConfig: function() {
17780 Roo.dd.DD.superclass.applyConfig.call(this);
17781 this.scroll = (this.config.scroll !== false);
17785 * Event that fires prior to the onMouseDown event. Overrides
17788 b4MouseDown: function(e) {
17789 // this.resetConstraints();
17790 this.autoOffset(e.getPageX(),
17795 * Event that fires prior to the onDrag event. Overrides
17798 b4Drag: function(e) {
17799 this.setDragElPos(e.getPageX(),
17803 toString: function() {
17804 return ("DD " + this.id);
17807 //////////////////////////////////////////////////////////////////////////
17808 // Debugging ygDragDrop events that can be overridden
17809 //////////////////////////////////////////////////////////////////////////
17811 startDrag: function(x, y) {
17814 onDrag: function(e) {
17817 onDragEnter: function(e, id) {
17820 onDragOver: function(e, id) {
17823 onDragOut: function(e, id) {
17826 onDragDrop: function(e, id) {
17829 endDrag: function(e) {
17836 * Ext JS Library 1.1.1
17837 * Copyright(c) 2006-2007, Ext JS, LLC.
17839 * Originally Released Under LGPL - original licence link has changed is not relivant.
17842 * <script type="text/javascript">
17846 * @class Roo.dd.DDProxy
17847 * A DragDrop implementation that inserts an empty, bordered div into
17848 * the document that follows the cursor during drag operations. At the time of
17849 * the click, the frame div is resized to the dimensions of the linked html
17850 * element, and moved to the exact location of the linked element.
17852 * References to the "frame" element refer to the single proxy element that
17853 * was created to be dragged in place of all DDProxy elements on the
17856 * @extends Roo.dd.DD
17858 * @param {String} id the id of the linked html element
17859 * @param {String} sGroup the group of related DragDrop objects
17860 * @param {object} config an object containing configurable attributes
17861 * Valid properties for DDProxy in addition to those in DragDrop:
17862 * resizeFrame, centerFrame, dragElId
17864 Roo.dd.DDProxy = function(id, sGroup, config) {
17866 this.init(id, sGroup, config);
17872 * The default drag frame div id
17873 * @property Roo.dd.DDProxy.dragElId
17877 Roo.dd.DDProxy.dragElId = "ygddfdiv";
17879 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
17882 * By default we resize the drag frame to be the same size as the element
17883 * we want to drag (this is to get the frame effect). We can turn it off
17884 * if we want a different behavior.
17885 * @property resizeFrame
17891 * By default the frame is positioned exactly where the drag element is, so
17892 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
17893 * you do not have constraints on the obj is to have the drag frame centered
17894 * around the cursor. Set centerFrame to true for this effect.
17895 * @property centerFrame
17898 centerFrame: false,
17901 * Creates the proxy element if it does not yet exist
17902 * @method createFrame
17904 createFrame: function() {
17906 var body = document.body;
17908 if (!body || !body.firstChild) {
17909 setTimeout( function() { self.createFrame(); }, 50 );
17913 var div = this.getDragEl();
17916 div = document.createElement("div");
17917 div.id = this.dragElId;
17920 s.position = "absolute";
17921 s.visibility = "hidden";
17923 s.border = "2px solid #aaa";
17926 // appendChild can blow up IE if invoked prior to the window load event
17927 // while rendering a table. It is possible there are other scenarios
17928 // that would cause this to happen as well.
17929 body.insertBefore(div, body.firstChild);
17934 * Initialization for the drag frame element. Must be called in the
17935 * constructor of all subclasses
17936 * @method initFrame
17938 initFrame: function() {
17939 this.createFrame();
17942 applyConfig: function() {
17943 Roo.dd.DDProxy.superclass.applyConfig.call(this);
17945 this.resizeFrame = (this.config.resizeFrame !== false);
17946 this.centerFrame = (this.config.centerFrame);
17947 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
17951 * Resizes the drag frame to the dimensions of the clicked object, positions
17952 * it over the object, and finally displays it
17953 * @method showFrame
17954 * @param {int} iPageX X click position
17955 * @param {int} iPageY Y click position
17958 showFrame: function(iPageX, iPageY) {
17959 var el = this.getEl();
17960 var dragEl = this.getDragEl();
17961 var s = dragEl.style;
17963 this._resizeProxy();
17965 if (this.centerFrame) {
17966 this.setDelta( Math.round(parseInt(s.width, 10)/2),
17967 Math.round(parseInt(s.height, 10)/2) );
17970 this.setDragElPos(iPageX, iPageY);
17972 Roo.fly(dragEl).show();
17976 * The proxy is automatically resized to the dimensions of the linked
17977 * element when a drag is initiated, unless resizeFrame is set to false
17978 * @method _resizeProxy
17981 _resizeProxy: function() {
17982 if (this.resizeFrame) {
17983 var el = this.getEl();
17984 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
17988 // overrides Roo.dd.DragDrop
17989 b4MouseDown: function(e) {
17990 var x = e.getPageX();
17991 var y = e.getPageY();
17992 this.autoOffset(x, y);
17993 this.setDragElPos(x, y);
17996 // overrides Roo.dd.DragDrop
17997 b4StartDrag: function(x, y) {
17998 // show the drag frame
17999 this.showFrame(x, y);
18002 // overrides Roo.dd.DragDrop
18003 b4EndDrag: function(e) {
18004 Roo.fly(this.getDragEl()).hide();
18007 // overrides Roo.dd.DragDrop
18008 // By default we try to move the element to the last location of the frame.
18009 // This is so that the default behavior mirrors that of Roo.dd.DD.
18010 endDrag: function(e) {
18012 var lel = this.getEl();
18013 var del = this.getDragEl();
18015 // Show the drag frame briefly so we can get its position
18016 del.style.visibility = "";
18019 // Hide the linked element before the move to get around a Safari
18021 lel.style.visibility = "hidden";
18022 Roo.dd.DDM.moveToEl(lel, del);
18023 del.style.visibility = "hidden";
18024 lel.style.visibility = "";
18029 beforeMove : function(){
18033 afterDrag : function(){
18037 toString: function() {
18038 return ("DDProxy " + this.id);
18044 * Ext JS Library 1.1.1
18045 * Copyright(c) 2006-2007, Ext JS, LLC.
18047 * Originally Released Under LGPL - original licence link has changed is not relivant.
18050 * <script type="text/javascript">
18054 * @class Roo.dd.DDTarget
18055 * A DragDrop implementation that does not move, but can be a drop
18056 * target. You would get the same result by simply omitting implementation
18057 * for the event callbacks, but this way we reduce the processing cost of the
18058 * event listener and the callbacks.
18059 * @extends Roo.dd.DragDrop
18061 * @param {String} id the id of the element that is a drop target
18062 * @param {String} sGroup the group of related DragDrop objects
18063 * @param {object} config an object containing configurable attributes
18064 * Valid properties for DDTarget in addition to those in
18068 Roo.dd.DDTarget = function(id, sGroup, config) {
18070 this.initTarget(id, sGroup, config);
18072 if (config.listeners || config.events) {
18073 Roo.dd.DragDrop.superclass.constructor.call(this, {
18074 listeners : config.listeners || {},
18075 events : config.events || {}
18080 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
18081 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
18082 toString: function() {
18083 return ("DDTarget " + this.id);
18088 * Ext JS Library 1.1.1
18089 * Copyright(c) 2006-2007, Ext JS, LLC.
18091 * Originally Released Under LGPL - original licence link has changed is not relivant.
18094 * <script type="text/javascript">
18099 * @class Roo.dd.ScrollManager
18100 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
18101 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
18104 Roo.dd.ScrollManager = function(){
18105 var ddm = Roo.dd.DragDropMgr;
18112 var onStop = function(e){
18117 var triggerRefresh = function(){
18118 if(ddm.dragCurrent){
18119 ddm.refreshCache(ddm.dragCurrent.groups);
18123 var doScroll = function(){
18124 if(ddm.dragCurrent){
18125 var dds = Roo.dd.ScrollManager;
18127 if(proc.el.scroll(proc.dir, dds.increment)){
18131 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
18136 var clearProc = function(){
18138 clearInterval(proc.id);
18145 var startProc = function(el, dir){
18146 Roo.log('scroll startproc');
18150 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
18153 var onFire = function(e, isDrop){
18155 if(isDrop || !ddm.dragCurrent){ return; }
18156 var dds = Roo.dd.ScrollManager;
18157 if(!dragEl || dragEl != ddm.dragCurrent){
18158 dragEl = ddm.dragCurrent;
18159 // refresh regions on drag start
18160 dds.refreshCache();
18163 var xy = Roo.lib.Event.getXY(e);
18164 var pt = new Roo.lib.Point(xy[0], xy[1]);
18165 for(var id in els){
18166 var el = els[id], r = el._region;
18167 if(r && r.contains(pt) && el.isScrollable()){
18168 if(r.bottom - pt.y <= dds.thresh){
18170 startProc(el, "down");
18173 }else if(r.right - pt.x <= dds.thresh){
18175 startProc(el, "left");
18178 }else if(pt.y - r.top <= dds.thresh){
18180 startProc(el, "up");
18183 }else if(pt.x - r.left <= dds.thresh){
18185 startProc(el, "right");
18194 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
18195 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
18199 * Registers new overflow element(s) to auto scroll
18200 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
18202 register : function(el){
18203 if(el instanceof Array){
18204 for(var i = 0, len = el.length; i < len; i++) {
18205 this.register(el[i]);
18211 Roo.dd.ScrollManager.els = els;
18215 * Unregisters overflow element(s) so they are no longer scrolled
18216 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
18218 unregister : function(el){
18219 if(el instanceof Array){
18220 for(var i = 0, len = el.length; i < len; i++) {
18221 this.unregister(el[i]);
18230 * The number of pixels from the edge of a container the pointer needs to be to
18231 * trigger scrolling (defaults to 25)
18237 * The number of pixels to scroll in each scroll increment (defaults to 50)
18243 * The frequency of scrolls in milliseconds (defaults to 500)
18249 * True to animate the scroll (defaults to true)
18255 * The animation duration in seconds -
18256 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
18262 * Manually trigger a cache refresh.
18264 refreshCache : function(){
18265 for(var id in els){
18266 if(typeof els[id] == 'object'){ // for people extending the object prototype
18267 els[id]._region = els[id].getRegion();
18274 * Ext JS Library 1.1.1
18275 * Copyright(c) 2006-2007, Ext JS, LLC.
18277 * Originally Released Under LGPL - original licence link has changed is not relivant.
18280 * <script type="text/javascript">
18285 * @class Roo.dd.Registry
18286 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
18287 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
18290 Roo.dd.Registry = function(){
18293 var autoIdSeed = 0;
18295 var getId = function(el, autogen){
18296 if(typeof el == "string"){
18300 if(!id && autogen !== false){
18301 id = "roodd-" + (++autoIdSeed);
18309 * Register a drag drop element
18310 * @param {String|HTMLElement} element The id or DOM node to register
18311 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
18312 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
18313 * knows how to interpret, plus there are some specific properties known to the Registry that should be
18314 * populated in the data object (if applicable):
18316 Value Description<br />
18317 --------- ------------------------------------------<br />
18318 handles Array of DOM nodes that trigger dragging<br />
18319 for the element being registered<br />
18320 isHandle True if the element passed in triggers<br />
18321 dragging itself, else false
18324 register : function(el, data){
18326 if(typeof el == "string"){
18327 el = document.getElementById(el);
18330 elements[getId(el)] = data;
18331 if(data.isHandle !== false){
18332 handles[data.ddel.id] = data;
18335 var hs = data.handles;
18336 for(var i = 0, len = hs.length; i < len; i++){
18337 handles[getId(hs[i])] = data;
18343 * Unregister a drag drop element
18344 * @param {String|HTMLElement} element The id or DOM node to unregister
18346 unregister : function(el){
18347 var id = getId(el, false);
18348 var data = elements[id];
18350 delete elements[id];
18352 var hs = data.handles;
18353 for(var i = 0, len = hs.length; i < len; i++){
18354 delete handles[getId(hs[i], false)];
18361 * Returns the handle registered for a DOM Node by id
18362 * @param {String|HTMLElement} id The DOM node or id to look up
18363 * @return {Object} handle The custom handle data
18365 getHandle : function(id){
18366 if(typeof id != "string"){ // must be element?
18369 return handles[id];
18373 * Returns the handle that is registered for the DOM node that is the target of the event
18374 * @param {Event} e The event
18375 * @return {Object} handle The custom handle data
18377 getHandleFromEvent : function(e){
18378 var t = Roo.lib.Event.getTarget(e);
18379 return t ? handles[t.id] : null;
18383 * Returns a custom data object that is registered for a DOM node by id
18384 * @param {String|HTMLElement} id The DOM node or id to look up
18385 * @return {Object} data The custom data
18387 getTarget : function(id){
18388 if(typeof id != "string"){ // must be element?
18391 return elements[id];
18395 * Returns a custom data object that is registered for the DOM node that is the target of the event
18396 * @param {Event} e The event
18397 * @return {Object} data The custom data
18399 getTargetFromEvent : function(e){
18400 var t = Roo.lib.Event.getTarget(e);
18401 return t ? elements[t.id] || handles[t.id] : null;
18406 * Ext JS Library 1.1.1
18407 * Copyright(c) 2006-2007, Ext JS, LLC.
18409 * Originally Released Under LGPL - original licence link has changed is not relivant.
18412 * <script type="text/javascript">
18417 * @class Roo.dd.StatusProxy
18418 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
18419 * default drag proxy used by all Roo.dd components.
18421 * @param {Object} config
18423 Roo.dd.StatusProxy = function(config){
18424 Roo.apply(this, config);
18425 this.id = this.id || Roo.id();
18426 this.el = new Roo.Layer({
18428 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
18429 {tag: "div", cls: "x-dd-drop-icon"},
18430 {tag: "div", cls: "x-dd-drag-ghost"}
18433 shadow: !config || config.shadow !== false
18435 this.ghost = Roo.get(this.el.dom.childNodes[1]);
18436 this.dropStatus = this.dropNotAllowed;
18439 Roo.dd.StatusProxy.prototype = {
18441 * @cfg {String} dropAllowed
18442 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
18444 dropAllowed : "x-dd-drop-ok",
18446 * @cfg {String} dropNotAllowed
18447 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
18449 dropNotAllowed : "x-dd-drop-nodrop",
18452 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
18453 * over the current target element.
18454 * @param {String} cssClass The css class for the new drop status indicator image
18456 setStatus : function(cssClass){
18457 cssClass = cssClass || this.dropNotAllowed;
18458 if(this.dropStatus != cssClass){
18459 this.el.replaceClass(this.dropStatus, cssClass);
18460 this.dropStatus = cssClass;
18465 * Resets the status indicator to the default dropNotAllowed value
18466 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
18468 reset : function(clearGhost){
18469 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
18470 this.dropStatus = this.dropNotAllowed;
18472 this.ghost.update("");
18477 * Updates the contents of the ghost element
18478 * @param {String} html The html that will replace the current innerHTML of the ghost element
18480 update : function(html){
18481 if(typeof html == "string"){
18482 this.ghost.update(html);
18484 this.ghost.update("");
18485 html.style.margin = "0";
18486 this.ghost.dom.appendChild(html);
18488 // ensure float = none set?? cant remember why though.
18489 var el = this.ghost.dom.firstChild;
18491 Roo.fly(el).setStyle('float', 'none');
18496 * Returns the underlying proxy {@link Roo.Layer}
18497 * @return {Roo.Layer} el
18499 getEl : function(){
18504 * Returns the ghost element
18505 * @return {Roo.Element} el
18507 getGhost : function(){
18513 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
18515 hide : function(clear){
18523 * Stops the repair animation if it's currently running
18526 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
18532 * Displays this proxy
18539 * Force the Layer to sync its shadow and shim positions to the element
18546 * Causes the proxy to return to its position of origin via an animation. Should be called after an
18547 * invalid drop operation by the item being dragged.
18548 * @param {Array} xy The XY position of the element ([x, y])
18549 * @param {Function} callback The function to call after the repair is complete
18550 * @param {Object} scope The scope in which to execute the callback
18552 repair : function(xy, callback, scope){
18553 this.callback = callback;
18554 this.scope = scope;
18555 if(xy && this.animRepair !== false){
18556 this.el.addClass("x-dd-drag-repair");
18557 this.el.hideUnders(true);
18558 this.anim = this.el.shift({
18559 duration: this.repairDuration || .5,
18563 callback: this.afterRepair,
18567 this.afterRepair();
18572 afterRepair : function(){
18574 if(typeof this.callback == "function"){
18575 this.callback.call(this.scope || this);
18577 this.callback = null;
18582 * Ext JS Library 1.1.1
18583 * Copyright(c) 2006-2007, Ext JS, LLC.
18585 * Originally Released Under LGPL - original licence link has changed is not relivant.
18588 * <script type="text/javascript">
18592 * @class Roo.dd.DragSource
18593 * @extends Roo.dd.DDProxy
18594 * A simple class that provides the basic implementation needed to make any element draggable.
18596 * @param {String/HTMLElement/Element} el The container element
18597 * @param {Object} config
18599 Roo.dd.DragSource = function(el, config){
18600 this.el = Roo.get(el);
18601 this.dragData = {};
18603 Roo.apply(this, config);
18606 this.proxy = new Roo.dd.StatusProxy();
18609 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
18610 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
18612 this.dragging = false;
18615 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
18617 * @cfg {String} dropAllowed
18618 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
18620 dropAllowed : "x-dd-drop-ok",
18622 * @cfg {String} dropNotAllowed
18623 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
18625 dropNotAllowed : "x-dd-drop-nodrop",
18628 * Returns the data object associated with this drag source
18629 * @return {Object} data An object containing arbitrary data
18631 getDragData : function(e){
18632 return this.dragData;
18636 onDragEnter : function(e, id){
18637 var target = Roo.dd.DragDropMgr.getDDById(id);
18638 this.cachedTarget = target;
18639 if(this.beforeDragEnter(target, e, id) !== false){
18640 if(target.isNotifyTarget){
18641 var status = target.notifyEnter(this, e, this.dragData);
18642 this.proxy.setStatus(status);
18644 this.proxy.setStatus(this.dropAllowed);
18647 if(this.afterDragEnter){
18649 * An empty function by default, but provided so that you can perform a custom action
18650 * when the dragged item enters the drop target by providing an implementation.
18651 * @param {Roo.dd.DragDrop} target The drop target
18652 * @param {Event} e The event object
18653 * @param {String} id The id of the dragged element
18654 * @method afterDragEnter
18656 this.afterDragEnter(target, e, id);
18662 * An empty function by default, but provided so that you can perform a custom action
18663 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
18664 * @param {Roo.dd.DragDrop} target The drop target
18665 * @param {Event} e The event object
18666 * @param {String} id The id of the dragged element
18667 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18669 beforeDragEnter : function(target, e, id){
18674 alignElWithMouse: function() {
18675 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
18680 onDragOver : function(e, id){
18681 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18682 if(this.beforeDragOver(target, e, id) !== false){
18683 if(target.isNotifyTarget){
18684 var status = target.notifyOver(this, e, this.dragData);
18685 this.proxy.setStatus(status);
18688 if(this.afterDragOver){
18690 * An empty function by default, but provided so that you can perform a custom action
18691 * while the dragged item is over the drop target by providing an implementation.
18692 * @param {Roo.dd.DragDrop} target The drop target
18693 * @param {Event} e The event object
18694 * @param {String} id The id of the dragged element
18695 * @method afterDragOver
18697 this.afterDragOver(target, e, id);
18703 * An empty function by default, but provided so that you can perform a custom action
18704 * while the dragged item is over the drop target and optionally cancel the onDragOver.
18705 * @param {Roo.dd.DragDrop} target The drop target
18706 * @param {Event} e The event object
18707 * @param {String} id The id of the dragged element
18708 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18710 beforeDragOver : function(target, e, id){
18715 onDragOut : function(e, id){
18716 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18717 if(this.beforeDragOut(target, e, id) !== false){
18718 if(target.isNotifyTarget){
18719 target.notifyOut(this, e, this.dragData);
18721 this.proxy.reset();
18722 if(this.afterDragOut){
18724 * An empty function by default, but provided so that you can perform a custom action
18725 * after the dragged item is dragged out of the target without dropping.
18726 * @param {Roo.dd.DragDrop} target The drop target
18727 * @param {Event} e The event object
18728 * @param {String} id The id of the dragged element
18729 * @method afterDragOut
18731 this.afterDragOut(target, e, id);
18734 this.cachedTarget = null;
18738 * An empty function by default, but provided so that you can perform a custom action before the dragged
18739 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
18740 * @param {Roo.dd.DragDrop} target The drop target
18741 * @param {Event} e The event object
18742 * @param {String} id The id of the dragged element
18743 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18745 beforeDragOut : function(target, e, id){
18750 onDragDrop : function(e, id){
18751 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
18752 if(this.beforeDragDrop(target, e, id) !== false){
18753 if(target.isNotifyTarget){
18754 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
18755 this.onValidDrop(target, e, id);
18757 this.onInvalidDrop(target, e, id);
18760 this.onValidDrop(target, e, id);
18763 if(this.afterDragDrop){
18765 * An empty function by default, but provided so that you can perform a custom action
18766 * after a valid drag drop has occurred by providing an implementation.
18767 * @param {Roo.dd.DragDrop} target The drop target
18768 * @param {Event} e The event object
18769 * @param {String} id The id of the dropped element
18770 * @method afterDragDrop
18772 this.afterDragDrop(target, e, id);
18775 delete this.cachedTarget;
18779 * An empty function by default, but provided so that you can perform a custom action before the dragged
18780 * item is dropped onto the target and optionally cancel the onDragDrop.
18781 * @param {Roo.dd.DragDrop} target The drop target
18782 * @param {Event} e The event object
18783 * @param {String} id The id of the dragged element
18784 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
18786 beforeDragDrop : function(target, e, id){
18791 onValidDrop : function(target, e, id){
18793 if(this.afterValidDrop){
18795 * An empty function by default, but provided so that you can perform a custom action
18796 * after a valid drop has occurred by providing an implementation.
18797 * @param {Object} target The target DD
18798 * @param {Event} e The event object
18799 * @param {String} id The id of the dropped element
18800 * @method afterInvalidDrop
18802 this.afterValidDrop(target, e, id);
18807 getRepairXY : function(e, data){
18808 return this.el.getXY();
18812 onInvalidDrop : function(target, e, id){
18813 this.beforeInvalidDrop(target, e, id);
18814 if(this.cachedTarget){
18815 if(this.cachedTarget.isNotifyTarget){
18816 this.cachedTarget.notifyOut(this, e, this.dragData);
18818 this.cacheTarget = null;
18820 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
18822 if(this.afterInvalidDrop){
18824 * An empty function by default, but provided so that you can perform a custom action
18825 * after an invalid drop has occurred by providing an implementation.
18826 * @param {Event} e The event object
18827 * @param {String} id The id of the dropped element
18828 * @method afterInvalidDrop
18830 this.afterInvalidDrop(e, id);
18835 afterRepair : function(){
18837 this.el.highlight(this.hlColor || "c3daf9");
18839 this.dragging = false;
18843 * An empty function by default, but provided so that you can perform a custom action after an invalid
18844 * drop has occurred.
18845 * @param {Roo.dd.DragDrop} target The drop target
18846 * @param {Event} e The event object
18847 * @param {String} id The id of the dragged element
18848 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
18850 beforeInvalidDrop : function(target, e, id){
18855 handleMouseDown : function(e){
18856 if(this.dragging) {
18859 var data = this.getDragData(e);
18860 if(data && this.onBeforeDrag(data, e) !== false){
18861 this.dragData = data;
18863 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
18868 * An empty function by default, but provided so that you can perform a custom action before the initial
18869 * drag event begins and optionally cancel it.
18870 * @param {Object} data An object containing arbitrary data to be shared with drop targets
18871 * @param {Event} e The event object
18872 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
18874 onBeforeDrag : function(data, e){
18879 * An empty function by default, but provided so that you can perform a custom action once the initial
18880 * drag event has begun. The drag cannot be canceled from this function.
18881 * @param {Number} x The x position of the click on the dragged object
18882 * @param {Number} y The y position of the click on the dragged object
18884 onStartDrag : Roo.emptyFn,
18886 // private - YUI override
18887 startDrag : function(x, y){
18888 this.proxy.reset();
18889 this.dragging = true;
18890 this.proxy.update("");
18891 this.onInitDrag(x, y);
18896 onInitDrag : function(x, y){
18897 var clone = this.el.dom.cloneNode(true);
18898 clone.id = Roo.id(); // prevent duplicate ids
18899 this.proxy.update(clone);
18900 this.onStartDrag(x, y);
18905 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
18906 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
18908 getProxy : function(){
18913 * Hides the drag source's {@link Roo.dd.StatusProxy}
18915 hideProxy : function(){
18917 this.proxy.reset(true);
18918 this.dragging = false;
18922 triggerCacheRefresh : function(){
18923 Roo.dd.DDM.refreshCache(this.groups);
18926 // private - override to prevent hiding
18927 b4EndDrag: function(e) {
18930 // private - override to prevent moving
18931 endDrag : function(e){
18932 this.onEndDrag(this.dragData, e);
18936 onEndDrag : function(data, e){
18939 // private - pin to cursor
18940 autoOffset : function(x, y) {
18941 this.setDelta(-12, -20);
18945 * Ext JS Library 1.1.1
18946 * Copyright(c) 2006-2007, Ext JS, LLC.
18948 * Originally Released Under LGPL - original licence link has changed is not relivant.
18951 * <script type="text/javascript">
18956 * @class Roo.dd.DropTarget
18957 * @extends Roo.dd.DDTarget
18958 * A simple class that provides the basic implementation needed to make any element a drop target that can have
18959 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
18961 * @param {String/HTMLElement/Element} el The container element
18962 * @param {Object} config
18964 Roo.dd.DropTarget = function(el, config){
18965 this.el = Roo.get(el);
18967 var listeners = false; ;
18968 if (config && config.listeners) {
18969 listeners= config.listeners;
18970 delete config.listeners;
18972 Roo.apply(this, config);
18974 if(this.containerScroll){
18975 Roo.dd.ScrollManager.register(this.el);
18979 * @scope Roo.dd.DropTarget
18984 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
18985 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
18986 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
18988 * IMPORTANT : it should set this.overClass and this.dropAllowed
18990 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
18991 * @param {Event} e The event
18992 * @param {Object} data An object containing arbitrary data supplied by the drag source
18998 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
18999 * This method will be called on every mouse movement while the drag source is over the drop target.
19000 * This default implementation simply returns the dropAllowed config value.
19002 * IMPORTANT : it should set this.dropAllowed
19004 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19005 * @param {Event} e The event
19006 * @param {Object} data An object containing arbitrary data supplied by the drag source
19012 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
19013 * out of the target without dropping. This default implementation simply removes the CSS class specified by
19014 * overClass (if any) from the drop element.
19016 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19017 * @param {Event} e The event
19018 * @param {Object} data An object containing arbitrary data supplied by the drag source
19024 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
19025 * been dropped on it. This method has no default implementation and returns false, so you must provide an
19026 * implementation that does something to process the drop event and returns true so that the drag source's
19027 * repair action does not run.
19029 * IMPORTANT : it should set this.success
19031 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19032 * @param {Event} e The event
19033 * @param {Object} data An object containing arbitrary data supplied by the drag source
19039 Roo.dd.DropTarget.superclass.constructor.call( this,
19041 this.ddGroup || this.group,
19044 listeners : listeners || {}
19052 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
19054 * @cfg {String} overClass
19055 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
19058 * @cfg {String} ddGroup
19059 * The drag drop group to handle drop events for
19063 * @cfg {String} dropAllowed
19064 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19066 dropAllowed : "x-dd-drop-ok",
19068 * @cfg {String} dropNotAllowed
19069 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19071 dropNotAllowed : "x-dd-drop-nodrop",
19073 * @cfg {boolean} success
19074 * set this after drop listener..
19078 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
19079 * if the drop point is valid for over/enter..
19086 isNotifyTarget : true,
19091 notifyEnter : function(dd, e, data)
19094 this.fireEvent('enter', dd, e, data);
19095 if(this.overClass){
19096 this.el.addClass(this.overClass);
19098 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19099 this.valid ? this.dropAllowed : this.dropNotAllowed
19106 notifyOver : function(dd, e, data)
19109 this.fireEvent('over', dd, e, data);
19110 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
19111 this.valid ? this.dropAllowed : this.dropNotAllowed
19118 notifyOut : function(dd, e, data)
19120 this.fireEvent('out', dd, e, data);
19121 if(this.overClass){
19122 this.el.removeClass(this.overClass);
19129 notifyDrop : function(dd, e, data)
19131 this.success = false;
19132 this.fireEvent('drop', dd, e, data);
19133 return this.success;
19137 * Ext JS Library 1.1.1
19138 * Copyright(c) 2006-2007, Ext JS, LLC.
19140 * Originally Released Under LGPL - original licence link has changed is not relivant.
19143 * <script type="text/javascript">
19148 * @class Roo.dd.DragZone
19149 * @extends Roo.dd.DragSource
19150 * This class provides a container DD instance that proxies for multiple child node sources.<br />
19151 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
19153 * @param {String/HTMLElement/Element} el The container element
19154 * @param {Object} config
19156 Roo.dd.DragZone = function(el, config){
19157 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
19158 if(this.containerScroll){
19159 Roo.dd.ScrollManager.register(this.el);
19163 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
19165 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
19166 * for auto scrolling during drag operations.
19169 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
19170 * method after a failed drop (defaults to "c3daf9" - light blue)
19174 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
19175 * for a valid target to drag based on the mouse down. Override this method
19176 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
19177 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
19178 * @param {EventObject} e The mouse down event
19179 * @return {Object} The dragData
19181 getDragData : function(e){
19182 return Roo.dd.Registry.getHandleFromEvent(e);
19186 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
19187 * this.dragData.ddel
19188 * @param {Number} x The x position of the click on the dragged object
19189 * @param {Number} y The y position of the click on the dragged object
19190 * @return {Boolean} true to continue the drag, false to cancel
19192 onInitDrag : function(x, y){
19193 this.proxy.update(this.dragData.ddel.cloneNode(true));
19194 this.onStartDrag(x, y);
19199 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
19201 afterRepair : function(){
19203 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
19205 this.dragging = false;
19209 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
19210 * the XY of this.dragData.ddel
19211 * @param {EventObject} e The mouse up event
19212 * @return {Array} The xy location (e.g. [100, 200])
19214 getRepairXY : function(e){
19215 return Roo.Element.fly(this.dragData.ddel).getXY();
19219 * Ext JS Library 1.1.1
19220 * Copyright(c) 2006-2007, Ext JS, LLC.
19222 * Originally Released Under LGPL - original licence link has changed is not relivant.
19225 * <script type="text/javascript">
19228 * @class Roo.dd.DropZone
19229 * @extends Roo.dd.DropTarget
19230 * This class provides a container DD instance that proxies for multiple child node targets.<br />
19231 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
19233 * @param {String/HTMLElement/Element} el The container element
19234 * @param {Object} config
19236 Roo.dd.DropZone = function(el, config){
19237 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
19240 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
19242 * Returns a custom data object associated with the DOM node that is the target of the event. By default
19243 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
19244 * provide your own custom lookup.
19245 * @param {Event} e The event
19246 * @return {Object} data The custom data
19248 getTargetFromEvent : function(e){
19249 return Roo.dd.Registry.getTargetFromEvent(e);
19253 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
19254 * that it has registered. This method has no default implementation and should be overridden to provide
19255 * node-specific processing if necessary.
19256 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19257 * {@link #getTargetFromEvent} for this node)
19258 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19259 * @param {Event} e The event
19260 * @param {Object} data An object containing arbitrary data supplied by the drag source
19262 onNodeEnter : function(n, dd, e, data){
19267 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
19268 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
19269 * overridden to provide the proper feedback.
19270 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19271 * {@link #getTargetFromEvent} for this node)
19272 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19273 * @param {Event} e The event
19274 * @param {Object} data An object containing arbitrary data supplied by the drag source
19275 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19276 * underlying {@link Roo.dd.StatusProxy} can be updated
19278 onNodeOver : function(n, dd, e, data){
19279 return this.dropAllowed;
19283 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
19284 * the drop node without dropping. This method has no default implementation and should be overridden to provide
19285 * node-specific processing if necessary.
19286 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19287 * {@link #getTargetFromEvent} for this node)
19288 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19289 * @param {Event} e The event
19290 * @param {Object} data An object containing arbitrary data supplied by the drag source
19292 onNodeOut : function(n, dd, e, data){
19297 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
19298 * the drop node. The default implementation returns false, so it should be overridden to provide the
19299 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
19300 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
19301 * {@link #getTargetFromEvent} for this node)
19302 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19303 * @param {Event} e The event
19304 * @param {Object} data An object containing arbitrary data supplied by the drag source
19305 * @return {Boolean} True if the drop was valid, else false
19307 onNodeDrop : function(n, dd, e, data){
19312 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
19313 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
19314 * it should be overridden to provide the proper feedback if necessary.
19315 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19316 * @param {Event} e The event
19317 * @param {Object} data An object containing arbitrary data supplied by the drag source
19318 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19319 * underlying {@link Roo.dd.StatusProxy} can be updated
19321 onContainerOver : function(dd, e, data){
19322 return this.dropNotAllowed;
19326 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
19327 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
19328 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
19329 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
19330 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19331 * @param {Event} e The event
19332 * @param {Object} data An object containing arbitrary data supplied by the drag source
19333 * @return {Boolean} True if the drop was valid, else false
19335 onContainerDrop : function(dd, e, data){
19340 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
19341 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
19342 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
19343 * you should override this method and provide a custom implementation.
19344 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19345 * @param {Event} e The event
19346 * @param {Object} data An object containing arbitrary data supplied by the drag source
19347 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19348 * underlying {@link Roo.dd.StatusProxy} can be updated
19350 notifyEnter : function(dd, e, data){
19351 return this.dropNotAllowed;
19355 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
19356 * This method will be called on every mouse movement while the drag source is over the drop zone.
19357 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
19358 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
19359 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
19360 * registered node, it will call {@link #onContainerOver}.
19361 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19362 * @param {Event} e The event
19363 * @param {Object} data An object containing arbitrary data supplied by the drag source
19364 * @return {String} status The CSS class that communicates the drop status back to the source so that the
19365 * underlying {@link Roo.dd.StatusProxy} can be updated
19367 notifyOver : function(dd, e, data){
19368 var n = this.getTargetFromEvent(e);
19369 if(!n){ // not over valid drop target
19370 if(this.lastOverNode){
19371 this.onNodeOut(this.lastOverNode, dd, e, data);
19372 this.lastOverNode = null;
19374 return this.onContainerOver(dd, e, data);
19376 if(this.lastOverNode != n){
19377 if(this.lastOverNode){
19378 this.onNodeOut(this.lastOverNode, dd, e, data);
19380 this.onNodeEnter(n, dd, e, data);
19381 this.lastOverNode = n;
19383 return this.onNodeOver(n, dd, e, data);
19387 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
19388 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
19389 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
19390 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
19391 * @param {Event} e The event
19392 * @param {Object} data An object containing arbitrary data supplied by the drag zone
19394 notifyOut : function(dd, e, data){
19395 if(this.lastOverNode){
19396 this.onNodeOut(this.lastOverNode, dd, e, data);
19397 this.lastOverNode = null;
19402 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
19403 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
19404 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
19405 * otherwise it will call {@link #onContainerDrop}.
19406 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
19407 * @param {Event} e The event
19408 * @param {Object} data An object containing arbitrary data supplied by the drag source
19409 * @return {Boolean} True if the drop was valid, else false
19411 notifyDrop : function(dd, e, data){
19412 if(this.lastOverNode){
19413 this.onNodeOut(this.lastOverNode, dd, e, data);
19414 this.lastOverNode = null;
19416 var n = this.getTargetFromEvent(e);
19418 this.onNodeDrop(n, dd, e, data) :
19419 this.onContainerDrop(dd, e, data);
19423 triggerCacheRefresh : function(){
19424 Roo.dd.DDM.refreshCache(this.groups);
19428 * Ext JS Library 1.1.1
19429 * Copyright(c) 2006-2007, Ext JS, LLC.
19431 * Originally Released Under LGPL - original licence link has changed is not relivant.
19434 * <script type="text/javascript">
19439 * @class Roo.data.SortTypes
19441 * Defines the default sorting (casting?) comparison functions used when sorting data.
19443 Roo.data.SortTypes = {
19445 * Default sort that does nothing
19446 * @param {Mixed} s The value being converted
19447 * @return {Mixed} The comparison value
19449 none : function(s){
19454 * The regular expression used to strip tags
19458 stripTagsRE : /<\/?[^>]+>/gi,
19461 * Strips all HTML tags to sort on text only
19462 * @param {Mixed} s The value being converted
19463 * @return {String} The comparison value
19465 asText : function(s){
19466 return String(s).replace(this.stripTagsRE, "");
19470 * Strips all HTML tags to sort on text only - Case insensitive
19471 * @param {Mixed} s The value being converted
19472 * @return {String} The comparison value
19474 asUCText : function(s){
19475 return String(s).toUpperCase().replace(this.stripTagsRE, "");
19479 * Case insensitive string
19480 * @param {Mixed} s The value being converted
19481 * @return {String} The comparison value
19483 asUCString : function(s) {
19484 return String(s).toUpperCase();
19489 * @param {Mixed} s The value being converted
19490 * @return {Number} The comparison value
19492 asDate : function(s) {
19496 if(s instanceof Date){
19497 return s.getTime();
19499 return Date.parse(String(s));
19504 * @param {Mixed} s The value being converted
19505 * @return {Float} The comparison value
19507 asFloat : function(s) {
19508 var val = parseFloat(String(s).replace(/,/g, ""));
19509 if(isNaN(val)) val = 0;
19515 * @param {Mixed} s The value being converted
19516 * @return {Number} The comparison value
19518 asInt : function(s) {
19519 var val = parseInt(String(s).replace(/,/g, ""));
19520 if(isNaN(val)) val = 0;
19525 * Ext JS Library 1.1.1
19526 * Copyright(c) 2006-2007, Ext JS, LLC.
19528 * Originally Released Under LGPL - original licence link has changed is not relivant.
19531 * <script type="text/javascript">
19535 * @class Roo.data.Record
19536 * Instances of this class encapsulate both record <em>definition</em> information, and record
19537 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
19538 * to access Records cached in an {@link Roo.data.Store} object.<br>
19540 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
19541 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
19544 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
19546 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
19547 * {@link #create}. The parameters are the same.
19548 * @param {Array} data An associative Array of data values keyed by the field name.
19549 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
19550 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
19551 * not specified an integer id is generated.
19553 Roo.data.Record = function(data, id){
19554 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
19559 * Generate a constructor for a specific record layout.
19560 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
19561 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
19562 * Each field definition object may contain the following properties: <ul>
19563 * <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,
19564 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
19565 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
19566 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
19567 * is being used, then this is a string containing the javascript expression to reference the data relative to
19568 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
19569 * to the data item relative to the record element. If the mapping expression is the same as the field name,
19570 * this may be omitted.</p></li>
19571 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
19572 * <ul><li>auto (Default, implies no conversion)</li>
19577 * <li>date</li></ul></p></li>
19578 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
19579 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
19580 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
19581 * by the Reader into an object that will be stored in the Record. It is passed the
19582 * following parameters:<ul>
19583 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
19585 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
19587 * <br>usage:<br><pre><code>
19588 var TopicRecord = Roo.data.Record.create(
19589 {name: 'title', mapping: 'topic_title'},
19590 {name: 'author', mapping: 'username'},
19591 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
19592 {name: 'lastPost', mapping: 'post_time', type: 'date'},
19593 {name: 'lastPoster', mapping: 'user2'},
19594 {name: 'excerpt', mapping: 'post_text'}
19597 var myNewRecord = new TopicRecord({
19598 title: 'Do my job please',
19601 lastPost: new Date(),
19602 lastPoster: 'Animal',
19603 excerpt: 'No way dude!'
19605 myStore.add(myNewRecord);
19610 Roo.data.Record.create = function(o){
19611 var f = function(){
19612 f.superclass.constructor.apply(this, arguments);
19614 Roo.extend(f, Roo.data.Record);
19615 var p = f.prototype;
19616 p.fields = new Roo.util.MixedCollection(false, function(field){
19619 for(var i = 0, len = o.length; i < len; i++){
19620 p.fields.add(new Roo.data.Field(o[i]));
19622 f.getField = function(name){
19623 return p.fields.get(name);
19628 Roo.data.Record.AUTO_ID = 1000;
19629 Roo.data.Record.EDIT = 'edit';
19630 Roo.data.Record.REJECT = 'reject';
19631 Roo.data.Record.COMMIT = 'commit';
19633 Roo.data.Record.prototype = {
19635 * Readonly flag - true if this record has been modified.
19644 join : function(store){
19645 this.store = store;
19649 * Set the named field to the specified value.
19650 * @param {String} name The name of the field to set.
19651 * @param {Object} value The value to set the field to.
19653 set : function(name, value){
19654 if(this.data[name] == value){
19658 if(!this.modified){
19659 this.modified = {};
19661 if(typeof this.modified[name] == 'undefined'){
19662 this.modified[name] = this.data[name];
19664 this.data[name] = value;
19665 if(!this.editing && this.store){
19666 this.store.afterEdit(this);
19671 * Get the value of the named field.
19672 * @param {String} name The name of the field to get the value of.
19673 * @return {Object} The value of the field.
19675 get : function(name){
19676 return this.data[name];
19680 beginEdit : function(){
19681 this.editing = true;
19682 this.modified = {};
19686 cancelEdit : function(){
19687 this.editing = false;
19688 delete this.modified;
19692 endEdit : function(){
19693 this.editing = false;
19694 if(this.dirty && this.store){
19695 this.store.afterEdit(this);
19700 * Usually called by the {@link Roo.data.Store} which owns the Record.
19701 * Rejects all changes made to the Record since either creation, or the last commit operation.
19702 * Modified fields are reverted to their original values.
19704 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19705 * of reject operations.
19707 reject : function(){
19708 var m = this.modified;
19710 if(typeof m[n] != "function"){
19711 this.data[n] = m[n];
19714 this.dirty = false;
19715 delete this.modified;
19716 this.editing = false;
19718 this.store.afterReject(this);
19723 * Usually called by the {@link Roo.data.Store} which owns the Record.
19724 * Commits all changes made to the Record since either creation, or the last commit operation.
19726 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
19727 * of commit operations.
19729 commit : function(){
19730 this.dirty = false;
19731 delete this.modified;
19732 this.editing = false;
19734 this.store.afterCommit(this);
19739 hasError : function(){
19740 return this.error != null;
19744 clearError : function(){
19749 * Creates a copy of this record.
19750 * @param {String} id (optional) A new record id if you don't want to use this record's id
19753 copy : function(newId) {
19754 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
19758 * Ext JS Library 1.1.1
19759 * Copyright(c) 2006-2007, Ext JS, LLC.
19761 * Originally Released Under LGPL - original licence link has changed is not relivant.
19764 * <script type="text/javascript">
19770 * @class Roo.data.Store
19771 * @extends Roo.util.Observable
19772 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
19773 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
19775 * 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
19776 * has no knowledge of the format of the data returned by the Proxy.<br>
19778 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
19779 * instances from the data object. These records are cached and made available through accessor functions.
19781 * Creates a new Store.
19782 * @param {Object} config A config object containing the objects needed for the Store to access data,
19783 * and read the data into Records.
19785 Roo.data.Store = function(config){
19786 this.data = new Roo.util.MixedCollection(false);
19787 this.data.getKey = function(o){
19790 this.baseParams = {};
19792 this.paramNames = {
19797 "multisort" : "_multisort"
19800 if(config && config.data){
19801 this.inlineData = config.data;
19802 delete config.data;
19805 Roo.apply(this, config);
19807 if(this.reader){ // reader passed
19808 this.reader = Roo.factory(this.reader, Roo.data);
19809 this.reader.xmodule = this.xmodule || false;
19810 if(!this.recordType){
19811 this.recordType = this.reader.recordType;
19813 if(this.reader.onMetaChange){
19814 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
19818 if(this.recordType){
19819 this.fields = this.recordType.prototype.fields;
19821 this.modified = [];
19825 * @event datachanged
19826 * Fires when the data cache has changed, and a widget which is using this Store
19827 * as a Record cache should refresh its view.
19828 * @param {Store} this
19830 datachanged : true,
19832 * @event metachange
19833 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
19834 * @param {Store} this
19835 * @param {Object} meta The JSON metadata
19840 * Fires when Records have been added to the Store
19841 * @param {Store} this
19842 * @param {Roo.data.Record[]} records The array of Records added
19843 * @param {Number} index The index at which the record(s) were added
19848 * Fires when a Record has been removed from the Store
19849 * @param {Store} this
19850 * @param {Roo.data.Record} record The Record that was removed
19851 * @param {Number} index The index at which the record was removed
19856 * Fires when a Record has been updated
19857 * @param {Store} this
19858 * @param {Roo.data.Record} record The Record that was updated
19859 * @param {String} operation The update operation being performed. Value may be one of:
19861 Roo.data.Record.EDIT
19862 Roo.data.Record.REJECT
19863 Roo.data.Record.COMMIT
19869 * Fires when the data cache has been cleared.
19870 * @param {Store} this
19874 * @event beforeload
19875 * Fires before a request is made for a new data object. If the beforeload handler returns false
19876 * the load action will be canceled.
19877 * @param {Store} this
19878 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19882 * @event beforeloadadd
19883 * Fires after a new set of Records has been loaded.
19884 * @param {Store} this
19885 * @param {Roo.data.Record[]} records The Records that were loaded
19886 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19888 beforeloadadd : true,
19891 * Fires after a new set of Records has been loaded, before they are added to the store.
19892 * @param {Store} this
19893 * @param {Roo.data.Record[]} records The Records that were loaded
19894 * @param {Object} options The loading options that were specified (see {@link #load} for details)
19895 * @params {Object} return from reader
19899 * @event loadexception
19900 * Fires if an exception occurs in the Proxy during loading.
19901 * Called with the signature of the Proxy's "loadexception" event.
19902 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
19905 * @param {Object} return from JsonData.reader() - success, totalRecords, records
19906 * @param {Object} load options
19907 * @param {Object} jsonData from your request (normally this contains the Exception)
19909 loadexception : true
19913 this.proxy = Roo.factory(this.proxy, Roo.data);
19914 this.proxy.xmodule = this.xmodule || false;
19915 this.relayEvents(this.proxy, ["loadexception"]);
19917 this.sortToggle = {};
19918 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
19920 Roo.data.Store.superclass.constructor.call(this);
19922 if(this.inlineData){
19923 this.loadData(this.inlineData);
19924 delete this.inlineData;
19928 Roo.extend(Roo.data.Store, Roo.util.Observable, {
19930 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
19931 * without a remote query - used by combo/forms at present.
19935 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
19938 * @cfg {Array} data Inline data to be loaded when the store is initialized.
19941 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
19942 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
19945 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
19946 * on any HTTP request
19949 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
19952 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
19956 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
19957 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
19959 remoteSort : false,
19962 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
19963 * loaded or when a record is removed. (defaults to false).
19965 pruneModifiedRecords : false,
19968 lastOptions : null,
19971 * Add Records to the Store and fires the add event.
19972 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
19974 add : function(records){
19975 records = [].concat(records);
19976 for(var i = 0, len = records.length; i < len; i++){
19977 records[i].join(this);
19979 var index = this.data.length;
19980 this.data.addAll(records);
19981 this.fireEvent("add", this, records, index);
19985 * Remove a Record from the Store and fires the remove event.
19986 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
19988 remove : function(record){
19989 var index = this.data.indexOf(record);
19990 this.data.removeAt(index);
19991 if(this.pruneModifiedRecords){
19992 this.modified.remove(record);
19994 this.fireEvent("remove", this, record, index);
19998 * Remove all Records from the Store and fires the clear event.
20000 removeAll : function(){
20002 if(this.pruneModifiedRecords){
20003 this.modified = [];
20005 this.fireEvent("clear", this);
20009 * Inserts Records to the Store at the given index and fires the add event.
20010 * @param {Number} index The start index at which to insert the passed Records.
20011 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
20013 insert : function(index, records){
20014 records = [].concat(records);
20015 for(var i = 0, len = records.length; i < len; i++){
20016 this.data.insert(index, records[i]);
20017 records[i].join(this);
20019 this.fireEvent("add", this, records, index);
20023 * Get the index within the cache of the passed Record.
20024 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
20025 * @return {Number} The index of the passed Record. Returns -1 if not found.
20027 indexOf : function(record){
20028 return this.data.indexOf(record);
20032 * Get the index within the cache of the Record with the passed id.
20033 * @param {String} id The id of the Record to find.
20034 * @return {Number} The index of the Record. Returns -1 if not found.
20036 indexOfId : function(id){
20037 return this.data.indexOfKey(id);
20041 * Get the Record with the specified id.
20042 * @param {String} id The id of the Record to find.
20043 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
20045 getById : function(id){
20046 return this.data.key(id);
20050 * Get the Record at the specified index.
20051 * @param {Number} index The index of the Record to find.
20052 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
20054 getAt : function(index){
20055 return this.data.itemAt(index);
20059 * Returns a range of Records between specified indices.
20060 * @param {Number} startIndex (optional) The starting index (defaults to 0)
20061 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
20062 * @return {Roo.data.Record[]} An array of Records
20064 getRange : function(start, end){
20065 return this.data.getRange(start, end);
20069 storeOptions : function(o){
20070 o = Roo.apply({}, o);
20073 this.lastOptions = o;
20077 * Loads the Record cache from the configured Proxy using the configured Reader.
20079 * If using remote paging, then the first load call must specify the <em>start</em>
20080 * and <em>limit</em> properties in the options.params property to establish the initial
20081 * position within the dataset, and the number of Records to cache on each read from the Proxy.
20083 * <strong>It is important to note that for remote data sources, loading is asynchronous,
20084 * and this call will return before the new data has been loaded. Perform any post-processing
20085 * in a callback function, or in a "load" event handler.</strong>
20087 * @param {Object} options An object containing properties which control loading options:<ul>
20088 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
20089 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
20090 * passed the following arguments:<ul>
20091 * <li>r : Roo.data.Record[]</li>
20092 * <li>options: Options object from the load call</li>
20093 * <li>success: Boolean success indicator</li></ul></li>
20094 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
20095 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
20098 load : function(options){
20099 options = options || {};
20100 if(this.fireEvent("beforeload", this, options) !== false){
20101 this.storeOptions(options);
20102 var p = Roo.apply(options.params || {}, this.baseParams);
20103 // if meta was not loaded from remote source.. try requesting it.
20104 if (!this.reader.metaFromRemote) {
20105 p._requestMeta = 1;
20107 if(this.sortInfo && this.remoteSort){
20108 var pn = this.paramNames;
20109 p[pn["sort"]] = this.sortInfo.field;
20110 p[pn["dir"]] = this.sortInfo.direction;
20112 if (this.multiSort) {
20113 var pn = this.paramNames;
20114 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
20117 this.proxy.load(p, this.reader, this.loadRecords, this, options);
20122 * Reloads the Record cache from the configured Proxy using the configured Reader and
20123 * the options from the last load operation performed.
20124 * @param {Object} options (optional) An object containing properties which may override the options
20125 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
20126 * the most recently used options are reused).
20128 reload : function(options){
20129 this.load(Roo.applyIf(options||{}, this.lastOptions));
20133 // Called as a callback by the Reader during a load operation.
20134 loadRecords : function(o, options, success){
20135 if(!o || success === false){
20136 if(success !== false){
20137 this.fireEvent("load", this, [], options, o);
20139 if(options.callback){
20140 options.callback.call(options.scope || this, [], options, false);
20144 // if data returned failure - throw an exception.
20145 if (o.success === false) {
20146 // show a message if no listener is registered.
20147 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
20148 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
20150 // loadmask wil be hooked into this..
20151 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
20154 var r = o.records, t = o.totalRecords || r.length;
20156 this.fireEvent("beforeloadadd", this, r, options, o);
20158 if(!options || options.add !== true){
20159 if(this.pruneModifiedRecords){
20160 this.modified = [];
20162 for(var i = 0, len = r.length; i < len; i++){
20166 this.data = this.snapshot;
20167 delete this.snapshot;
20170 this.data.addAll(r);
20171 this.totalLength = t;
20173 this.fireEvent("datachanged", this);
20175 this.totalLength = Math.max(t, this.data.length+r.length);
20178 this.fireEvent("load", this, r, options, o);
20179 if(options.callback){
20180 options.callback.call(options.scope || this, r, options, true);
20186 * Loads data from a passed data block. A Reader which understands the format of the data
20187 * must have been configured in the constructor.
20188 * @param {Object} data The data block from which to read the Records. The format of the data expected
20189 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
20190 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
20192 loadData : function(o, append){
20193 var r = this.reader.readRecords(o);
20194 this.loadRecords(r, {add: append}, true);
20198 * Gets the number of cached records.
20200 * <em>If using paging, this may not be the total size of the dataset. If the data object
20201 * used by the Reader contains the dataset size, then the getTotalCount() function returns
20202 * the data set size</em>
20204 getCount : function(){
20205 return this.data.length || 0;
20209 * Gets the total number of records in the dataset as returned by the server.
20211 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
20212 * the dataset size</em>
20214 getTotalCount : function(){
20215 return this.totalLength || 0;
20219 * Returns the sort state of the Store as an object with two properties:
20221 field {String} The name of the field by which the Records are sorted
20222 direction {String} The sort order, "ASC" or "DESC"
20225 getSortState : function(){
20226 return this.sortInfo;
20230 applySort : function(){
20231 if(this.sortInfo && !this.remoteSort){
20232 var s = this.sortInfo, f = s.field;
20233 var st = this.fields.get(f).sortType;
20234 var fn = function(r1, r2){
20235 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
20236 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
20238 this.data.sort(s.direction, fn);
20239 if(this.snapshot && this.snapshot != this.data){
20240 this.snapshot.sort(s.direction, fn);
20246 * Sets the default sort column and order to be used by the next load operation.
20247 * @param {String} fieldName The name of the field to sort by.
20248 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20250 setDefaultSort : function(field, dir){
20251 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
20255 * Sort the Records.
20256 * If remote sorting is used, the sort is performed on the server, and the cache is
20257 * reloaded. If local sorting is used, the cache is sorted internally.
20258 * @param {String} fieldName The name of the field to sort by.
20259 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
20261 sort : function(fieldName, dir){
20262 var f = this.fields.get(fieldName);
20264 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
20266 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
20267 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
20272 this.sortToggle[f.name] = dir;
20273 this.sortInfo = {field: f.name, direction: dir};
20274 if(!this.remoteSort){
20276 this.fireEvent("datachanged", this);
20278 this.load(this.lastOptions);
20283 * Calls the specified function for each of the Records in the cache.
20284 * @param {Function} fn The function to call. The Record is passed as the first parameter.
20285 * Returning <em>false</em> aborts and exits the iteration.
20286 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
20288 each : function(fn, scope){
20289 this.data.each(fn, scope);
20293 * Gets all records modified since the last commit. Modified records are persisted across load operations
20294 * (e.g., during paging).
20295 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
20297 getModifiedRecords : function(){
20298 return this.modified;
20302 createFilterFn : function(property, value, anyMatch){
20303 if(!value.exec){ // not a regex
20304 value = String(value);
20305 if(value.length == 0){
20308 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
20310 return function(r){
20311 return value.test(r.data[property]);
20316 * Sums the value of <i>property</i> for each record between start and end and returns the result.
20317 * @param {String} property A field on your records
20318 * @param {Number} start The record index to start at (defaults to 0)
20319 * @param {Number} end The last record index to include (defaults to length - 1)
20320 * @return {Number} The sum
20322 sum : function(property, start, end){
20323 var rs = this.data.items, v = 0;
20324 start = start || 0;
20325 end = (end || end === 0) ? end : rs.length-1;
20327 for(var i = start; i <= end; i++){
20328 v += (rs[i].data[property] || 0);
20334 * Filter the records by a specified property.
20335 * @param {String} field A field on your records
20336 * @param {String/RegExp} value Either a string that the field
20337 * should start with or a RegExp to test against the field
20338 * @param {Boolean} anyMatch True to match any part not just the beginning
20340 filter : function(property, value, anyMatch){
20341 var fn = this.createFilterFn(property, value, anyMatch);
20342 return fn ? this.filterBy(fn) : this.clearFilter();
20346 * Filter by a function. The specified function will be called with each
20347 * record in this data source. If the function returns true the record is included,
20348 * otherwise it is filtered.
20349 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20350 * @param {Object} scope (optional) The scope of the function (defaults to this)
20352 filterBy : function(fn, scope){
20353 this.snapshot = this.snapshot || this.data;
20354 this.data = this.queryBy(fn, scope||this);
20355 this.fireEvent("datachanged", this);
20359 * Query the records by a specified property.
20360 * @param {String} field A field on your records
20361 * @param {String/RegExp} value Either a string that the field
20362 * should start with or a RegExp to test against the field
20363 * @param {Boolean} anyMatch True to match any part not just the beginning
20364 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20366 query : function(property, value, anyMatch){
20367 var fn = this.createFilterFn(property, value, anyMatch);
20368 return fn ? this.queryBy(fn) : this.data.clone();
20372 * Query by a function. The specified function will be called with each
20373 * record in this data source. If the function returns true the record is included
20375 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
20376 * @param {Object} scope (optional) The scope of the function (defaults to this)
20377 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
20379 queryBy : function(fn, scope){
20380 var data = this.snapshot || this.data;
20381 return data.filterBy(fn, scope||this);
20385 * Collects unique values for a particular dataIndex from this store.
20386 * @param {String} dataIndex The property to collect
20387 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
20388 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
20389 * @return {Array} An array of the unique values
20391 collect : function(dataIndex, allowNull, bypassFilter){
20392 var d = (bypassFilter === true && this.snapshot) ?
20393 this.snapshot.items : this.data.items;
20394 var v, sv, r = [], l = {};
20395 for(var i = 0, len = d.length; i < len; i++){
20396 v = d[i].data[dataIndex];
20398 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
20407 * Revert to a view of the Record cache with no filtering applied.
20408 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
20410 clearFilter : function(suppressEvent){
20411 if(this.snapshot && this.snapshot != this.data){
20412 this.data = this.snapshot;
20413 delete this.snapshot;
20414 if(suppressEvent !== true){
20415 this.fireEvent("datachanged", this);
20421 afterEdit : function(record){
20422 if(this.modified.indexOf(record) == -1){
20423 this.modified.push(record);
20425 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
20429 afterReject : function(record){
20430 this.modified.remove(record);
20431 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
20435 afterCommit : function(record){
20436 this.modified.remove(record);
20437 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
20441 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
20442 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
20444 commitChanges : function(){
20445 var m = this.modified.slice(0);
20446 this.modified = [];
20447 for(var i = 0, len = m.length; i < len; i++){
20453 * Cancel outstanding changes on all changed records.
20455 rejectChanges : function(){
20456 var m = this.modified.slice(0);
20457 this.modified = [];
20458 for(var i = 0, len = m.length; i < len; i++){
20463 onMetaChange : function(meta, rtype, o){
20464 this.recordType = rtype;
20465 this.fields = rtype.prototype.fields;
20466 delete this.snapshot;
20467 this.sortInfo = meta.sortInfo || this.sortInfo;
20468 this.modified = [];
20469 this.fireEvent('metachange', this, this.reader.meta);
20473 * Ext JS Library 1.1.1
20474 * Copyright(c) 2006-2007, Ext JS, LLC.
20476 * Originally Released Under LGPL - original licence link has changed is not relivant.
20479 * <script type="text/javascript">
20483 * @class Roo.data.SimpleStore
20484 * @extends Roo.data.Store
20485 * Small helper class to make creating Stores from Array data easier.
20486 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
20487 * @cfg {Array} fields An array of field definition objects, or field name strings.
20488 * @cfg {Array} data The multi-dimensional array of data
20490 * @param {Object} config
20492 Roo.data.SimpleStore = function(config){
20493 Roo.data.SimpleStore.superclass.constructor.call(this, {
20495 reader: new Roo.data.ArrayReader({
20498 Roo.data.Record.create(config.fields)
20500 proxy : new Roo.data.MemoryProxy(config.data)
20504 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
20506 * Ext JS Library 1.1.1
20507 * Copyright(c) 2006-2007, Ext JS, LLC.
20509 * Originally Released Under LGPL - original licence link has changed is not relivant.
20512 * <script type="text/javascript">
20517 * @extends Roo.data.Store
20518 * @class Roo.data.JsonStore
20519 * Small helper class to make creating Stores for JSON data easier. <br/>
20521 var store = new Roo.data.JsonStore({
20522 url: 'get-images.php',
20524 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
20527 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
20528 * JsonReader and HttpProxy (unless inline data is provided).</b>
20529 * @cfg {Array} fields An array of field definition objects, or field name strings.
20531 * @param {Object} config
20533 Roo.data.JsonStore = function(c){
20534 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
20535 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
20536 reader: new Roo.data.JsonReader(c, c.fields)
20539 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
20541 * Ext JS Library 1.1.1
20542 * Copyright(c) 2006-2007, Ext JS, LLC.
20544 * Originally Released Under LGPL - original licence link has changed is not relivant.
20547 * <script type="text/javascript">
20551 Roo.data.Field = function(config){
20552 if(typeof config == "string"){
20553 config = {name: config};
20555 Roo.apply(this, config);
20558 this.type = "auto";
20561 var st = Roo.data.SortTypes;
20562 // named sortTypes are supported, here we look them up
20563 if(typeof this.sortType == "string"){
20564 this.sortType = st[this.sortType];
20567 // set default sortType for strings and dates
20568 if(!this.sortType){
20571 this.sortType = st.asUCString;
20574 this.sortType = st.asDate;
20577 this.sortType = st.none;
20582 var stripRe = /[\$,%]/g;
20584 // prebuilt conversion function for this field, instead of
20585 // switching every time we're reading a value
20587 var cv, dateFormat = this.dateFormat;
20592 cv = function(v){ return v; };
20595 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
20599 return v !== undefined && v !== null && v !== '' ?
20600 parseInt(String(v).replace(stripRe, ""), 10) : '';
20605 return v !== undefined && v !== null && v !== '' ?
20606 parseFloat(String(v).replace(stripRe, ""), 10) : '';
20611 cv = function(v){ return v === true || v === "true" || v == 1; };
20618 if(v instanceof Date){
20622 if(dateFormat == "timestamp"){
20623 return new Date(v*1000);
20625 return Date.parseDate(v, dateFormat);
20627 var parsed = Date.parse(v);
20628 return parsed ? new Date(parsed) : null;
20637 Roo.data.Field.prototype = {
20645 * Ext JS Library 1.1.1
20646 * Copyright(c) 2006-2007, Ext JS, LLC.
20648 * Originally Released Under LGPL - original licence link has changed is not relivant.
20651 * <script type="text/javascript">
20654 // Base class for reading structured data from a data source. This class is intended to be
20655 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
20658 * @class Roo.data.DataReader
20659 * Base class for reading structured data from a data source. This class is intended to be
20660 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
20663 Roo.data.DataReader = function(meta, recordType){
20667 this.recordType = recordType instanceof Array ?
20668 Roo.data.Record.create(recordType) : recordType;
20671 Roo.data.DataReader.prototype = {
20673 * Create an empty record
20674 * @param {Object} data (optional) - overlay some values
20675 * @return {Roo.data.Record} record created.
20677 newRow : function(d) {
20679 this.recordType.prototype.fields.each(function(c) {
20681 case 'int' : da[c.name] = 0; break;
20682 case 'date' : da[c.name] = new Date(); break;
20683 case 'float' : da[c.name] = 0.0; break;
20684 case 'boolean' : da[c.name] = false; break;
20685 default : da[c.name] = ""; break;
20689 return new this.recordType(Roo.apply(da, d));
20694 * Ext JS Library 1.1.1
20695 * Copyright(c) 2006-2007, Ext JS, LLC.
20697 * Originally Released Under LGPL - original licence link has changed is not relivant.
20700 * <script type="text/javascript">
20704 * @class Roo.data.DataProxy
20705 * @extends Roo.data.Observable
20706 * This class is an abstract base class for implementations which provide retrieval of
20707 * unformatted data objects.<br>
20709 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
20710 * (of the appropriate type which knows how to parse the data object) to provide a block of
20711 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
20713 * Custom implementations must implement the load method as described in
20714 * {@link Roo.data.HttpProxy#load}.
20716 Roo.data.DataProxy = function(){
20719 * @event beforeload
20720 * Fires before a network request is made to retrieve a data object.
20721 * @param {Object} This DataProxy object.
20722 * @param {Object} params The params parameter to the load function.
20727 * Fires before the load method's callback is called.
20728 * @param {Object} This DataProxy object.
20729 * @param {Object} o The data object.
20730 * @param {Object} arg The callback argument object passed to the load function.
20734 * @event loadexception
20735 * Fires if an Exception occurs during data retrieval.
20736 * @param {Object} This DataProxy object.
20737 * @param {Object} o The data object.
20738 * @param {Object} arg The callback argument object passed to the load function.
20739 * @param {Object} e The Exception.
20741 loadexception : true
20743 Roo.data.DataProxy.superclass.constructor.call(this);
20746 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
20749 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
20753 * Ext JS Library 1.1.1
20754 * Copyright(c) 2006-2007, Ext JS, LLC.
20756 * Originally Released Under LGPL - original licence link has changed is not relivant.
20759 * <script type="text/javascript">
20762 * @class Roo.data.MemoryProxy
20763 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
20764 * to the Reader when its load method is called.
20766 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
20768 Roo.data.MemoryProxy = function(data){
20772 Roo.data.MemoryProxy.superclass.constructor.call(this);
20776 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
20778 * Load data from the requested source (in this case an in-memory
20779 * data object passed to the constructor), read the data object into
20780 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
20781 * process that block using the passed callback.
20782 * @param {Object} params This parameter is not used by the MemoryProxy class.
20783 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20784 * object into a block of Roo.data.Records.
20785 * @param {Function} callback The function into which to pass the block of Roo.data.records.
20786 * The function must be passed <ul>
20787 * <li>The Record block object</li>
20788 * <li>The "arg" argument from the load function</li>
20789 * <li>A boolean success indicator</li>
20791 * @param {Object} scope The scope in which to call the callback
20792 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20794 load : function(params, reader, callback, scope, arg){
20795 params = params || {};
20798 result = reader.readRecords(this.data);
20800 this.fireEvent("loadexception", this, arg, null, e);
20801 callback.call(scope, null, arg, false);
20804 callback.call(scope, result, arg, true);
20808 update : function(params, records){
20813 * Ext JS Library 1.1.1
20814 * Copyright(c) 2006-2007, Ext JS, LLC.
20816 * Originally Released Under LGPL - original licence link has changed is not relivant.
20819 * <script type="text/javascript">
20822 * @class Roo.data.HttpProxy
20823 * @extends Roo.data.DataProxy
20824 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
20825 * configured to reference a certain URL.<br><br>
20827 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
20828 * from which the running page was served.<br><br>
20830 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
20832 * Be aware that to enable the browser to parse an XML document, the server must set
20833 * the Content-Type header in the HTTP response to "text/xml".
20835 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
20836 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
20837 * will be used to make the request.
20839 Roo.data.HttpProxy = function(conn){
20840 Roo.data.HttpProxy.superclass.constructor.call(this);
20841 // is conn a conn config or a real conn?
20843 this.useAjax = !conn || !conn.events;
20847 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
20848 // thse are take from connection...
20851 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
20854 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
20855 * extra parameters to each request made by this object. (defaults to undefined)
20858 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
20859 * to each request made by this object. (defaults to undefined)
20862 * @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)
20865 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
20868 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
20874 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
20878 * Return the {@link Roo.data.Connection} object being used by this Proxy.
20879 * @return {Connection} The Connection object. This object may be used to subscribe to events on
20880 * a finer-grained basis than the DataProxy events.
20882 getConnection : function(){
20883 return this.useAjax ? Roo.Ajax : this.conn;
20887 * Load data from the configured {@link Roo.data.Connection}, read the data object into
20888 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
20889 * process that block using the passed callback.
20890 * @param {Object} params An object containing properties which are to be used as HTTP parameters
20891 * for the request to the remote server.
20892 * @param {Roo.data.DataReader} reader The Reader object which converts the data
20893 * object into a block of Roo.data.Records.
20894 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
20895 * The function must be passed <ul>
20896 * <li>The Record block object</li>
20897 * <li>The "arg" argument from the load function</li>
20898 * <li>A boolean success indicator</li>
20900 * @param {Object} scope The scope in which to call the callback
20901 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
20903 load : function(params, reader, callback, scope, arg){
20904 if(this.fireEvent("beforeload", this, params) !== false){
20906 params : params || {},
20908 callback : callback,
20913 callback : this.loadResponse,
20917 Roo.applyIf(o, this.conn);
20918 if(this.activeRequest){
20919 Roo.Ajax.abort(this.activeRequest);
20921 this.activeRequest = Roo.Ajax.request(o);
20923 this.conn.request(o);
20926 callback.call(scope||this, null, arg, false);
20931 loadResponse : function(o, success, response){
20932 delete this.activeRequest;
20934 this.fireEvent("loadexception", this, o, response);
20935 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20940 result = o.reader.read(response);
20942 this.fireEvent("loadexception", this, o, response, e);
20943 o.request.callback.call(o.request.scope, null, o.request.arg, false);
20947 this.fireEvent("load", this, o, o.request.arg);
20948 o.request.callback.call(o.request.scope, result, o.request.arg, true);
20952 update : function(dataSet){
20957 updateResponse : function(dataSet){
20962 * Ext JS Library 1.1.1
20963 * Copyright(c) 2006-2007, Ext JS, LLC.
20965 * Originally Released Under LGPL - original licence link has changed is not relivant.
20968 * <script type="text/javascript">
20972 * @class Roo.data.ScriptTagProxy
20973 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
20974 * other than the originating domain of the running page.<br><br>
20976 * <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
20977 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
20979 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
20980 * source code that is used as the source inside a <script> tag.<br><br>
20982 * In order for the browser to process the returned data, the server must wrap the data object
20983 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
20984 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
20985 * depending on whether the callback name was passed:
20988 boolean scriptTag = false;
20989 String cb = request.getParameter("callback");
20992 response.setContentType("text/javascript");
20994 response.setContentType("application/x-json");
20996 Writer out = response.getWriter();
20998 out.write(cb + "(");
21000 out.print(dataBlock.toJsonString());
21007 * @param {Object} config A configuration object.
21009 Roo.data.ScriptTagProxy = function(config){
21010 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
21011 Roo.apply(this, config);
21012 this.head = document.getElementsByTagName("head")[0];
21015 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
21017 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
21019 * @cfg {String} url The URL from which to request the data object.
21022 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
21026 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
21027 * the server the name of the callback function set up by the load call to process the returned data object.
21028 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
21029 * javascript output which calls this named function passing the data object as its only parameter.
21031 callbackParam : "callback",
21033 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
21034 * name to the request.
21039 * Load data from the configured URL, read the data object into
21040 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
21041 * process that block using the passed callback.
21042 * @param {Object} params An object containing properties which are to be used as HTTP parameters
21043 * for the request to the remote server.
21044 * @param {Roo.data.DataReader} reader The Reader object which converts the data
21045 * object into a block of Roo.data.Records.
21046 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
21047 * The function must be passed <ul>
21048 * <li>The Record block object</li>
21049 * <li>The "arg" argument from the load function</li>
21050 * <li>A boolean success indicator</li>
21052 * @param {Object} scope The scope in which to call the callback
21053 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
21055 load : function(params, reader, callback, scope, arg){
21056 if(this.fireEvent("beforeload", this, params) !== false){
21058 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
21060 var url = this.url;
21061 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
21063 url += "&_dc=" + (new Date().getTime());
21065 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
21068 cb : "stcCallback"+transId,
21069 scriptId : "stcScript"+transId,
21073 callback : callback,
21079 window[trans.cb] = function(o){
21080 conn.handleResponse(o, trans);
21083 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
21085 if(this.autoAbort !== false){
21089 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
21091 var script = document.createElement("script");
21092 script.setAttribute("src", url);
21093 script.setAttribute("type", "text/javascript");
21094 script.setAttribute("id", trans.scriptId);
21095 this.head.appendChild(script);
21097 this.trans = trans;
21099 callback.call(scope||this, null, arg, false);
21104 isLoading : function(){
21105 return this.trans ? true : false;
21109 * Abort the current server request.
21111 abort : function(){
21112 if(this.isLoading()){
21113 this.destroyTrans(this.trans);
21118 destroyTrans : function(trans, isLoaded){
21119 this.head.removeChild(document.getElementById(trans.scriptId));
21120 clearTimeout(trans.timeoutId);
21122 window[trans.cb] = undefined;
21124 delete window[trans.cb];
21127 // if hasn't been loaded, wait for load to remove it to prevent script error
21128 window[trans.cb] = function(){
21129 window[trans.cb] = undefined;
21131 delete window[trans.cb];
21138 handleResponse : function(o, trans){
21139 this.trans = false;
21140 this.destroyTrans(trans, true);
21143 result = trans.reader.readRecords(o);
21145 this.fireEvent("loadexception", this, o, trans.arg, e);
21146 trans.callback.call(trans.scope||window, null, trans.arg, false);
21149 this.fireEvent("load", this, o, trans.arg);
21150 trans.callback.call(trans.scope||window, result, trans.arg, true);
21154 handleFailure : function(trans){
21155 this.trans = false;
21156 this.destroyTrans(trans, false);
21157 this.fireEvent("loadexception", this, null, trans.arg);
21158 trans.callback.call(trans.scope||window, null, trans.arg, false);
21162 * Ext JS Library 1.1.1
21163 * Copyright(c) 2006-2007, Ext JS, LLC.
21165 * Originally Released Under LGPL - original licence link has changed is not relivant.
21168 * <script type="text/javascript">
21172 * @class Roo.data.JsonReader
21173 * @extends Roo.data.DataReader
21174 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
21175 * based on mappings in a provided Roo.data.Record constructor.
21177 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
21178 * in the reply previously.
21183 var RecordDef = Roo.data.Record.create([
21184 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21185 {name: 'occupation'} // This field will use "occupation" as the mapping.
21187 var myReader = new Roo.data.JsonReader({
21188 totalProperty: "results", // The property which contains the total dataset size (optional)
21189 root: "rows", // The property which contains an Array of row objects
21190 id: "id" // The property within each row object that provides an ID for the record (optional)
21194 * This would consume a JSON file like this:
21196 { 'results': 2, 'rows': [
21197 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
21198 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
21201 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
21202 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21203 * paged from the remote server.
21204 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
21205 * @cfg {String} root name of the property which contains the Array of row objects.
21206 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
21208 * Create a new JsonReader
21209 * @param {Object} meta Metadata configuration options
21210 * @param {Object} recordType Either an Array of field definition objects,
21211 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
21213 Roo.data.JsonReader = function(meta, recordType){
21216 // set some defaults:
21217 Roo.applyIf(meta, {
21218 totalProperty: 'total',
21219 successProperty : 'success',
21224 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21226 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
21229 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
21230 * Used by Store query builder to append _requestMeta to params.
21233 metaFromRemote : false,
21235 * This method is only used by a DataProxy which has retrieved data from a remote server.
21236 * @param {Object} response The XHR object which contains the JSON data in its responseText.
21237 * @return {Object} data A data block which is used by an Roo.data.Store object as
21238 * a cache of Roo.data.Records.
21240 read : function(response){
21241 var json = response.responseText;
21243 var o = /* eval:var:o */ eval("("+json+")");
21245 throw {message: "JsonReader.read: Json object not found"};
21251 this.metaFromRemote = true;
21252 this.meta = o.metaData;
21253 this.recordType = Roo.data.Record.create(o.metaData.fields);
21254 this.onMetaChange(this.meta, this.recordType, o);
21256 return this.readRecords(o);
21259 // private function a store will implement
21260 onMetaChange : function(meta, recordType, o){
21267 simpleAccess: function(obj, subsc) {
21274 getJsonAccessor: function(){
21276 return function(expr) {
21278 return(re.test(expr))
21279 ? new Function("obj", "return obj." + expr)
21284 return Roo.emptyFn;
21289 * Create a data block containing Roo.data.Records from an XML document.
21290 * @param {Object} o An object which contains an Array of row objects in the property specified
21291 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
21292 * which contains the total size of the dataset.
21293 * @return {Object} data A data block which is used by an Roo.data.Store object as
21294 * a cache of Roo.data.Records.
21296 readRecords : function(o){
21298 * After any data loads, the raw JSON data is available for further custom processing.
21302 var s = this.meta, Record = this.recordType,
21303 f = Record.prototype.fields, fi = f.items, fl = f.length;
21305 // Generate extraction functions for the totalProperty, the root, the id, and for each field
21307 if(s.totalProperty) {
21308 this.getTotal = this.getJsonAccessor(s.totalProperty);
21310 if(s.successProperty) {
21311 this.getSuccess = this.getJsonAccessor(s.successProperty);
21313 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
21315 var g = this.getJsonAccessor(s.id);
21316 this.getId = function(rec) {
21318 return (r === undefined || r === "") ? null : r;
21321 this.getId = function(){return null;};
21324 for(var jj = 0; jj < fl; jj++){
21326 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
21327 this.ef[jj] = this.getJsonAccessor(map);
21331 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
21332 if(s.totalProperty){
21333 var vt = parseInt(this.getTotal(o), 10);
21338 if(s.successProperty){
21339 var vs = this.getSuccess(o);
21340 if(vs === false || vs === 'false'){
21345 for(var i = 0; i < c; i++){
21348 var id = this.getId(n);
21349 for(var j = 0; j < fl; j++){
21351 var v = this.ef[j](n);
21353 Roo.log('missing convert for ' + f.name);
21357 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
21359 var record = new Record(values, id);
21361 records[i] = record;
21367 totalRecords : totalRecords
21372 * Ext JS Library 1.1.1
21373 * Copyright(c) 2006-2007, Ext JS, LLC.
21375 * Originally Released Under LGPL - original licence link has changed is not relivant.
21378 * <script type="text/javascript">
21382 * @class Roo.data.XmlReader
21383 * @extends Roo.data.DataReader
21384 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
21385 * based on mappings in a provided Roo.data.Record constructor.<br><br>
21387 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
21388 * header in the HTTP response must be set to "text/xml".</em>
21392 var RecordDef = Roo.data.Record.create([
21393 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
21394 {name: 'occupation'} // This field will use "occupation" as the mapping.
21396 var myReader = new Roo.data.XmlReader({
21397 totalRecords: "results", // The element which contains the total dataset size (optional)
21398 record: "row", // The repeated element which contains row information
21399 id: "id" // The element within the row that provides an ID for the record (optional)
21403 * This would consume an XML file like this:
21407 <results>2</results>
21410 <name>Bill</name>
21411 <occupation>Gardener</occupation>
21415 <name>Ben</name>
21416 <occupation>Horticulturalist</occupation>
21420 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
21421 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
21422 * paged from the remote server.
21423 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
21424 * @cfg {String} success The DomQuery path to the success attribute used by forms.
21425 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
21426 * a record identifier value.
21428 * Create a new XmlReader
21429 * @param {Object} meta Metadata configuration options
21430 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
21431 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
21432 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
21434 Roo.data.XmlReader = function(meta, recordType){
21436 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
21438 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
21440 * This method is only used by a DataProxy which has retrieved data from a remote server.
21441 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
21442 * to contain a method called 'responseXML' that returns an XML document object.
21443 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21444 * a cache of Roo.data.Records.
21446 read : function(response){
21447 var doc = response.responseXML;
21449 throw {message: "XmlReader.read: XML Document not available"};
21451 return this.readRecords(doc);
21455 * Create a data block containing Roo.data.Records from an XML document.
21456 * @param {Object} doc A parsed XML document.
21457 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
21458 * a cache of Roo.data.Records.
21460 readRecords : function(doc){
21462 * After any data loads/reads, the raw XML Document is available for further custom processing.
21463 * @type XMLDocument
21465 this.xmlData = doc;
21466 var root = doc.documentElement || doc;
21467 var q = Roo.DomQuery;
21468 var recordType = this.recordType, fields = recordType.prototype.fields;
21469 var sid = this.meta.id;
21470 var totalRecords = 0, success = true;
21471 if(this.meta.totalRecords){
21472 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
21475 if(this.meta.success){
21476 var sv = q.selectValue(this.meta.success, root, true);
21477 success = sv !== false && sv !== 'false';
21480 var ns = q.select(this.meta.record, root);
21481 for(var i = 0, len = ns.length; i < len; i++) {
21484 var id = sid ? q.selectValue(sid, n) : undefined;
21485 for(var j = 0, jlen = fields.length; j < jlen; j++){
21486 var f = fields.items[j];
21487 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
21489 values[f.name] = v;
21491 var record = new recordType(values, id);
21493 records[records.length] = record;
21499 totalRecords : totalRecords || records.length
21504 * Ext JS Library 1.1.1
21505 * Copyright(c) 2006-2007, Ext JS, LLC.
21507 * Originally Released Under LGPL - original licence link has changed is not relivant.
21510 * <script type="text/javascript">
21514 * @class Roo.data.ArrayReader
21515 * @extends Roo.data.DataReader
21516 * Data reader class to create an Array of Roo.data.Record objects from an Array.
21517 * Each element of that Array represents a row of data fields. The
21518 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
21519 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
21523 var RecordDef = Roo.data.Record.create([
21524 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
21525 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
21527 var myReader = new Roo.data.ArrayReader({
21528 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
21532 * This would consume an Array like this:
21534 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
21536 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
21538 * Create a new JsonReader
21539 * @param {Object} meta Metadata configuration options.
21540 * @param {Object} recordType Either an Array of field definition objects
21541 * as specified to {@link Roo.data.Record#create},
21542 * or an {@link Roo.data.Record} object
21543 * created using {@link Roo.data.Record#create}.
21545 Roo.data.ArrayReader = function(meta, recordType){
21546 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
21549 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
21551 * Create a data block containing Roo.data.Records from an XML document.
21552 * @param {Object} o An Array of row objects which represents the dataset.
21553 * @return {Object} data A data block which is used by an Roo.data.Store object as
21554 * a cache of Roo.data.Records.
21556 readRecords : function(o){
21557 var sid = this.meta ? this.meta.id : null;
21558 var recordType = this.recordType, fields = recordType.prototype.fields;
21561 for(var i = 0; i < root.length; i++){
21564 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
21565 for(var j = 0, jlen = fields.length; j < jlen; j++){
21566 var f = fields.items[j];
21567 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
21568 var v = n[k] !== undefined ? n[k] : f.defaultValue;
21570 values[f.name] = v;
21572 var record = new recordType(values, id);
21574 records[records.length] = record;
21578 totalRecords : records.length
21583 * Ext JS Library 1.1.1
21584 * Copyright(c) 2006-2007, Ext JS, LLC.
21586 * Originally Released Under LGPL - original licence link has changed is not relivant.
21589 * <script type="text/javascript">
21594 * @class Roo.data.Tree
21595 * @extends Roo.util.Observable
21596 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
21597 * in the tree have most standard DOM functionality.
21599 * @param {Node} root (optional) The root node
21601 Roo.data.Tree = function(root){
21602 this.nodeHash = {};
21604 * The root node for this tree
21609 this.setRootNode(root);
21614 * Fires when a new child node is appended to a node in this tree.
21615 * @param {Tree} tree The owner tree
21616 * @param {Node} parent The parent node
21617 * @param {Node} node The newly appended node
21618 * @param {Number} index The index of the newly appended node
21623 * Fires when a child node is removed from a node in this tree.
21624 * @param {Tree} tree The owner tree
21625 * @param {Node} parent The parent node
21626 * @param {Node} node The child node removed
21631 * Fires when a node is moved to a new location in the tree
21632 * @param {Tree} tree The owner tree
21633 * @param {Node} node The node moved
21634 * @param {Node} oldParent The old parent of this node
21635 * @param {Node} newParent The new parent of this node
21636 * @param {Number} index The index it was moved to
21641 * Fires when a new child node is inserted in a node in this tree.
21642 * @param {Tree} tree The owner tree
21643 * @param {Node} parent The parent node
21644 * @param {Node} node The child node inserted
21645 * @param {Node} refNode The child node the node was inserted before
21649 * @event beforeappend
21650 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
21651 * @param {Tree} tree The owner tree
21652 * @param {Node} parent The parent node
21653 * @param {Node} node The child node to be appended
21655 "beforeappend" : true,
21657 * @event beforeremove
21658 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
21659 * @param {Tree} tree The owner tree
21660 * @param {Node} parent The parent node
21661 * @param {Node} node The child node to be removed
21663 "beforeremove" : true,
21665 * @event beforemove
21666 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
21667 * @param {Tree} tree The owner tree
21668 * @param {Node} node The node being moved
21669 * @param {Node} oldParent The parent of the node
21670 * @param {Node} newParent The new parent the node is moving to
21671 * @param {Number} index The index it is being moved to
21673 "beforemove" : true,
21675 * @event beforeinsert
21676 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
21677 * @param {Tree} tree The owner tree
21678 * @param {Node} parent The parent node
21679 * @param {Node} node The child node to be inserted
21680 * @param {Node} refNode The child node the node is being inserted before
21682 "beforeinsert" : true
21685 Roo.data.Tree.superclass.constructor.call(this);
21688 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
21689 pathSeparator: "/",
21691 proxyNodeEvent : function(){
21692 return this.fireEvent.apply(this, arguments);
21696 * Returns the root node for this tree.
21699 getRootNode : function(){
21704 * Sets the root node for this tree.
21705 * @param {Node} node
21708 setRootNode : function(node){
21710 node.ownerTree = this;
21711 node.isRoot = true;
21712 this.registerNode(node);
21717 * Gets a node in this tree by its id.
21718 * @param {String} id
21721 getNodeById : function(id){
21722 return this.nodeHash[id];
21725 registerNode : function(node){
21726 this.nodeHash[node.id] = node;
21729 unregisterNode : function(node){
21730 delete this.nodeHash[node.id];
21733 toString : function(){
21734 return "[Tree"+(this.id?" "+this.id:"")+"]";
21739 * @class Roo.data.Node
21740 * @extends Roo.util.Observable
21741 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
21742 * @cfg {String} id The id for this node. If one is not specified, one is generated.
21744 * @param {Object} attributes The attributes/config for the node
21746 Roo.data.Node = function(attributes){
21748 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
21751 this.attributes = attributes || {};
21752 this.leaf = this.attributes.leaf;
21754 * The node id. @type String
21756 this.id = this.attributes.id;
21758 this.id = Roo.id(null, "ynode-");
21759 this.attributes.id = this.id;
21764 * All child nodes of this node. @type Array
21766 this.childNodes = [];
21767 if(!this.childNodes.indexOf){ // indexOf is a must
21768 this.childNodes.indexOf = function(o){
21769 for(var i = 0, len = this.length; i < len; i++){
21778 * The parent node for this node. @type Node
21780 this.parentNode = null;
21782 * The first direct child node of this node, or null if this node has no child nodes. @type Node
21784 this.firstChild = null;
21786 * The last direct child node of this node, or null if this node has no child nodes. @type Node
21788 this.lastChild = null;
21790 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
21792 this.previousSibling = null;
21794 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
21796 this.nextSibling = null;
21801 * Fires when a new child node is appended
21802 * @param {Tree} tree The owner tree
21803 * @param {Node} this This node
21804 * @param {Node} node The newly appended node
21805 * @param {Number} index The index of the newly appended node
21810 * Fires when a child node is removed
21811 * @param {Tree} tree The owner tree
21812 * @param {Node} this This node
21813 * @param {Node} node The removed node
21818 * Fires when this node is moved to a new location in the tree
21819 * @param {Tree} tree The owner tree
21820 * @param {Node} this This node
21821 * @param {Node} oldParent The old parent of this node
21822 * @param {Node} newParent The new parent of this node
21823 * @param {Number} index The index it was moved to
21828 * Fires when a new child node is inserted.
21829 * @param {Tree} tree The owner tree
21830 * @param {Node} this This node
21831 * @param {Node} node The child node inserted
21832 * @param {Node} refNode The child node the node was inserted before
21836 * @event beforeappend
21837 * Fires before a new child is appended, return false to cancel the append.
21838 * @param {Tree} tree The owner tree
21839 * @param {Node} this This node
21840 * @param {Node} node The child node to be appended
21842 "beforeappend" : true,
21844 * @event beforeremove
21845 * Fires before a child is removed, return false to cancel the remove.
21846 * @param {Tree} tree The owner tree
21847 * @param {Node} this This node
21848 * @param {Node} node The child node to be removed
21850 "beforeremove" : true,
21852 * @event beforemove
21853 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
21854 * @param {Tree} tree The owner tree
21855 * @param {Node} this This node
21856 * @param {Node} oldParent The parent of this node
21857 * @param {Node} newParent The new parent this node is moving to
21858 * @param {Number} index The index it is being moved to
21860 "beforemove" : true,
21862 * @event beforeinsert
21863 * Fires before a new child is inserted, return false to cancel the insert.
21864 * @param {Tree} tree The owner tree
21865 * @param {Node} this This node
21866 * @param {Node} node The child node to be inserted
21867 * @param {Node} refNode The child node the node is being inserted before
21869 "beforeinsert" : true
21871 this.listeners = this.attributes.listeners;
21872 Roo.data.Node.superclass.constructor.call(this);
21875 Roo.extend(Roo.data.Node, Roo.util.Observable, {
21876 fireEvent : function(evtName){
21877 // first do standard event for this node
21878 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
21881 // then bubble it up to the tree if the event wasn't cancelled
21882 var ot = this.getOwnerTree();
21884 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
21892 * Returns true if this node is a leaf
21893 * @return {Boolean}
21895 isLeaf : function(){
21896 return this.leaf === true;
21900 setFirstChild : function(node){
21901 this.firstChild = node;
21905 setLastChild : function(node){
21906 this.lastChild = node;
21911 * Returns true if this node is the last child of its parent
21912 * @return {Boolean}
21914 isLast : function(){
21915 return (!this.parentNode ? true : this.parentNode.lastChild == this);
21919 * Returns true if this node is the first child of its parent
21920 * @return {Boolean}
21922 isFirst : function(){
21923 return (!this.parentNode ? true : this.parentNode.firstChild == this);
21926 hasChildNodes : function(){
21927 return !this.isLeaf() && this.childNodes.length > 0;
21931 * Insert node(s) as the last child node of this node.
21932 * @param {Node/Array} node The node or Array of nodes to append
21933 * @return {Node} The appended node if single append, or null if an array was passed
21935 appendChild : function(node){
21937 if(node instanceof Array){
21939 }else if(arguments.length > 1){
21942 // if passed an array or multiple args do them one by one
21944 for(var i = 0, len = multi.length; i < len; i++) {
21945 this.appendChild(multi[i]);
21948 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
21951 var index = this.childNodes.length;
21952 var oldParent = node.parentNode;
21953 // it's a move, make sure we move it cleanly
21955 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
21958 oldParent.removeChild(node);
21960 index = this.childNodes.length;
21962 this.setFirstChild(node);
21964 this.childNodes.push(node);
21965 node.parentNode = this;
21966 var ps = this.childNodes[index-1];
21968 node.previousSibling = ps;
21969 ps.nextSibling = node;
21971 node.previousSibling = null;
21973 node.nextSibling = null;
21974 this.setLastChild(node);
21975 node.setOwnerTree(this.getOwnerTree());
21976 this.fireEvent("append", this.ownerTree, this, node, index);
21978 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
21985 * Removes a child node from this node.
21986 * @param {Node} node The node to remove
21987 * @return {Node} The removed node
21989 removeChild : function(node){
21990 var index = this.childNodes.indexOf(node);
21994 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
21998 // remove it from childNodes collection
21999 this.childNodes.splice(index, 1);
22002 if(node.previousSibling){
22003 node.previousSibling.nextSibling = node.nextSibling;
22005 if(node.nextSibling){
22006 node.nextSibling.previousSibling = node.previousSibling;
22009 // update child refs
22010 if(this.firstChild == node){
22011 this.setFirstChild(node.nextSibling);
22013 if(this.lastChild == node){
22014 this.setLastChild(node.previousSibling);
22017 node.setOwnerTree(null);
22018 // clear any references from the node
22019 node.parentNode = null;
22020 node.previousSibling = null;
22021 node.nextSibling = null;
22022 this.fireEvent("remove", this.ownerTree, this, node);
22027 * Inserts the first node before the second node in this nodes childNodes collection.
22028 * @param {Node} node The node to insert
22029 * @param {Node} refNode The node to insert before (if null the node is appended)
22030 * @return {Node} The inserted node
22032 insertBefore : function(node, refNode){
22033 if(!refNode){ // like standard Dom, refNode can be null for append
22034 return this.appendChild(node);
22037 if(node == refNode){
22041 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
22044 var index = this.childNodes.indexOf(refNode);
22045 var oldParent = node.parentNode;
22046 var refIndex = index;
22048 // when moving internally, indexes will change after remove
22049 if(oldParent == this && this.childNodes.indexOf(node) < index){
22053 // it's a move, make sure we move it cleanly
22055 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
22058 oldParent.removeChild(node);
22061 this.setFirstChild(node);
22063 this.childNodes.splice(refIndex, 0, node);
22064 node.parentNode = this;
22065 var ps = this.childNodes[refIndex-1];
22067 node.previousSibling = ps;
22068 ps.nextSibling = node;
22070 node.previousSibling = null;
22072 node.nextSibling = refNode;
22073 refNode.previousSibling = node;
22074 node.setOwnerTree(this.getOwnerTree());
22075 this.fireEvent("insert", this.ownerTree, this, node, refNode);
22077 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
22083 * Returns the child node at the specified index.
22084 * @param {Number} index
22087 item : function(index){
22088 return this.childNodes[index];
22092 * Replaces one child node in this node with another.
22093 * @param {Node} newChild The replacement node
22094 * @param {Node} oldChild The node to replace
22095 * @return {Node} The replaced node
22097 replaceChild : function(newChild, oldChild){
22098 this.insertBefore(newChild, oldChild);
22099 this.removeChild(oldChild);
22104 * Returns the index of a child node
22105 * @param {Node} node
22106 * @return {Number} The index of the node or -1 if it was not found
22108 indexOf : function(child){
22109 return this.childNodes.indexOf(child);
22113 * Returns the tree this node is in.
22116 getOwnerTree : function(){
22117 // if it doesn't have one, look for one
22118 if(!this.ownerTree){
22122 this.ownerTree = p.ownerTree;
22128 return this.ownerTree;
22132 * Returns depth of this node (the root node has a depth of 0)
22135 getDepth : function(){
22138 while(p.parentNode){
22146 setOwnerTree : function(tree){
22147 // if it's move, we need to update everyone
22148 if(tree != this.ownerTree){
22149 if(this.ownerTree){
22150 this.ownerTree.unregisterNode(this);
22152 this.ownerTree = tree;
22153 var cs = this.childNodes;
22154 for(var i = 0, len = cs.length; i < len; i++) {
22155 cs[i].setOwnerTree(tree);
22158 tree.registerNode(this);
22164 * Returns the path for this node. The path can be used to expand or select this node programmatically.
22165 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
22166 * @return {String} The path
22168 getPath : function(attr){
22169 attr = attr || "id";
22170 var p = this.parentNode;
22171 var b = [this.attributes[attr]];
22173 b.unshift(p.attributes[attr]);
22176 var sep = this.getOwnerTree().pathSeparator;
22177 return sep + b.join(sep);
22181 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22182 * function call will be the scope provided or the current node. The arguments to the function
22183 * will be the args provided or the current node. If the function returns false at any point,
22184 * the bubble is stopped.
22185 * @param {Function} fn The function to call
22186 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22187 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22189 bubble : function(fn, scope, args){
22192 if(fn.call(scope || p, args || p) === false){
22200 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
22201 * function call will be the scope provided or the current node. The arguments to the function
22202 * will be the args provided or the current node. If the function returns false at any point,
22203 * the cascade is stopped on that branch.
22204 * @param {Function} fn The function to call
22205 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22206 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22208 cascade : function(fn, scope, args){
22209 if(fn.call(scope || this, args || this) !== false){
22210 var cs = this.childNodes;
22211 for(var i = 0, len = cs.length; i < len; i++) {
22212 cs[i].cascade(fn, scope, args);
22218 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
22219 * function call will be the scope provided or the current node. The arguments to the function
22220 * will be the args provided or the current node. If the function returns false at any point,
22221 * the iteration stops.
22222 * @param {Function} fn The function to call
22223 * @param {Object} scope (optional) The scope of the function (defaults to current node)
22224 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
22226 eachChild : function(fn, scope, args){
22227 var cs = this.childNodes;
22228 for(var i = 0, len = cs.length; i < len; i++) {
22229 if(fn.call(scope || this, args || cs[i]) === false){
22236 * Finds the first child that has the attribute with the specified value.
22237 * @param {String} attribute The attribute name
22238 * @param {Mixed} value The value to search for
22239 * @return {Node} The found child or null if none was found
22241 findChild : function(attribute, value){
22242 var cs = this.childNodes;
22243 for(var i = 0, len = cs.length; i < len; i++) {
22244 if(cs[i].attributes[attribute] == value){
22252 * Finds the first child by a custom function. The child matches if the function passed
22254 * @param {Function} fn
22255 * @param {Object} scope (optional)
22256 * @return {Node} The found child or null if none was found
22258 findChildBy : function(fn, scope){
22259 var cs = this.childNodes;
22260 for(var i = 0, len = cs.length; i < len; i++) {
22261 if(fn.call(scope||cs[i], cs[i]) === true){
22269 * Sorts this nodes children using the supplied sort function
22270 * @param {Function} fn
22271 * @param {Object} scope (optional)
22273 sort : function(fn, scope){
22274 var cs = this.childNodes;
22275 var len = cs.length;
22277 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
22279 for(var i = 0; i < len; i++){
22281 n.previousSibling = cs[i-1];
22282 n.nextSibling = cs[i+1];
22284 this.setFirstChild(n);
22287 this.setLastChild(n);
22294 * Returns true if this node is an ancestor (at any point) of the passed node.
22295 * @param {Node} node
22296 * @return {Boolean}
22298 contains : function(node){
22299 return node.isAncestor(this);
22303 * Returns true if the passed node is an ancestor (at any point) of this node.
22304 * @param {Node} node
22305 * @return {Boolean}
22307 isAncestor : function(node){
22308 var p = this.parentNode;
22318 toString : function(){
22319 return "[Node"+(this.id?" "+this.id:"")+"]";
22323 * Ext JS Library 1.1.1
22324 * Copyright(c) 2006-2007, Ext JS, LLC.
22326 * Originally Released Under LGPL - original licence link has changed is not relivant.
22329 * <script type="text/javascript">
22334 * @class Roo.ComponentMgr
22335 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
22338 Roo.ComponentMgr = function(){
22339 var all = new Roo.util.MixedCollection();
22343 * Registers a component.
22344 * @param {Roo.Component} c The component
22346 register : function(c){
22351 * Unregisters a component.
22352 * @param {Roo.Component} c The component
22354 unregister : function(c){
22359 * Returns a component by id
22360 * @param {String} id The component id
22362 get : function(id){
22363 return all.get(id);
22367 * Registers a function that will be called when a specified component is added to ComponentMgr
22368 * @param {String} id The component id
22369 * @param {Funtction} fn The callback function
22370 * @param {Object} scope The scope of the callback
22372 onAvailable : function(id, fn, scope){
22373 all.on("add", function(index, o){
22375 fn.call(scope || o, o);
22376 all.un("add", fn, scope);
22383 * Ext JS Library 1.1.1
22384 * Copyright(c) 2006-2007, Ext JS, LLC.
22386 * Originally Released Under LGPL - original licence link has changed is not relivant.
22389 * <script type="text/javascript">
22393 * @class Roo.Component
22394 * @extends Roo.util.Observable
22395 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
22396 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
22397 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
22398 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
22399 * All visual components (widgets) that require rendering into a layout should subclass Component.
22401 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
22402 * 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
22403 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
22405 Roo.Component = function(config){
22406 config = config || {};
22407 if(config.tagName || config.dom || typeof config == "string"){ // element object
22408 config = {el: config, id: config.id || config};
22410 this.initialConfig = config;
22412 Roo.apply(this, config);
22416 * Fires after the component is disabled.
22417 * @param {Roo.Component} this
22422 * Fires after the component is enabled.
22423 * @param {Roo.Component} this
22427 * @event beforeshow
22428 * Fires before the component is shown. Return false to stop the show.
22429 * @param {Roo.Component} this
22434 * Fires after the component is shown.
22435 * @param {Roo.Component} this
22439 * @event beforehide
22440 * Fires before the component is hidden. Return false to stop the hide.
22441 * @param {Roo.Component} this
22446 * Fires after the component is hidden.
22447 * @param {Roo.Component} this
22451 * @event beforerender
22452 * Fires before the component is rendered. Return false to stop the render.
22453 * @param {Roo.Component} this
22455 beforerender : true,
22458 * Fires after the component is rendered.
22459 * @param {Roo.Component} this
22463 * @event beforedestroy
22464 * Fires before the component is destroyed. Return false to stop the destroy.
22465 * @param {Roo.Component} this
22467 beforedestroy : true,
22470 * Fires after the component is destroyed.
22471 * @param {Roo.Component} this
22476 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
22478 Roo.ComponentMgr.register(this);
22479 Roo.Component.superclass.constructor.call(this);
22480 this.initComponent();
22481 if(this.renderTo){ // not supported by all components yet. use at your own risk!
22482 this.render(this.renderTo);
22483 delete this.renderTo;
22488 Roo.Component.AUTO_ID = 1000;
22490 Roo.extend(Roo.Component, Roo.util.Observable, {
22492 * @scope Roo.Component.prototype
22494 * true if this component is hidden. Read-only.
22499 * true if this component is disabled. Read-only.
22504 * true if this component has been rendered. Read-only.
22508 /** @cfg {String} disableClass
22509 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
22511 disabledClass : "x-item-disabled",
22512 /** @cfg {Boolean} allowDomMove
22513 * Whether the component can move the Dom node when rendering (defaults to true).
22515 allowDomMove : true,
22516 /** @cfg {String} hideMode
22517 * How this component should hidden. Supported values are
22518 * "visibility" (css visibility), "offsets" (negative offset position) and
22519 * "display" (css display) - defaults to "display".
22521 hideMode: 'display',
22524 ctype : "Roo.Component",
22527 * @cfg {String} actionMode
22528 * which property holds the element that used for hide() / show() / disable() / enable()
22534 getActionEl : function(){
22535 return this[this.actionMode];
22538 initComponent : Roo.emptyFn,
22540 * If this is a lazy rendering component, render it to its container element.
22541 * @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.
22543 render : function(container, position){
22544 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
22545 if(!container && this.el){
22546 this.el = Roo.get(this.el);
22547 container = this.el.dom.parentNode;
22548 this.allowDomMove = false;
22550 this.container = Roo.get(container);
22551 this.rendered = true;
22552 if(position !== undefined){
22553 if(typeof position == 'number'){
22554 position = this.container.dom.childNodes[position];
22556 position = Roo.getDom(position);
22559 this.onRender(this.container, position || null);
22561 this.el.addClass(this.cls);
22565 this.el.applyStyles(this.style);
22568 this.fireEvent("render", this);
22569 this.afterRender(this.container);
22581 // default function is not really useful
22582 onRender : function(ct, position){
22584 this.el = Roo.get(this.el);
22585 if(this.allowDomMove !== false){
22586 ct.dom.insertBefore(this.el.dom, position);
22592 getAutoCreate : function(){
22593 var cfg = typeof this.autoCreate == "object" ?
22594 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
22595 if(this.id && !cfg.id){
22602 afterRender : Roo.emptyFn,
22605 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
22606 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
22608 destroy : function(){
22609 if(this.fireEvent("beforedestroy", this) !== false){
22610 this.purgeListeners();
22611 this.beforeDestroy();
22613 this.el.removeAllListeners();
22615 if(this.actionMode == "container"){
22616 this.container.remove();
22620 Roo.ComponentMgr.unregister(this);
22621 this.fireEvent("destroy", this);
22626 beforeDestroy : function(){
22631 onDestroy : function(){
22636 * Returns the underlying {@link Roo.Element}.
22637 * @return {Roo.Element} The element
22639 getEl : function(){
22644 * Returns the id of this component.
22647 getId : function(){
22652 * Try to focus this component.
22653 * @param {Boolean} selectText True to also select the text in this component (if applicable)
22654 * @return {Roo.Component} this
22656 focus : function(selectText){
22659 if(selectText === true){
22660 this.el.dom.select();
22675 * Disable this component.
22676 * @return {Roo.Component} this
22678 disable : function(){
22682 this.disabled = true;
22683 this.fireEvent("disable", this);
22688 onDisable : function(){
22689 this.getActionEl().addClass(this.disabledClass);
22690 this.el.dom.disabled = true;
22694 * Enable this component.
22695 * @return {Roo.Component} this
22697 enable : function(){
22701 this.disabled = false;
22702 this.fireEvent("enable", this);
22707 onEnable : function(){
22708 this.getActionEl().removeClass(this.disabledClass);
22709 this.el.dom.disabled = false;
22713 * Convenience function for setting disabled/enabled by boolean.
22714 * @param {Boolean} disabled
22716 setDisabled : function(disabled){
22717 this[disabled ? "disable" : "enable"]();
22721 * Show this component.
22722 * @return {Roo.Component} this
22725 if(this.fireEvent("beforeshow", this) !== false){
22726 this.hidden = false;
22730 this.fireEvent("show", this);
22736 onShow : function(){
22737 var ae = this.getActionEl();
22738 if(this.hideMode == 'visibility'){
22739 ae.dom.style.visibility = "visible";
22740 }else if(this.hideMode == 'offsets'){
22741 ae.removeClass('x-hidden');
22743 ae.dom.style.display = "";
22748 * Hide this component.
22749 * @return {Roo.Component} this
22752 if(this.fireEvent("beforehide", this) !== false){
22753 this.hidden = true;
22757 this.fireEvent("hide", this);
22763 onHide : function(){
22764 var ae = this.getActionEl();
22765 if(this.hideMode == 'visibility'){
22766 ae.dom.style.visibility = "hidden";
22767 }else if(this.hideMode == 'offsets'){
22768 ae.addClass('x-hidden');
22770 ae.dom.style.display = "none";
22775 * Convenience function to hide or show this component by boolean.
22776 * @param {Boolean} visible True to show, false to hide
22777 * @return {Roo.Component} this
22779 setVisible: function(visible){
22789 * Returns true if this component is visible.
22791 isVisible : function(){
22792 return this.getActionEl().isVisible();
22795 cloneConfig : function(overrides){
22796 overrides = overrides || {};
22797 var id = overrides.id || Roo.id();
22798 var cfg = Roo.applyIf(overrides, this.initialConfig);
22799 cfg.id = id; // prevent dup id
22800 return new this.constructor(cfg);
22804 * Ext JS Library 1.1.1
22805 * Copyright(c) 2006-2007, Ext JS, LLC.
22807 * Originally Released Under LGPL - original licence link has changed is not relivant.
22810 * <script type="text/javascript">
22815 * @extends Roo.Element
22816 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
22817 * automatic maintaining of shadow/shim positions.
22818 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
22819 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
22820 * you can pass a string with a CSS class name. False turns off the shadow.
22821 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
22822 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
22823 * @cfg {String} cls CSS class to add to the element
22824 * @cfg {Number} zindex Starting z-index (defaults to 11000)
22825 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
22827 * @param {Object} config An object with config options.
22828 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
22831 Roo.Layer = function(config, existingEl){
22832 config = config || {};
22833 var dh = Roo.DomHelper;
22834 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
22836 this.dom = Roo.getDom(existingEl);
22839 var o = config.dh || {tag: "div", cls: "x-layer"};
22840 this.dom = dh.append(pel, o);
22843 this.addClass(config.cls);
22845 this.constrain = config.constrain !== false;
22846 this.visibilityMode = Roo.Element.VISIBILITY;
22848 this.id = this.dom.id = config.id;
22850 this.id = Roo.id(this.dom);
22852 this.zindex = config.zindex || this.getZIndex();
22853 this.position("absolute", this.zindex);
22855 this.shadowOffset = config.shadowOffset || 4;
22856 this.shadow = new Roo.Shadow({
22857 offset : this.shadowOffset,
22858 mode : config.shadow
22861 this.shadowOffset = 0;
22863 this.useShim = config.shim !== false && Roo.useShims;
22864 this.useDisplay = config.useDisplay;
22868 var supr = Roo.Element.prototype;
22870 // shims are shared among layer to keep from having 100 iframes
22873 Roo.extend(Roo.Layer, Roo.Element, {
22875 getZIndex : function(){
22876 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
22879 getShim : function(){
22886 var shim = shims.shift();
22888 shim = this.createShim();
22889 shim.enableDisplayMode('block');
22890 shim.dom.style.display = 'none';
22891 shim.dom.style.visibility = 'visible';
22893 var pn = this.dom.parentNode;
22894 if(shim.dom.parentNode != pn){
22895 pn.insertBefore(shim.dom, this.dom);
22897 shim.setStyle('z-index', this.getZIndex()-2);
22902 hideShim : function(){
22904 this.shim.setDisplayed(false);
22905 shims.push(this.shim);
22910 disableShadow : function(){
22912 this.shadowDisabled = true;
22913 this.shadow.hide();
22914 this.lastShadowOffset = this.shadowOffset;
22915 this.shadowOffset = 0;
22919 enableShadow : function(show){
22921 this.shadowDisabled = false;
22922 this.shadowOffset = this.lastShadowOffset;
22923 delete this.lastShadowOffset;
22931 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
22932 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
22933 sync : function(doShow){
22934 var sw = this.shadow;
22935 if(!this.updating && this.isVisible() && (sw || this.useShim)){
22936 var sh = this.getShim();
22938 var w = this.getWidth(),
22939 h = this.getHeight();
22941 var l = this.getLeft(true),
22942 t = this.getTop(true);
22944 if(sw && !this.shadowDisabled){
22945 if(doShow && !sw.isVisible()){
22948 sw.realign(l, t, w, h);
22954 // fit the shim behind the shadow, so it is shimmed too
22955 var a = sw.adjusts, s = sh.dom.style;
22956 s.left = (Math.min(l, l+a.l))+"px";
22957 s.top = (Math.min(t, t+a.t))+"px";
22958 s.width = (w+a.w)+"px";
22959 s.height = (h+a.h)+"px";
22966 sh.setLeftTop(l, t);
22973 destroy : function(){
22976 this.shadow.hide();
22978 this.removeAllListeners();
22979 var pn = this.dom.parentNode;
22981 pn.removeChild(this.dom);
22983 Roo.Element.uncache(this.id);
22986 remove : function(){
22991 beginUpdate : function(){
22992 this.updating = true;
22996 endUpdate : function(){
22997 this.updating = false;
23002 hideUnders : function(negOffset){
23004 this.shadow.hide();
23010 constrainXY : function(){
23011 if(this.constrain){
23012 var vw = Roo.lib.Dom.getViewWidth(),
23013 vh = Roo.lib.Dom.getViewHeight();
23014 var s = Roo.get(document).getScroll();
23016 var xy = this.getXY();
23017 var x = xy[0], y = xy[1];
23018 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23019 // only move it if it needs it
23021 // first validate right/bottom
23022 if((x + w) > vw+s.left){
23023 x = vw - w - this.shadowOffset;
23026 if((y + h) > vh+s.top){
23027 y = vh - h - this.shadowOffset;
23030 // then make sure top/left isn't negative
23041 var ay = this.avoidY;
23042 if(y <= ay && (y+h) >= ay){
23048 supr.setXY.call(this, xy);
23054 isVisible : function(){
23055 return this.visible;
23059 showAction : function(){
23060 this.visible = true; // track visibility to prevent getStyle calls
23061 if(this.useDisplay === true){
23062 this.setDisplayed("");
23063 }else if(this.lastXY){
23064 supr.setXY.call(this, this.lastXY);
23065 }else if(this.lastLT){
23066 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23071 hideAction : function(){
23072 this.visible = false;
23073 if(this.useDisplay === true){
23074 this.setDisplayed(false);
23076 this.setLeftTop(-10000,-10000);
23080 // overridden Element method
23081 setVisible : function(v, a, d, c, e){
23086 var cb = function(){
23091 }.createDelegate(this);
23092 supr.setVisible.call(this, true, true, d, cb, e);
23095 this.hideUnders(true);
23104 }.createDelegate(this);
23106 supr.setVisible.call(this, v, a, d, cb, e);
23115 storeXY : function(xy){
23116 delete this.lastLT;
23120 storeLeftTop : function(left, top){
23121 delete this.lastXY;
23122 this.lastLT = [left, top];
23126 beforeFx : function(){
23127 this.beforeAction();
23128 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23132 afterFx : function(){
23133 Roo.Layer.superclass.afterFx.apply(this, arguments);
23134 this.sync(this.isVisible());
23138 beforeAction : function(){
23139 if(!this.updating && this.shadow){
23140 this.shadow.hide();
23144 // overridden Element method
23145 setLeft : function(left){
23146 this.storeLeftTop(left, this.getTop(true));
23147 supr.setLeft.apply(this, arguments);
23151 setTop : function(top){
23152 this.storeLeftTop(this.getLeft(true), top);
23153 supr.setTop.apply(this, arguments);
23157 setLeftTop : function(left, top){
23158 this.storeLeftTop(left, top);
23159 supr.setLeftTop.apply(this, arguments);
23163 setXY : function(xy, a, d, c, e){
23165 this.beforeAction();
23167 var cb = this.createCB(c);
23168 supr.setXY.call(this, xy, a, d, cb, e);
23175 createCB : function(c){
23186 // overridden Element method
23187 setX : function(x, a, d, c, e){
23188 this.setXY([x, this.getY()], a, d, c, e);
23191 // overridden Element method
23192 setY : function(y, a, d, c, e){
23193 this.setXY([this.getX(), y], a, d, c, e);
23196 // overridden Element method
23197 setSize : function(w, h, a, d, c, e){
23198 this.beforeAction();
23199 var cb = this.createCB(c);
23200 supr.setSize.call(this, w, h, a, d, cb, e);
23206 // overridden Element method
23207 setWidth : function(w, a, d, c, e){
23208 this.beforeAction();
23209 var cb = this.createCB(c);
23210 supr.setWidth.call(this, w, a, d, cb, e);
23216 // overridden Element method
23217 setHeight : function(h, a, d, c, e){
23218 this.beforeAction();
23219 var cb = this.createCB(c);
23220 supr.setHeight.call(this, h, a, d, cb, e);
23226 // overridden Element method
23227 setBounds : function(x, y, w, h, a, d, c, e){
23228 this.beforeAction();
23229 var cb = this.createCB(c);
23231 this.storeXY([x, y]);
23232 supr.setXY.call(this, [x, y]);
23233 supr.setSize.call(this, w, h, a, d, cb, e);
23236 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
23242 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
23243 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
23244 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
23245 * @param {Number} zindex The new z-index to set
23246 * @return {this} The Layer
23248 setZIndex : function(zindex){
23249 this.zindex = zindex;
23250 this.setStyle("z-index", zindex + 2);
23252 this.shadow.setZIndex(zindex + 1);
23255 this.shim.setStyle("z-index", zindex);
23261 * Ext JS Library 1.1.1
23262 * Copyright(c) 2006-2007, Ext JS, LLC.
23264 * Originally Released Under LGPL - original licence link has changed is not relivant.
23267 * <script type="text/javascript">
23272 * @class Roo.Shadow
23273 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
23274 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
23275 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
23277 * Create a new Shadow
23278 * @param {Object} config The config object
23280 Roo.Shadow = function(config){
23281 Roo.apply(this, config);
23282 if(typeof this.mode != "string"){
23283 this.mode = this.defaultMode;
23285 var o = this.offset, a = {h: 0};
23286 var rad = Math.floor(this.offset/2);
23287 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
23293 a.l -= this.offset + rad;
23294 a.t -= this.offset + rad;
23305 a.l -= (this.offset - rad);
23306 a.t -= this.offset + rad;
23308 a.w -= (this.offset - rad)*2;
23319 a.l -= (this.offset - rad);
23320 a.t -= (this.offset - rad);
23322 a.w -= (this.offset + rad + 1);
23323 a.h -= (this.offset + rad);
23332 Roo.Shadow.prototype = {
23334 * @cfg {String} mode
23335 * The shadow display mode. Supports the following options:<br />
23336 * sides: Shadow displays on both sides and bottom only<br />
23337 * frame: Shadow displays equally on all four sides<br />
23338 * drop: Traditional bottom-right drop shadow (default)
23341 * @cfg {String} offset
23342 * The number of pixels to offset the shadow from the element (defaults to 4)
23347 defaultMode: "drop",
23350 * Displays the shadow under the target element
23351 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
23353 show : function(target){
23354 target = Roo.get(target);
23356 this.el = Roo.Shadow.Pool.pull();
23357 if(this.el.dom.nextSibling != target.dom){
23358 this.el.insertBefore(target);
23361 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
23363 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
23366 target.getLeft(true),
23367 target.getTop(true),
23371 this.el.dom.style.display = "block";
23375 * Returns true if the shadow is visible, else false
23377 isVisible : function(){
23378 return this.el ? true : false;
23382 * Direct alignment when values are already available. Show must be called at least once before
23383 * calling this method to ensure it is initialized.
23384 * @param {Number} left The target element left position
23385 * @param {Number} top The target element top position
23386 * @param {Number} width The target element width
23387 * @param {Number} height The target element height
23389 realign : function(l, t, w, h){
23393 var a = this.adjusts, d = this.el.dom, s = d.style;
23395 s.left = (l+a.l)+"px";
23396 s.top = (t+a.t)+"px";
23397 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
23399 if(s.width != sws || s.height != shs){
23403 var cn = d.childNodes;
23404 var sww = Math.max(0, (sw-12))+"px";
23405 cn[0].childNodes[1].style.width = sww;
23406 cn[1].childNodes[1].style.width = sww;
23407 cn[2].childNodes[1].style.width = sww;
23408 cn[1].style.height = Math.max(0, (sh-12))+"px";
23414 * Hides this shadow
23418 this.el.dom.style.display = "none";
23419 Roo.Shadow.Pool.push(this.el);
23425 * Adjust the z-index of this shadow
23426 * @param {Number} zindex The new z-index
23428 setZIndex : function(z){
23431 this.el.setStyle("z-index", z);
23436 // Private utility class that manages the internal Shadow cache
23437 Roo.Shadow.Pool = function(){
23439 var markup = Roo.isIE ?
23440 '<div class="x-ie-shadow"></div>' :
23441 '<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>';
23444 var sh = p.shift();
23446 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
23447 sh.autoBoxAdjust = false;
23452 push : function(sh){
23458 * Ext JS Library 1.1.1
23459 * Copyright(c) 2006-2007, Ext JS, LLC.
23461 * Originally Released Under LGPL - original licence link has changed is not relivant.
23464 * <script type="text/javascript">
23468 * @class Roo.BoxComponent
23469 * @extends Roo.Component
23470 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
23471 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
23472 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
23473 * layout containers.
23475 * @param {Roo.Element/String/Object} config The configuration options.
23477 Roo.BoxComponent = function(config){
23478 Roo.Component.call(this, config);
23482 * Fires after the component is resized.
23483 * @param {Roo.Component} this
23484 * @param {Number} adjWidth The box-adjusted width that was set
23485 * @param {Number} adjHeight The box-adjusted height that was set
23486 * @param {Number} rawWidth The width that was originally specified
23487 * @param {Number} rawHeight The height that was originally specified
23492 * Fires after the component is moved.
23493 * @param {Roo.Component} this
23494 * @param {Number} x The new x position
23495 * @param {Number} y The new y position
23501 Roo.extend(Roo.BoxComponent, Roo.Component, {
23502 // private, set in afterRender to signify that the component has been rendered
23504 // private, used to defer height settings to subclasses
23505 deferHeight: false,
23506 /** @cfg {Number} width
23507 * width (optional) size of component
23509 /** @cfg {Number} height
23510 * height (optional) size of component
23514 * Sets the width and height of the component. This method fires the resize event. This method can accept
23515 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
23516 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
23517 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
23518 * @return {Roo.BoxComponent} this
23520 setSize : function(w, h){
23521 // support for standard size objects
23522 if(typeof w == 'object'){
23527 if(!this.boxReady){
23533 // prevent recalcs when not needed
23534 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
23537 this.lastSize = {width: w, height: h};
23539 var adj = this.adjustSize(w, h);
23540 var aw = adj.width, ah = adj.height;
23541 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
23542 var rz = this.getResizeEl();
23543 if(!this.deferHeight && aw !== undefined && ah !== undefined){
23544 rz.setSize(aw, ah);
23545 }else if(!this.deferHeight && ah !== undefined){
23547 }else if(aw !== undefined){
23550 this.onResize(aw, ah, w, h);
23551 this.fireEvent('resize', this, aw, ah, w, h);
23557 * Gets the current size of the component's underlying element.
23558 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
23560 getSize : function(){
23561 return this.el.getSize();
23565 * Gets the current XY position of the component's underlying element.
23566 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23567 * @return {Array} The XY position of the element (e.g., [100, 200])
23569 getPosition : function(local){
23570 if(local === true){
23571 return [this.el.getLeft(true), this.el.getTop(true)];
23573 return this.xy || this.el.getXY();
23577 * Gets the current box measurements of the component's underlying element.
23578 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
23579 * @returns {Object} box An object in the format {x, y, width, height}
23581 getBox : function(local){
23582 var s = this.el.getSize();
23584 s.x = this.el.getLeft(true);
23585 s.y = this.el.getTop(true);
23587 var xy = this.xy || this.el.getXY();
23595 * Sets the current box measurements of the component's underlying element.
23596 * @param {Object} box An object in the format {x, y, width, height}
23597 * @returns {Roo.BoxComponent} this
23599 updateBox : function(box){
23600 this.setSize(box.width, box.height);
23601 this.setPagePosition(box.x, box.y);
23606 getResizeEl : function(){
23607 return this.resizeEl || this.el;
23611 getPositionEl : function(){
23612 return this.positionEl || this.el;
23616 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
23617 * This method fires the move event.
23618 * @param {Number} left The new left
23619 * @param {Number} top The new top
23620 * @returns {Roo.BoxComponent} this
23622 setPosition : function(x, y){
23625 if(!this.boxReady){
23628 var adj = this.adjustPosition(x, y);
23629 var ax = adj.x, ay = adj.y;
23631 var el = this.getPositionEl();
23632 if(ax !== undefined || ay !== undefined){
23633 if(ax !== undefined && ay !== undefined){
23634 el.setLeftTop(ax, ay);
23635 }else if(ax !== undefined){
23637 }else if(ay !== undefined){
23640 this.onPosition(ax, ay);
23641 this.fireEvent('move', this, ax, ay);
23647 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
23648 * This method fires the move event.
23649 * @param {Number} x The new x position
23650 * @param {Number} y The new y position
23651 * @returns {Roo.BoxComponent} this
23653 setPagePosition : function(x, y){
23656 if(!this.boxReady){
23659 if(x === undefined || y === undefined){ // cannot translate undefined points
23662 var p = this.el.translatePoints(x, y);
23663 this.setPosition(p.left, p.top);
23668 onRender : function(ct, position){
23669 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
23671 this.resizeEl = Roo.get(this.resizeEl);
23673 if(this.positionEl){
23674 this.positionEl = Roo.get(this.positionEl);
23679 afterRender : function(){
23680 Roo.BoxComponent.superclass.afterRender.call(this);
23681 this.boxReady = true;
23682 this.setSize(this.width, this.height);
23683 if(this.x || this.y){
23684 this.setPosition(this.x, this.y);
23686 if(this.pageX || this.pageY){
23687 this.setPagePosition(this.pageX, this.pageY);
23692 * Force the component's size to recalculate based on the underlying element's current height and width.
23693 * @returns {Roo.BoxComponent} this
23695 syncSize : function(){
23696 delete this.lastSize;
23697 this.setSize(this.el.getWidth(), this.el.getHeight());
23702 * Called after the component is resized, this method is empty by default but can be implemented by any
23703 * subclass that needs to perform custom logic after a resize occurs.
23704 * @param {Number} adjWidth The box-adjusted width that was set
23705 * @param {Number} adjHeight The box-adjusted height that was set
23706 * @param {Number} rawWidth The width that was originally specified
23707 * @param {Number} rawHeight The height that was originally specified
23709 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
23714 * Called after the component is moved, this method is empty by default but can be implemented by any
23715 * subclass that needs to perform custom logic after a move occurs.
23716 * @param {Number} x The new x position
23717 * @param {Number} y The new y position
23719 onPosition : function(x, y){
23724 adjustSize : function(w, h){
23725 if(this.autoWidth){
23728 if(this.autoHeight){
23731 return {width : w, height: h};
23735 adjustPosition : function(x, y){
23736 return {x : x, y: y};
23740 * Ext JS Library 1.1.1
23741 * Copyright(c) 2006-2007, Ext JS, LLC.
23743 * Originally Released Under LGPL - original licence link has changed is not relivant.
23746 * <script type="text/javascript">
23751 * @class Roo.SplitBar
23752 * @extends Roo.util.Observable
23753 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
23757 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
23758 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
23759 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
23760 split.minSize = 100;
23761 split.maxSize = 600;
23762 split.animate = true;
23763 split.on('moved', splitterMoved);
23766 * Create a new SplitBar
23767 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
23768 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
23769 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23770 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
23771 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
23772 position of the SplitBar).
23774 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
23777 this.el = Roo.get(dragElement, true);
23778 this.el.dom.unselectable = "on";
23780 this.resizingEl = Roo.get(resizingElement, true);
23784 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
23785 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
23788 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
23791 * The minimum size of the resizing element. (Defaults to 0)
23797 * The maximum size of the resizing element. (Defaults to 2000)
23800 this.maxSize = 2000;
23803 * Whether to animate the transition to the new size
23806 this.animate = false;
23809 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
23812 this.useShim = false;
23817 if(!existingProxy){
23819 this.proxy = Roo.SplitBar.createProxy(this.orientation);
23821 this.proxy = Roo.get(existingProxy).dom;
23824 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
23827 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
23830 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
23833 this.dragSpecs = {};
23836 * @private The adapter to use to positon and resize elements
23838 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
23839 this.adapter.init(this);
23841 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23843 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
23844 this.el.addClass("x-splitbar-h");
23847 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
23848 this.el.addClass("x-splitbar-v");
23854 * Fires when the splitter is moved (alias for {@link #event-moved})
23855 * @param {Roo.SplitBar} this
23856 * @param {Number} newSize the new width or height
23861 * Fires when the splitter is moved
23862 * @param {Roo.SplitBar} this
23863 * @param {Number} newSize the new width or height
23867 * @event beforeresize
23868 * Fires before the splitter is dragged
23869 * @param {Roo.SplitBar} this
23871 "beforeresize" : true,
23873 "beforeapply" : true
23876 Roo.util.Observable.call(this);
23879 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
23880 onStartProxyDrag : function(x, y){
23881 this.fireEvent("beforeresize", this);
23883 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
23885 o.enableDisplayMode("block");
23886 // all splitbars share the same overlay
23887 Roo.SplitBar.prototype.overlay = o;
23889 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
23890 this.overlay.show();
23891 Roo.get(this.proxy).setDisplayed("block");
23892 var size = this.adapter.getElementSize(this);
23893 this.activeMinSize = this.getMinimumSize();;
23894 this.activeMaxSize = this.getMaximumSize();;
23895 var c1 = size - this.activeMinSize;
23896 var c2 = Math.max(this.activeMaxSize - size, 0);
23897 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23898 this.dd.resetConstraints();
23899 this.dd.setXConstraint(
23900 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
23901 this.placement == Roo.SplitBar.LEFT ? c2 : c1
23903 this.dd.setYConstraint(0, 0);
23905 this.dd.resetConstraints();
23906 this.dd.setXConstraint(0, 0);
23907 this.dd.setYConstraint(
23908 this.placement == Roo.SplitBar.TOP ? c1 : c2,
23909 this.placement == Roo.SplitBar.TOP ? c2 : c1
23912 this.dragSpecs.startSize = size;
23913 this.dragSpecs.startPoint = [x, y];
23914 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
23918 * @private Called after the drag operation by the DDProxy
23920 onEndProxyDrag : function(e){
23921 Roo.get(this.proxy).setDisplayed(false);
23922 var endPoint = Roo.lib.Event.getXY(e);
23924 this.overlay.hide();
23927 if(this.orientation == Roo.SplitBar.HORIZONTAL){
23928 newSize = this.dragSpecs.startSize +
23929 (this.placement == Roo.SplitBar.LEFT ?
23930 endPoint[0] - this.dragSpecs.startPoint[0] :
23931 this.dragSpecs.startPoint[0] - endPoint[0]
23934 newSize = this.dragSpecs.startSize +
23935 (this.placement == Roo.SplitBar.TOP ?
23936 endPoint[1] - this.dragSpecs.startPoint[1] :
23937 this.dragSpecs.startPoint[1] - endPoint[1]
23940 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
23941 if(newSize != this.dragSpecs.startSize){
23942 if(this.fireEvent('beforeapply', this, newSize) !== false){
23943 this.adapter.setElementSize(this, newSize);
23944 this.fireEvent("moved", this, newSize);
23945 this.fireEvent("resize", this, newSize);
23951 * Get the adapter this SplitBar uses
23952 * @return The adapter object
23954 getAdapter : function(){
23955 return this.adapter;
23959 * Set the adapter this SplitBar uses
23960 * @param {Object} adapter A SplitBar adapter object
23962 setAdapter : function(adapter){
23963 this.adapter = adapter;
23964 this.adapter.init(this);
23968 * Gets the minimum size for the resizing element
23969 * @return {Number} The minimum size
23971 getMinimumSize : function(){
23972 return this.minSize;
23976 * Sets the minimum size for the resizing element
23977 * @param {Number} minSize The minimum size
23979 setMinimumSize : function(minSize){
23980 this.minSize = minSize;
23984 * Gets the maximum size for the resizing element
23985 * @return {Number} The maximum size
23987 getMaximumSize : function(){
23988 return this.maxSize;
23992 * Sets the maximum size for the resizing element
23993 * @param {Number} maxSize The maximum size
23995 setMaximumSize : function(maxSize){
23996 this.maxSize = maxSize;
24000 * Sets the initialize size for the resizing element
24001 * @param {Number} size The initial size
24003 setCurrentSize : function(size){
24004 var oldAnimate = this.animate;
24005 this.animate = false;
24006 this.adapter.setElementSize(this, size);
24007 this.animate = oldAnimate;
24011 * Destroy this splitbar.
24012 * @param {Boolean} removeEl True to remove the element
24014 destroy : function(removeEl){
24016 this.shim.remove();
24019 this.proxy.parentNode.removeChild(this.proxy);
24027 * @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.
24029 Roo.SplitBar.createProxy = function(dir){
24030 var proxy = new Roo.Element(document.createElement("div"));
24031 proxy.unselectable();
24032 var cls = 'x-splitbar-proxy';
24033 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24034 document.body.appendChild(proxy.dom);
24039 * @class Roo.SplitBar.BasicLayoutAdapter
24040 * Default Adapter. It assumes the splitter and resizing element are not positioned
24041 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24043 Roo.SplitBar.BasicLayoutAdapter = function(){
24046 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24047 // do nothing for now
24048 init : function(s){
24052 * Called before drag operations to get the current size of the resizing element.
24053 * @param {Roo.SplitBar} s The SplitBar using this adapter
24055 getElementSize : function(s){
24056 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24057 return s.resizingEl.getWidth();
24059 return s.resizingEl.getHeight();
24064 * Called after drag operations to set the size of the resizing element.
24065 * @param {Roo.SplitBar} s The SplitBar using this adapter
24066 * @param {Number} newSize The new size to set
24067 * @param {Function} onComplete A function to be invoked when resizing is complete
24069 setElementSize : function(s, newSize, onComplete){
24070 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24072 s.resizingEl.setWidth(newSize);
24074 onComplete(s, newSize);
24077 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24082 s.resizingEl.setHeight(newSize);
24084 onComplete(s, newSize);
24087 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24094 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24095 * @extends Roo.SplitBar.BasicLayoutAdapter
24096 * Adapter that moves the splitter element to align with the resized sizing element.
24097 * Used with an absolute positioned SplitBar.
24098 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24099 * document.body, make sure you assign an id to the body element.
24101 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24102 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24103 this.container = Roo.get(container);
24106 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24107 init : function(s){
24108 this.basic.init(s);
24111 getElementSize : function(s){
24112 return this.basic.getElementSize(s);
24115 setElementSize : function(s, newSize, onComplete){
24116 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24119 moveSplitter : function(s){
24120 var yes = Roo.SplitBar;
24121 switch(s.placement){
24123 s.el.setX(s.resizingEl.getRight());
24126 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24129 s.el.setY(s.resizingEl.getBottom());
24132 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24139 * Orientation constant - Create a vertical SplitBar
24143 Roo.SplitBar.VERTICAL = 1;
24146 * Orientation constant - Create a horizontal SplitBar
24150 Roo.SplitBar.HORIZONTAL = 2;
24153 * Placement constant - The resizing element is to the left of the splitter element
24157 Roo.SplitBar.LEFT = 1;
24160 * Placement constant - The resizing element is to the right of the splitter element
24164 Roo.SplitBar.RIGHT = 2;
24167 * Placement constant - The resizing element is positioned above the splitter element
24171 Roo.SplitBar.TOP = 3;
24174 * Placement constant - The resizing element is positioned under splitter element
24178 Roo.SplitBar.BOTTOM = 4;
24181 * Ext JS Library 1.1.1
24182 * Copyright(c) 2006-2007, Ext JS, LLC.
24184 * Originally Released Under LGPL - original licence link has changed is not relivant.
24187 * <script type="text/javascript">
24192 * @extends Roo.util.Observable
24193 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24194 * This class also supports single and multi selection modes. <br>
24195 * Create a data model bound view:
24197 var store = new Roo.data.Store(...);
24199 var view = new Roo.View({
24201 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24203 singleSelect: true,
24204 selectedClass: "ydataview-selected",
24208 // listen for node click?
24209 view.on("click", function(vw, index, node, e){
24210 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24214 dataModel.load("foobar.xml");
24216 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24218 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24219 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24221 * Note: old style constructor is still suported (container, template, config)
24224 * Create a new View
24225 * @param {Object} config The config object
24228 Roo.View = function(config, depreciated_tpl, depreciated_config){
24230 if (typeof(depreciated_tpl) == 'undefined') {
24231 // new way.. - universal constructor.
24232 Roo.apply(this, config);
24233 this.el = Roo.get(this.el);
24236 this.el = Roo.get(config);
24237 this.tpl = depreciated_tpl;
24238 Roo.apply(this, depreciated_config);
24240 this.wrapEl = this.el.wrap().wrap();
24241 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24244 if(typeof(this.tpl) == "string"){
24245 this.tpl = new Roo.Template(this.tpl);
24247 // support xtype ctors..
24248 this.tpl = new Roo.factory(this.tpl, Roo);
24252 this.tpl.compile();
24260 * @event beforeclick
24261 * Fires before a click is processed. Returns false to cancel the default action.
24262 * @param {Roo.View} this
24263 * @param {Number} index The index of the target node
24264 * @param {HTMLElement} node The target node
24265 * @param {Roo.EventObject} e The raw event object
24267 "beforeclick" : true,
24270 * Fires when a template node is clicked.
24271 * @param {Roo.View} this
24272 * @param {Number} index The index of the target node
24273 * @param {HTMLElement} node The target node
24274 * @param {Roo.EventObject} e The raw event object
24279 * Fires when a template node is double clicked.
24280 * @param {Roo.View} this
24281 * @param {Number} index The index of the target node
24282 * @param {HTMLElement} node The target node
24283 * @param {Roo.EventObject} e The raw event object
24287 * @event contextmenu
24288 * Fires when a template node is right clicked.
24289 * @param {Roo.View} this
24290 * @param {Number} index The index of the target node
24291 * @param {HTMLElement} node The target node
24292 * @param {Roo.EventObject} e The raw event object
24294 "contextmenu" : true,
24296 * @event selectionchange
24297 * Fires when the selected nodes change.
24298 * @param {Roo.View} this
24299 * @param {Array} selections Array of the selected nodes
24301 "selectionchange" : true,
24304 * @event beforeselect
24305 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24306 * @param {Roo.View} this
24307 * @param {HTMLElement} node The node to be selected
24308 * @param {Array} selections Array of currently selected nodes
24310 "beforeselect" : true,
24312 * @event preparedata
24313 * Fires on every row to render, to allow you to change the data.
24314 * @param {Roo.View} this
24315 * @param {Object} data to be rendered (change this)
24317 "preparedata" : true
24325 "click": this.onClick,
24326 "dblclick": this.onDblClick,
24327 "contextmenu": this.onContextMenu,
24331 this.selections = [];
24333 this.cmp = new Roo.CompositeElementLite([]);
24335 this.store = Roo.factory(this.store, Roo.data);
24336 this.setStore(this.store, true);
24339 if ( this.footer && this.footer.xtype) {
24341 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24343 this.footer.dataSource = this.store
24344 this.footer.container = fctr;
24345 this.footer = Roo.factory(this.footer, Roo);
24346 fctr.insertFirst(this.el);
24348 // this is a bit insane - as the paging toolbar seems to detach the el..
24349 // dom.parentNode.parentNode.parentNode
24350 // they get detached?
24354 Roo.View.superclass.constructor.call(this);
24359 Roo.extend(Roo.View, Roo.util.Observable, {
24362 * @cfg {Roo.data.Store} store Data store to load data from.
24367 * @cfg {String|Roo.Element} el The container element.
24372 * @cfg {String|Roo.Template} tpl The template used by this View
24376 * @cfg {String} dataName the named area of the template to use as the data area
24377 * Works with domtemplates roo-name="name"
24381 * @cfg {String} selectedClass The css class to add to selected nodes
24383 selectedClass : "x-view-selected",
24385 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24390 * @cfg {String} text to display on mask (default Loading)
24394 * @cfg {Boolean} multiSelect Allow multiple selection
24396 multiSelect : false,
24398 * @cfg {Boolean} singleSelect Allow single selection
24400 singleSelect: false,
24403 * @cfg {Boolean} toggleSelect - selecting
24405 toggleSelect : false,
24408 * Returns the element this view is bound to.
24409 * @return {Roo.Element}
24411 getEl : function(){
24412 return this.wrapEl;
24418 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24420 refresh : function(){
24423 // if we are using something like 'domtemplate', then
24424 // the what gets used is:
24425 // t.applySubtemplate(NAME, data, wrapping data..)
24426 // the outer template then get' applied with
24427 // the store 'extra data'
24428 // and the body get's added to the
24429 // roo-name="data" node?
24430 // <span class='roo-tpl-{name}'></span> ?????
24434 this.clearSelections();
24435 this.el.update("");
24437 var records = this.store.getRange();
24438 if(records.length < 1) {
24440 // is this valid?? = should it render a template??
24442 this.el.update(this.emptyText);
24446 if (this.dataName) {
24447 this.el.update(t.apply(this.store.meta)); //????
24448 el = this.el.child('.roo-tpl-' + this.dataName);
24451 for(var i = 0, len = records.length; i < len; i++){
24452 var data = this.prepareData(records[i].data, i, records[i]);
24453 this.fireEvent("preparedata", this, data, i, records[i]);
24454 html[html.length] = Roo.util.Format.trim(
24456 t.applySubtemplate(this.dataName, data, this.store.meta) :
24463 el.update(html.join(""));
24464 this.nodes = el.dom.childNodes;
24465 this.updateIndexes(0);
24469 * Function to override to reformat the data that is sent to
24470 * the template for each node.
24471 * DEPRICATED - use the preparedata event handler.
24472 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24473 * a JSON object for an UpdateManager bound view).
24475 prepareData : function(data, index, record)
24477 this.fireEvent("preparedata", this, data, index, record);
24481 onUpdate : function(ds, record){
24482 this.clearSelections();
24483 var index = this.store.indexOf(record);
24484 var n = this.nodes[index];
24485 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24486 n.parentNode.removeChild(n);
24487 this.updateIndexes(index, index);
24493 onAdd : function(ds, records, index)
24495 this.clearSelections();
24496 if(this.nodes.length == 0){
24500 var n = this.nodes[index];
24501 for(var i = 0, len = records.length; i < len; i++){
24502 var d = this.prepareData(records[i].data, i, records[i]);
24504 this.tpl.insertBefore(n, d);
24507 this.tpl.append(this.el, d);
24510 this.updateIndexes(index);
24513 onRemove : function(ds, record, index){
24514 this.clearSelections();
24515 var el = this.dataName ?
24516 this.el.child('.roo-tpl-' + this.dataName) :
24518 el.dom.removeChild(this.nodes[index]);
24519 this.updateIndexes(index);
24523 * Refresh an individual node.
24524 * @param {Number} index
24526 refreshNode : function(index){
24527 this.onUpdate(this.store, this.store.getAt(index));
24530 updateIndexes : function(startIndex, endIndex){
24531 var ns = this.nodes;
24532 startIndex = startIndex || 0;
24533 endIndex = endIndex || ns.length - 1;
24534 for(var i = startIndex; i <= endIndex; i++){
24535 ns[i].nodeIndex = i;
24540 * Changes the data store this view uses and refresh the view.
24541 * @param {Store} store
24543 setStore : function(store, initial){
24544 if(!initial && this.store){
24545 this.store.un("datachanged", this.refresh);
24546 this.store.un("add", this.onAdd);
24547 this.store.un("remove", this.onRemove);
24548 this.store.un("update", this.onUpdate);
24549 this.store.un("clear", this.refresh);
24550 this.store.un("beforeload", this.onBeforeLoad);
24551 this.store.un("load", this.onLoad);
24552 this.store.un("loadexception", this.onLoad);
24556 store.on("datachanged", this.refresh, this);
24557 store.on("add", this.onAdd, this);
24558 store.on("remove", this.onRemove, this);
24559 store.on("update", this.onUpdate, this);
24560 store.on("clear", this.refresh, this);
24561 store.on("beforeload", this.onBeforeLoad, this);
24562 store.on("load", this.onLoad, this);
24563 store.on("loadexception", this.onLoad, this);
24571 * onbeforeLoad - masks the loading area.
24574 onBeforeLoad : function()
24576 this.el.update("");
24577 this.el.mask(this.mask ? this.mask : "Loading" );
24579 onLoad : function ()
24586 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
24587 * @param {HTMLElement} node
24588 * @return {HTMLElement} The template node
24590 findItemFromChild : function(node){
24591 var el = this.dataName ?
24592 this.el.child('.roo-tpl-' + this.dataName,true) :
24595 if(!node || node.parentNode == el){
24598 var p = node.parentNode;
24599 while(p && p != el){
24600 if(p.parentNode == el){
24609 onClick : function(e){
24610 var item = this.findItemFromChild(e.getTarget());
24612 var index = this.indexOf(item);
24613 if(this.onItemClick(item, index, e) !== false){
24614 this.fireEvent("click", this, index, item, e);
24617 this.clearSelections();
24622 onContextMenu : function(e){
24623 var item = this.findItemFromChild(e.getTarget());
24625 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
24630 onDblClick : function(e){
24631 var item = this.findItemFromChild(e.getTarget());
24633 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
24637 onItemClick : function(item, index, e)
24639 if(this.fireEvent("beforeclick", this, index, item, e) === false){
24642 if (this.toggleSelect) {
24643 var m = this.isSelected(item) ? 'unselect' : 'select';
24646 _t[m](item, true, false);
24649 if(this.multiSelect || this.singleSelect){
24650 if(this.multiSelect && e.shiftKey && this.lastSelection){
24651 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
24653 this.select(item, this.multiSelect && e.ctrlKey);
24654 this.lastSelection = item;
24656 e.preventDefault();
24662 * Get the number of selected nodes.
24665 getSelectionCount : function(){
24666 return this.selections.length;
24670 * Get the currently selected nodes.
24671 * @return {Array} An array of HTMLElements
24673 getSelectedNodes : function(){
24674 return this.selections;
24678 * Get the indexes of the selected nodes.
24681 getSelectedIndexes : function(){
24682 var indexes = [], s = this.selections;
24683 for(var i = 0, len = s.length; i < len; i++){
24684 indexes.push(s[i].nodeIndex);
24690 * Clear all selections
24691 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
24693 clearSelections : function(suppressEvent){
24694 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
24695 this.cmp.elements = this.selections;
24696 this.cmp.removeClass(this.selectedClass);
24697 this.selections = [];
24698 if(!suppressEvent){
24699 this.fireEvent("selectionchange", this, this.selections);
24705 * Returns true if the passed node is selected
24706 * @param {HTMLElement/Number} node The node or node index
24707 * @return {Boolean}
24709 isSelected : function(node){
24710 var s = this.selections;
24714 node = this.getNode(node);
24715 return s.indexOf(node) !== -1;
24720 * @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
24721 * @param {Boolean} keepExisting (optional) true to keep existing selections
24722 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24724 select : function(nodeInfo, keepExisting, suppressEvent){
24725 if(nodeInfo instanceof Array){
24727 this.clearSelections(true);
24729 for(var i = 0, len = nodeInfo.length; i < len; i++){
24730 this.select(nodeInfo[i], true, true);
24734 var node = this.getNode(nodeInfo);
24735 if(!node || this.isSelected(node)){
24736 return; // already selected.
24739 this.clearSelections(true);
24741 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
24742 Roo.fly(node).addClass(this.selectedClass);
24743 this.selections.push(node);
24744 if(!suppressEvent){
24745 this.fireEvent("selectionchange", this, this.selections);
24753 * @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
24754 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
24755 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
24757 unselect : function(nodeInfo, keepExisting, suppressEvent)
24759 if(nodeInfo instanceof Array){
24760 Roo.each(this.selections, function(s) {
24761 this.unselect(s, nodeInfo);
24765 var node = this.getNode(nodeInfo);
24766 if(!node || !this.isSelected(node)){
24767 Roo.log("not selected");
24768 return; // not selected.
24772 Roo.each(this.selections, function(s) {
24774 Roo.fly(node).removeClass(this.selectedClass);
24781 this.selections= ns;
24782 this.fireEvent("selectionchange", this, this.selections);
24786 * Gets a template node.
24787 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24788 * @return {HTMLElement} The node or null if it wasn't found
24790 getNode : function(nodeInfo){
24791 if(typeof nodeInfo == "string"){
24792 return document.getElementById(nodeInfo);
24793 }else if(typeof nodeInfo == "number"){
24794 return this.nodes[nodeInfo];
24800 * Gets a range template nodes.
24801 * @param {Number} startIndex
24802 * @param {Number} endIndex
24803 * @return {Array} An array of nodes
24805 getNodes : function(start, end){
24806 var ns = this.nodes;
24807 start = start || 0;
24808 end = typeof end == "undefined" ? ns.length - 1 : end;
24811 for(var i = start; i <= end; i++){
24815 for(var i = start; i >= end; i--){
24823 * Finds the index of the passed node
24824 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
24825 * @return {Number} The index of the node or -1
24827 indexOf : function(node){
24828 node = this.getNode(node);
24829 if(typeof node.nodeIndex == "number"){
24830 return node.nodeIndex;
24832 var ns = this.nodes;
24833 for(var i = 0, len = ns.length; i < len; i++){
24843 * Ext JS Library 1.1.1
24844 * Copyright(c) 2006-2007, Ext JS, LLC.
24846 * Originally Released Under LGPL - original licence link has changed is not relivant.
24849 * <script type="text/javascript">
24853 * @class Roo.JsonView
24854 * @extends Roo.View
24855 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
24857 var view = new Roo.JsonView({
24858 container: "my-element",
24859 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
24864 // listen for node click?
24865 view.on("click", function(vw, index, node, e){
24866 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24869 // direct load of JSON data
24870 view.load("foobar.php");
24872 // Example from my blog list
24873 var tpl = new Roo.Template(
24874 '<div class="entry">' +
24875 '<a class="entry-title" href="{link}">{title}</a>' +
24876 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
24877 "</div><hr />"
24880 var moreView = new Roo.JsonView({
24881 container : "entry-list",
24885 moreView.on("beforerender", this.sortEntries, this);
24887 url: "/blog/get-posts.php",
24888 params: "allposts=true",
24889 text: "Loading Blog Entries..."
24893 * Note: old code is supported with arguments : (container, template, config)
24897 * Create a new JsonView
24899 * @param {Object} config The config object
24902 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
24905 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
24907 var um = this.el.getUpdateManager();
24908 um.setRenderer(this);
24909 um.on("update", this.onLoad, this);
24910 um.on("failure", this.onLoadException, this);
24913 * @event beforerender
24914 * Fires before rendering of the downloaded JSON data.
24915 * @param {Roo.JsonView} this
24916 * @param {Object} data The JSON data loaded
24920 * Fires when data is loaded.
24921 * @param {Roo.JsonView} this
24922 * @param {Object} data The JSON data loaded
24923 * @param {Object} response The raw Connect response object
24926 * @event loadexception
24927 * Fires when loading fails.
24928 * @param {Roo.JsonView} this
24929 * @param {Object} response The raw Connect response object
24932 'beforerender' : true,
24934 'loadexception' : true
24937 Roo.extend(Roo.JsonView, Roo.View, {
24939 * @type {String} The root property in the loaded JSON object that contains the data
24944 * Refreshes the view.
24946 refresh : function(){
24947 this.clearSelections();
24948 this.el.update("");
24950 var o = this.jsonData;
24951 if(o && o.length > 0){
24952 for(var i = 0, len = o.length; i < len; i++){
24953 var data = this.prepareData(o[i], i, o);
24954 html[html.length] = this.tpl.apply(data);
24957 html.push(this.emptyText);
24959 this.el.update(html.join(""));
24960 this.nodes = this.el.dom.childNodes;
24961 this.updateIndexes(0);
24965 * 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.
24966 * @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:
24969 url: "your-url.php",
24970 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
24971 callback: yourFunction,
24972 scope: yourObject, //(optional scope)
24975 text: "Loading...",
24980 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
24981 * 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.
24982 * @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}
24983 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
24984 * @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.
24987 var um = this.el.getUpdateManager();
24988 um.update.apply(um, arguments);
24991 render : function(el, response){
24992 this.clearSelections();
24993 this.el.update("");
24996 o = Roo.util.JSON.decode(response.responseText);
24999 o = o[this.jsonRoot];
25004 * The current JSON data or null
25007 this.beforeRender();
25012 * Get the number of records in the current JSON dataset
25015 getCount : function(){
25016 return this.jsonData ? this.jsonData.length : 0;
25020 * Returns the JSON object for the specified node(s)
25021 * @param {HTMLElement/Array} node The node or an array of nodes
25022 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25023 * you get the JSON object for the node
25025 getNodeData : function(node){
25026 if(node instanceof Array){
25028 for(var i = 0, len = node.length; i < len; i++){
25029 data.push(this.getNodeData(node[i]));
25033 return this.jsonData[this.indexOf(node)] || null;
25036 beforeRender : function(){
25037 this.snapshot = this.jsonData;
25039 this.sort.apply(this, this.sortInfo);
25041 this.fireEvent("beforerender", this, this.jsonData);
25044 onLoad : function(el, o){
25045 this.fireEvent("load", this, this.jsonData, o);
25048 onLoadException : function(el, o){
25049 this.fireEvent("loadexception", this, o);
25053 * Filter the data by a specific property.
25054 * @param {String} property A property on your JSON objects
25055 * @param {String/RegExp} value Either string that the property values
25056 * should start with, or a RegExp to test against the property
25058 filter : function(property, value){
25061 var ss = this.snapshot;
25062 if(typeof value == "string"){
25063 var vlen = value.length;
25065 this.clearFilter();
25068 value = value.toLowerCase();
25069 for(var i = 0, len = ss.length; i < len; i++){
25071 if(o[property].substr(0, vlen).toLowerCase() == value){
25075 } else if(value.exec){ // regex?
25076 for(var i = 0, len = ss.length; i < len; i++){
25078 if(value.test(o[property])){
25085 this.jsonData = data;
25091 * Filter by a function. The passed function will be called with each
25092 * object in the current dataset. If the function returns true the value is kept,
25093 * otherwise it is filtered.
25094 * @param {Function} fn
25095 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25097 filterBy : function(fn, scope){
25100 var ss = this.snapshot;
25101 for(var i = 0, len = ss.length; i < len; i++){
25103 if(fn.call(scope || this, o)){
25107 this.jsonData = data;
25113 * Clears the current filter.
25115 clearFilter : function(){
25116 if(this.snapshot && this.jsonData != this.snapshot){
25117 this.jsonData = this.snapshot;
25124 * Sorts the data for this view and refreshes it.
25125 * @param {String} property A property on your JSON objects to sort on
25126 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25127 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25129 sort : function(property, dir, sortType){
25130 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25133 var dsc = dir && dir.toLowerCase() == "desc";
25134 var f = function(o1, o2){
25135 var v1 = sortType ? sortType(o1[p]) : o1[p];
25136 var v2 = sortType ? sortType(o2[p]) : o2[p];
25139 return dsc ? +1 : -1;
25140 } else if(v1 > v2){
25141 return dsc ? -1 : +1;
25146 this.jsonData.sort(f);
25148 if(this.jsonData != this.snapshot){
25149 this.snapshot.sort(f);
25155 * Ext JS Library 1.1.1
25156 * Copyright(c) 2006-2007, Ext JS, LLC.
25158 * Originally Released Under LGPL - original licence link has changed is not relivant.
25161 * <script type="text/javascript">
25166 * @class Roo.ColorPalette
25167 * @extends Roo.Component
25168 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25169 * Here's an example of typical usage:
25171 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25172 cp.render('my-div');
25174 cp.on('select', function(palette, selColor){
25175 // do something with selColor
25179 * Create a new ColorPalette
25180 * @param {Object} config The config object
25182 Roo.ColorPalette = function(config){
25183 Roo.ColorPalette.superclass.constructor.call(this, config);
25187 * Fires when a color is selected
25188 * @param {ColorPalette} this
25189 * @param {String} color The 6-digit color hex code (without the # symbol)
25195 this.on("select", this.handler, this.scope, true);
25198 Roo.extend(Roo.ColorPalette, Roo.Component, {
25200 * @cfg {String} itemCls
25201 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25203 itemCls : "x-color-palette",
25205 * @cfg {String} value
25206 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25207 * the hex codes are case-sensitive.
25210 clickEvent:'click',
25212 ctype: "Roo.ColorPalette",
25215 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25217 allowReselect : false,
25220 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25221 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25222 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25223 * of colors with the width setting until the box is symmetrical.</p>
25224 * <p>You can override individual colors if needed:</p>
25226 var cp = new Roo.ColorPalette();
25227 cp.colors[0] = "FF0000"; // change the first box to red
25230 Or you can provide a custom array of your own for complete control:
25232 var cp = new Roo.ColorPalette();
25233 cp.colors = ["000000", "993300", "333300"];
25238 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25239 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25240 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25241 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25242 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25246 onRender : function(container, position){
25247 var t = new Roo.MasterTemplate(
25248 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25250 var c = this.colors;
25251 for(var i = 0, len = c.length; i < len; i++){
25254 var el = document.createElement("div");
25255 el.className = this.itemCls;
25257 container.dom.insertBefore(el, position);
25258 this.el = Roo.get(el);
25259 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25260 if(this.clickEvent != 'click'){
25261 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25266 afterRender : function(){
25267 Roo.ColorPalette.superclass.afterRender.call(this);
25269 var s = this.value;
25276 handleClick : function(e, t){
25277 e.preventDefault();
25278 if(!this.disabled){
25279 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25280 this.select(c.toUpperCase());
25285 * Selects the specified color in the palette (fires the select event)
25286 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25288 select : function(color){
25289 color = color.replace("#", "");
25290 if(color != this.value || this.allowReselect){
25293 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25295 el.child("a.color-"+color).addClass("x-color-palette-sel");
25296 this.value = color;
25297 this.fireEvent("select", this, color);
25302 * Ext JS Library 1.1.1
25303 * Copyright(c) 2006-2007, Ext JS, LLC.
25305 * Originally Released Under LGPL - original licence link has changed is not relivant.
25308 * <script type="text/javascript">
25312 * @class Roo.DatePicker
25313 * @extends Roo.Component
25314 * Simple date picker class.
25316 * Create a new DatePicker
25317 * @param {Object} config The config object
25319 Roo.DatePicker = function(config){
25320 Roo.DatePicker.superclass.constructor.call(this, config);
25322 this.value = config && config.value ?
25323 config.value.clearTime() : new Date().clearTime();
25328 * Fires when a date is selected
25329 * @param {DatePicker} this
25330 * @param {Date} date The selected date
25334 * @event monthchange
25335 * Fires when the displayed month changes
25336 * @param {DatePicker} this
25337 * @param {Date} date The selected month
25339 'monthchange': true
25343 this.on("select", this.handler, this.scope || this);
25345 // build the disabledDatesRE
25346 if(!this.disabledDatesRE && this.disabledDates){
25347 var dd = this.disabledDates;
25349 for(var i = 0; i < dd.length; i++){
25351 if(i != dd.length-1) re += "|";
25353 this.disabledDatesRE = new RegExp(re + ")");
25357 Roo.extend(Roo.DatePicker, Roo.Component, {
25359 * @cfg {String} todayText
25360 * The text to display on the button that selects the current date (defaults to "Today")
25362 todayText : "Today",
25364 * @cfg {String} okText
25365 * The text to display on the ok button
25367 okText : " OK ", //   to give the user extra clicking room
25369 * @cfg {String} cancelText
25370 * The text to display on the cancel button
25372 cancelText : "Cancel",
25374 * @cfg {String} todayTip
25375 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25377 todayTip : "{0} (Spacebar)",
25379 * @cfg {Date} minDate
25380 * Minimum allowable date (JavaScript date object, defaults to null)
25384 * @cfg {Date} maxDate
25385 * Maximum allowable date (JavaScript date object, defaults to null)
25389 * @cfg {String} minText
25390 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25392 minText : "This date is before the minimum date",
25394 * @cfg {String} maxText
25395 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25397 maxText : "This date is after the maximum date",
25399 * @cfg {String} format
25400 * The default date format string which can be overriden for localization support. The format must be
25401 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25405 * @cfg {Array} disabledDays
25406 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25408 disabledDays : null,
25410 * @cfg {String} disabledDaysText
25411 * The tooltip to display when the date falls on a disabled day (defaults to "")
25413 disabledDaysText : "",
25415 * @cfg {RegExp} disabledDatesRE
25416 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25418 disabledDatesRE : null,
25420 * @cfg {String} disabledDatesText
25421 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25423 disabledDatesText : "",
25425 * @cfg {Boolean} constrainToViewport
25426 * True to constrain the date picker to the viewport (defaults to true)
25428 constrainToViewport : true,
25430 * @cfg {Array} monthNames
25431 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25433 monthNames : Date.monthNames,
25435 * @cfg {Array} dayNames
25436 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25438 dayNames : Date.dayNames,
25440 * @cfg {String} nextText
25441 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25443 nextText: 'Next Month (Control+Right)',
25445 * @cfg {String} prevText
25446 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25448 prevText: 'Previous Month (Control+Left)',
25450 * @cfg {String} monthYearText
25451 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25453 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25455 * @cfg {Number} startDay
25456 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25460 * @cfg {Bool} showClear
25461 * Show a clear button (usefull for date form elements that can be blank.)
25467 * Sets the value of the date field
25468 * @param {Date} value The date to set
25470 setValue : function(value){
25471 var old = this.value;
25473 if (typeof(value) == 'string') {
25475 value = Date.parseDate(value, this.format);
25478 value = new Date();
25481 this.value = value.clearTime(true);
25483 this.update(this.value);
25488 * Gets the current selected value of the date field
25489 * @return {Date} The selected date
25491 getValue : function(){
25496 focus : function(){
25498 this.update(this.activeDate);
25503 onRender : function(container, position){
25506 '<table cellspacing="0">',
25507 '<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>',
25508 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
25509 var dn = this.dayNames;
25510 for(var i = 0; i < 7; i++){
25511 var d = this.startDay+i;
25515 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
25517 m[m.length] = "</tr></thead><tbody><tr>";
25518 for(var i = 0; i < 42; i++) {
25519 if(i % 7 == 0 && i != 0){
25520 m[m.length] = "</tr><tr>";
25522 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
25524 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
25525 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
25527 var el = document.createElement("div");
25528 el.className = "x-date-picker";
25529 el.innerHTML = m.join("");
25531 container.dom.insertBefore(el, position);
25533 this.el = Roo.get(el);
25534 this.eventEl = Roo.get(el.firstChild);
25536 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
25537 handler: this.showPrevMonth,
25539 preventDefault:true,
25543 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
25544 handler: this.showNextMonth,
25546 preventDefault:true,
25550 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
25552 this.monthPicker = this.el.down('div.x-date-mp');
25553 this.monthPicker.enableDisplayMode('block');
25555 var kn = new Roo.KeyNav(this.eventEl, {
25556 "left" : function(e){
25558 this.showPrevMonth() :
25559 this.update(this.activeDate.add("d", -1));
25562 "right" : function(e){
25564 this.showNextMonth() :
25565 this.update(this.activeDate.add("d", 1));
25568 "up" : function(e){
25570 this.showNextYear() :
25571 this.update(this.activeDate.add("d", -7));
25574 "down" : function(e){
25576 this.showPrevYear() :
25577 this.update(this.activeDate.add("d", 7));
25580 "pageUp" : function(e){
25581 this.showNextMonth();
25584 "pageDown" : function(e){
25585 this.showPrevMonth();
25588 "enter" : function(e){
25589 e.stopPropagation();
25596 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
25598 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
25600 this.el.unselectable();
25602 this.cells = this.el.select("table.x-date-inner tbody td");
25603 this.textNodes = this.el.query("table.x-date-inner tbody span");
25605 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
25607 tooltip: this.monthYearText
25610 this.mbtn.on('click', this.showMonthPicker, this);
25611 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
25614 var today = (new Date()).dateFormat(this.format);
25616 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
25617 if (this.showClear) {
25618 baseTb.add( new Roo.Toolbar.Fill());
25621 text: String.format(this.todayText, today),
25622 tooltip: String.format(this.todayTip, today),
25623 handler: this.selectToday,
25627 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
25630 if (this.showClear) {
25632 baseTb.add( new Roo.Toolbar.Fill());
25635 cls: 'x-btn-icon x-btn-clear',
25636 handler: function() {
25638 this.fireEvent("select", this, '');
25648 this.update(this.value);
25651 createMonthPicker : function(){
25652 if(!this.monthPicker.dom.firstChild){
25653 var buf = ['<table border="0" cellspacing="0">'];
25654 for(var i = 0; i < 6; i++){
25656 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
25657 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
25659 '<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>' :
25660 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
25664 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
25666 '</button><button type="button" class="x-date-mp-cancel">',
25668 '</button></td></tr>',
25671 this.monthPicker.update(buf.join(''));
25672 this.monthPicker.on('click', this.onMonthClick, this);
25673 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
25675 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
25676 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
25678 this.mpMonths.each(function(m, a, i){
25681 m.dom.xmonth = 5 + Math.round(i * .5);
25683 m.dom.xmonth = Math.round((i-1) * .5);
25689 showMonthPicker : function(){
25690 this.createMonthPicker();
25691 var size = this.el.getSize();
25692 this.monthPicker.setSize(size);
25693 this.monthPicker.child('table').setSize(size);
25695 this.mpSelMonth = (this.activeDate || this.value).getMonth();
25696 this.updateMPMonth(this.mpSelMonth);
25697 this.mpSelYear = (this.activeDate || this.value).getFullYear();
25698 this.updateMPYear(this.mpSelYear);
25700 this.monthPicker.slideIn('t', {duration:.2});
25703 updateMPYear : function(y){
25705 var ys = this.mpYears.elements;
25706 for(var i = 1; i <= 10; i++){
25707 var td = ys[i-1], y2;
25709 y2 = y + Math.round(i * .5);
25710 td.firstChild.innerHTML = y2;
25713 y2 = y - (5-Math.round(i * .5));
25714 td.firstChild.innerHTML = y2;
25717 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
25721 updateMPMonth : function(sm){
25722 this.mpMonths.each(function(m, a, i){
25723 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
25727 selectMPMonth: function(m){
25731 onMonthClick : function(e, t){
25733 var el = new Roo.Element(t), pn;
25734 if(el.is('button.x-date-mp-cancel')){
25735 this.hideMonthPicker();
25737 else if(el.is('button.x-date-mp-ok')){
25738 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25739 this.hideMonthPicker();
25741 else if(pn = el.up('td.x-date-mp-month', 2)){
25742 this.mpMonths.removeClass('x-date-mp-sel');
25743 pn.addClass('x-date-mp-sel');
25744 this.mpSelMonth = pn.dom.xmonth;
25746 else if(pn = el.up('td.x-date-mp-year', 2)){
25747 this.mpYears.removeClass('x-date-mp-sel');
25748 pn.addClass('x-date-mp-sel');
25749 this.mpSelYear = pn.dom.xyear;
25751 else if(el.is('a.x-date-mp-prev')){
25752 this.updateMPYear(this.mpyear-10);
25754 else if(el.is('a.x-date-mp-next')){
25755 this.updateMPYear(this.mpyear+10);
25759 onMonthDblClick : function(e, t){
25761 var el = new Roo.Element(t), pn;
25762 if(pn = el.up('td.x-date-mp-month', 2)){
25763 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
25764 this.hideMonthPicker();
25766 else if(pn = el.up('td.x-date-mp-year', 2)){
25767 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
25768 this.hideMonthPicker();
25772 hideMonthPicker : function(disableAnim){
25773 if(this.monthPicker){
25774 if(disableAnim === true){
25775 this.monthPicker.hide();
25777 this.monthPicker.slideOut('t', {duration:.2});
25783 showPrevMonth : function(e){
25784 this.update(this.activeDate.add("mo", -1));
25788 showNextMonth : function(e){
25789 this.update(this.activeDate.add("mo", 1));
25793 showPrevYear : function(){
25794 this.update(this.activeDate.add("y", -1));
25798 showNextYear : function(){
25799 this.update(this.activeDate.add("y", 1));
25803 handleMouseWheel : function(e){
25804 var delta = e.getWheelDelta();
25806 this.showPrevMonth();
25808 } else if(delta < 0){
25809 this.showNextMonth();
25815 handleDateClick : function(e, t){
25817 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
25818 this.setValue(new Date(t.dateValue));
25819 this.fireEvent("select", this, this.value);
25824 selectToday : function(){
25825 this.setValue(new Date().clearTime());
25826 this.fireEvent("select", this, this.value);
25830 update : function(date)
25832 var vd = this.activeDate;
25833 this.activeDate = date;
25835 var t = date.getTime();
25836 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
25837 this.cells.removeClass("x-date-selected");
25838 this.cells.each(function(c){
25839 if(c.dom.firstChild.dateValue == t){
25840 c.addClass("x-date-selected");
25841 setTimeout(function(){
25842 try{c.dom.firstChild.focus();}catch(e){}
25851 var days = date.getDaysInMonth();
25852 var firstOfMonth = date.getFirstDateOfMonth();
25853 var startingPos = firstOfMonth.getDay()-this.startDay;
25855 if(startingPos <= this.startDay){
25859 var pm = date.add("mo", -1);
25860 var prevStart = pm.getDaysInMonth()-startingPos;
25862 var cells = this.cells.elements;
25863 var textEls = this.textNodes;
25864 days += startingPos;
25866 // convert everything to numbers so it's fast
25867 var day = 86400000;
25868 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
25869 var today = new Date().clearTime().getTime();
25870 var sel = date.clearTime().getTime();
25871 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
25872 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
25873 var ddMatch = this.disabledDatesRE;
25874 var ddText = this.disabledDatesText;
25875 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
25876 var ddaysText = this.disabledDaysText;
25877 var format = this.format;
25879 var setCellClass = function(cal, cell){
25881 var t = d.getTime();
25882 cell.firstChild.dateValue = t;
25884 cell.className += " x-date-today";
25885 cell.title = cal.todayText;
25888 cell.className += " x-date-selected";
25889 setTimeout(function(){
25890 try{cell.firstChild.focus();}catch(e){}
25895 cell.className = " x-date-disabled";
25896 cell.title = cal.minText;
25900 cell.className = " x-date-disabled";
25901 cell.title = cal.maxText;
25905 if(ddays.indexOf(d.getDay()) != -1){
25906 cell.title = ddaysText;
25907 cell.className = " x-date-disabled";
25910 if(ddMatch && format){
25911 var fvalue = d.dateFormat(format);
25912 if(ddMatch.test(fvalue)){
25913 cell.title = ddText.replace("%0", fvalue);
25914 cell.className = " x-date-disabled";
25920 for(; i < startingPos; i++) {
25921 textEls[i].innerHTML = (++prevStart);
25922 d.setDate(d.getDate()+1);
25923 cells[i].className = "x-date-prevday";
25924 setCellClass(this, cells[i]);
25926 for(; i < days; i++){
25927 intDay = i - startingPos + 1;
25928 textEls[i].innerHTML = (intDay);
25929 d.setDate(d.getDate()+1);
25930 cells[i].className = "x-date-active";
25931 setCellClass(this, cells[i]);
25934 for(; i < 42; i++) {
25935 textEls[i].innerHTML = (++extraDays);
25936 d.setDate(d.getDate()+1);
25937 cells[i].className = "x-date-nextday";
25938 setCellClass(this, cells[i]);
25941 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
25942 this.fireEvent('monthchange', this, date);
25944 if(!this.internalRender){
25945 var main = this.el.dom.firstChild;
25946 var w = main.offsetWidth;
25947 this.el.setWidth(w + this.el.getBorderWidth("lr"));
25948 Roo.fly(main).setWidth(w);
25949 this.internalRender = true;
25950 // opera does not respect the auto grow header center column
25951 // then, after it gets a width opera refuses to recalculate
25952 // without a second pass
25953 if(Roo.isOpera && !this.secondPass){
25954 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
25955 this.secondPass = true;
25956 this.update.defer(10, this, [date]);
25964 * Ext JS Library 1.1.1
25965 * Copyright(c) 2006-2007, Ext JS, LLC.
25967 * Originally Released Under LGPL - original licence link has changed is not relivant.
25970 * <script type="text/javascript">
25973 * @class Roo.TabPanel
25974 * @extends Roo.util.Observable
25975 * A lightweight tab container.
25979 // basic tabs 1, built from existing content
25980 var tabs = new Roo.TabPanel("tabs1");
25981 tabs.addTab("script", "View Script");
25982 tabs.addTab("markup", "View Markup");
25983 tabs.activate("script");
25985 // more advanced tabs, built from javascript
25986 var jtabs = new Roo.TabPanel("jtabs");
25987 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
25989 // set up the UpdateManager
25990 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
25991 var updater = tab2.getUpdateManager();
25992 updater.setDefaultUrl("ajax1.htm");
25993 tab2.on('activate', updater.refresh, updater, true);
25995 // Use setUrl for Ajax loading
25996 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
25997 tab3.setUrl("ajax2.htm", null, true);
26000 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26003 jtabs.activate("jtabs-1");
26006 * Create a new TabPanel.
26007 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26008 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26010 Roo.TabPanel = function(container, config){
26012 * The container element for this TabPanel.
26013 * @type Roo.Element
26015 this.el = Roo.get(container, true);
26017 if(typeof config == "boolean"){
26018 this.tabPosition = config ? "bottom" : "top";
26020 Roo.apply(this, config);
26023 if(this.tabPosition == "bottom"){
26024 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26025 this.el.addClass("x-tabs-bottom");
26027 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26028 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26029 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26031 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26033 if(this.tabPosition != "bottom"){
26034 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26035 * @type Roo.Element
26037 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26038 this.el.addClass("x-tabs-top");
26042 this.bodyEl.setStyle("position", "relative");
26044 this.active = null;
26045 this.activateDelegate = this.activate.createDelegate(this);
26050 * Fires when the active tab changes
26051 * @param {Roo.TabPanel} this
26052 * @param {Roo.TabPanelItem} activePanel The new active tab
26056 * @event beforetabchange
26057 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26058 * @param {Roo.TabPanel} this
26059 * @param {Object} e Set cancel to true on this object to cancel the tab change
26060 * @param {Roo.TabPanelItem} tab The tab being changed to
26062 "beforetabchange" : true
26065 Roo.EventManager.onWindowResize(this.onResize, this);
26066 this.cpad = this.el.getPadding("lr");
26067 this.hiddenCount = 0;
26070 // toolbar on the tabbar support...
26071 if (this.toolbar) {
26072 var tcfg = this.toolbar;
26073 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26074 this.toolbar = new Roo.Toolbar(tcfg);
26075 if (Roo.isSafari) {
26076 var tbl = tcfg.container.child('table', true);
26077 tbl.setAttribute('width', '100%');
26084 Roo.TabPanel.superclass.constructor.call(this);
26087 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26089 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26091 tabPosition : "top",
26093 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26095 currentTabWidth : 0,
26097 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26101 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26105 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26107 preferredTabWidth : 175,
26109 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26111 resizeTabs : false,
26113 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26115 monitorResize : true,
26117 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26122 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26123 * @param {String} id The id of the div to use <b>or create</b>
26124 * @param {String} text The text for the tab
26125 * @param {String} content (optional) Content to put in the TabPanelItem body
26126 * @param {Boolean} closable (optional) True to create a close icon on the tab
26127 * @return {Roo.TabPanelItem} The created TabPanelItem
26129 addTab : function(id, text, content, closable){
26130 var item = new Roo.TabPanelItem(this, id, text, closable);
26131 this.addTabItem(item);
26133 item.setContent(content);
26139 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26140 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26141 * @return {Roo.TabPanelItem}
26143 getTab : function(id){
26144 return this.items[id];
26148 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26149 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26151 hideTab : function(id){
26152 var t = this.items[id];
26155 this.hiddenCount++;
26156 this.autoSizeTabs();
26161 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26162 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26164 unhideTab : function(id){
26165 var t = this.items[id];
26167 t.setHidden(false);
26168 this.hiddenCount--;
26169 this.autoSizeTabs();
26174 * Adds an existing {@link Roo.TabPanelItem}.
26175 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26177 addTabItem : function(item){
26178 this.items[item.id] = item;
26179 this.items.push(item);
26180 if(this.resizeTabs){
26181 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26182 this.autoSizeTabs();
26189 * Removes a {@link Roo.TabPanelItem}.
26190 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26192 removeTab : function(id){
26193 var items = this.items;
26194 var tab = items[id];
26195 if(!tab) { return; }
26196 var index = items.indexOf(tab);
26197 if(this.active == tab && items.length > 1){
26198 var newTab = this.getNextAvailable(index);
26203 this.stripEl.dom.removeChild(tab.pnode.dom);
26204 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26205 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26207 items.splice(index, 1);
26208 delete this.items[tab.id];
26209 tab.fireEvent("close", tab);
26210 tab.purgeListeners();
26211 this.autoSizeTabs();
26214 getNextAvailable : function(start){
26215 var items = this.items;
26217 // look for a next tab that will slide over to
26218 // replace the one being removed
26219 while(index < items.length){
26220 var item = items[++index];
26221 if(item && !item.isHidden()){
26225 // if one isn't found select the previous tab (on the left)
26228 var item = items[--index];
26229 if(item && !item.isHidden()){
26237 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26238 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26240 disableTab : function(id){
26241 var tab = this.items[id];
26242 if(tab && this.active != tab){
26248 * Enables a {@link Roo.TabPanelItem} that is disabled.
26249 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26251 enableTab : function(id){
26252 var tab = this.items[id];
26257 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26258 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26259 * @return {Roo.TabPanelItem} The TabPanelItem.
26261 activate : function(id){
26262 var tab = this.items[id];
26266 if(tab == this.active || tab.disabled){
26270 this.fireEvent("beforetabchange", this, e, tab);
26271 if(e.cancel !== true && !tab.disabled){
26273 this.active.hide();
26275 this.active = this.items[id];
26276 this.active.show();
26277 this.fireEvent("tabchange", this, this.active);
26283 * Gets the active {@link Roo.TabPanelItem}.
26284 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26286 getActiveTab : function(){
26287 return this.active;
26291 * Updates the tab body element to fit the height of the container element
26292 * for overflow scrolling
26293 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26295 syncHeight : function(targetHeight){
26296 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26297 var bm = this.bodyEl.getMargins();
26298 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26299 this.bodyEl.setHeight(newHeight);
26303 onResize : function(){
26304 if(this.monitorResize){
26305 this.autoSizeTabs();
26310 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26312 beginUpdate : function(){
26313 this.updating = true;
26317 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26319 endUpdate : function(){
26320 this.updating = false;
26321 this.autoSizeTabs();
26325 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26327 autoSizeTabs : function(){
26328 var count = this.items.length;
26329 var vcount = count - this.hiddenCount;
26330 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26331 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26332 var availWidth = Math.floor(w / vcount);
26333 var b = this.stripBody;
26334 if(b.getWidth() > w){
26335 var tabs = this.items;
26336 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26337 if(availWidth < this.minTabWidth){
26338 /*if(!this.sleft){ // incomplete scrolling code
26339 this.createScrollButtons();
26342 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26345 if(this.currentTabWidth < this.preferredTabWidth){
26346 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26352 * Returns the number of tabs in this TabPanel.
26355 getCount : function(){
26356 return this.items.length;
26360 * Resizes all the tabs to the passed width
26361 * @param {Number} The new width
26363 setTabWidth : function(width){
26364 this.currentTabWidth = width;
26365 for(var i = 0, len = this.items.length; i < len; i++) {
26366 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26371 * Destroys this TabPanel
26372 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26374 destroy : function(removeEl){
26375 Roo.EventManager.removeResizeListener(this.onResize, this);
26376 for(var i = 0, len = this.items.length; i < len; i++){
26377 this.items[i].purgeListeners();
26379 if(removeEl === true){
26380 this.el.update("");
26387 * @class Roo.TabPanelItem
26388 * @extends Roo.util.Observable
26389 * Represents an individual item (tab plus body) in a TabPanel.
26390 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26391 * @param {String} id The id of this TabPanelItem
26392 * @param {String} text The text for the tab of this TabPanelItem
26393 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26395 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26397 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26398 * @type Roo.TabPanel
26400 this.tabPanel = tabPanel;
26402 * The id for this TabPanelItem
26407 this.disabled = false;
26411 this.loaded = false;
26412 this.closable = closable;
26415 * The body element for this TabPanelItem.
26416 * @type Roo.Element
26418 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26419 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26420 this.bodyEl.setStyle("display", "block");
26421 this.bodyEl.setStyle("zoom", "1");
26424 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26426 this.el = Roo.get(els.el, true);
26427 this.inner = Roo.get(els.inner, true);
26428 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26429 this.pnode = Roo.get(els.el.parentNode, true);
26430 this.el.on("mousedown", this.onTabMouseDown, this);
26431 this.el.on("click", this.onTabClick, this);
26434 var c = Roo.get(els.close, true);
26435 c.dom.title = this.closeText;
26436 c.addClassOnOver("close-over");
26437 c.on("click", this.closeClick, this);
26443 * Fires when this tab becomes the active tab.
26444 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26445 * @param {Roo.TabPanelItem} this
26449 * @event beforeclose
26450 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26451 * @param {Roo.TabPanelItem} this
26452 * @param {Object} e Set cancel to true on this object to cancel the close.
26454 "beforeclose": true,
26457 * Fires when this tab is closed.
26458 * @param {Roo.TabPanelItem} this
26462 * @event deactivate
26463 * Fires when this tab is no longer the active tab.
26464 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26465 * @param {Roo.TabPanelItem} this
26467 "deactivate" : true
26469 this.hidden = false;
26471 Roo.TabPanelItem.superclass.constructor.call(this);
26474 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26475 purgeListeners : function(){
26476 Roo.util.Observable.prototype.purgeListeners.call(this);
26477 this.el.removeAllListeners();
26480 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26483 this.pnode.addClass("on");
26486 this.tabPanel.stripWrap.repaint();
26488 this.fireEvent("activate", this.tabPanel, this);
26492 * Returns true if this tab is the active tab.
26493 * @return {Boolean}
26495 isActive : function(){
26496 return this.tabPanel.getActiveTab() == this;
26500 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
26503 this.pnode.removeClass("on");
26505 this.fireEvent("deactivate", this.tabPanel, this);
26508 hideAction : function(){
26509 this.bodyEl.hide();
26510 this.bodyEl.setStyle("position", "absolute");
26511 this.bodyEl.setLeft("-20000px");
26512 this.bodyEl.setTop("-20000px");
26515 showAction : function(){
26516 this.bodyEl.setStyle("position", "relative");
26517 this.bodyEl.setTop("");
26518 this.bodyEl.setLeft("");
26519 this.bodyEl.show();
26523 * Set the tooltip for the tab.
26524 * @param {String} tooltip The tab's tooltip
26526 setTooltip : function(text){
26527 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
26528 this.textEl.dom.qtip = text;
26529 this.textEl.dom.removeAttribute('title');
26531 this.textEl.dom.title = text;
26535 onTabClick : function(e){
26536 e.preventDefault();
26537 this.tabPanel.activate(this.id);
26540 onTabMouseDown : function(e){
26541 e.preventDefault();
26542 this.tabPanel.activate(this.id);
26545 getWidth : function(){
26546 return this.inner.getWidth();
26549 setWidth : function(width){
26550 var iwidth = width - this.pnode.getPadding("lr");
26551 this.inner.setWidth(iwidth);
26552 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
26553 this.pnode.setWidth(width);
26557 * Show or hide the tab
26558 * @param {Boolean} hidden True to hide or false to show.
26560 setHidden : function(hidden){
26561 this.hidden = hidden;
26562 this.pnode.setStyle("display", hidden ? "none" : "");
26566 * Returns true if this tab is "hidden"
26567 * @return {Boolean}
26569 isHidden : function(){
26570 return this.hidden;
26574 * Returns the text for this tab
26577 getText : function(){
26581 autoSize : function(){
26582 //this.el.beginMeasure();
26583 this.textEl.setWidth(1);
26584 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
26585 //this.el.endMeasure();
26589 * Sets the text for the tab (Note: this also sets the tooltip text)
26590 * @param {String} text The tab's text and tooltip
26592 setText : function(text){
26594 this.textEl.update(text);
26595 this.setTooltip(text);
26596 if(!this.tabPanel.resizeTabs){
26601 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
26603 activate : function(){
26604 this.tabPanel.activate(this.id);
26608 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
26610 disable : function(){
26611 if(this.tabPanel.active != this){
26612 this.disabled = true;
26613 this.pnode.addClass("disabled");
26618 * Enables this TabPanelItem if it was previously disabled.
26620 enable : function(){
26621 this.disabled = false;
26622 this.pnode.removeClass("disabled");
26626 * Sets the content for this TabPanelItem.
26627 * @param {String} content The content
26628 * @param {Boolean} loadScripts true to look for and load scripts
26630 setContent : function(content, loadScripts){
26631 this.bodyEl.update(content, loadScripts);
26635 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
26636 * @return {Roo.UpdateManager} The UpdateManager
26638 getUpdateManager : function(){
26639 return this.bodyEl.getUpdateManager();
26643 * Set a URL to be used to load the content for this TabPanelItem.
26644 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
26645 * @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)
26646 * @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)
26647 * @return {Roo.UpdateManager} The UpdateManager
26649 setUrl : function(url, params, loadOnce){
26650 if(this.refreshDelegate){
26651 this.un('activate', this.refreshDelegate);
26653 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
26654 this.on("activate", this.refreshDelegate);
26655 return this.bodyEl.getUpdateManager();
26659 _handleRefresh : function(url, params, loadOnce){
26660 if(!loadOnce || !this.loaded){
26661 var updater = this.bodyEl.getUpdateManager();
26662 updater.update(url, params, this._setLoaded.createDelegate(this));
26667 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
26668 * Will fail silently if the setUrl method has not been called.
26669 * This does not activate the panel, just updates its content.
26671 refresh : function(){
26672 if(this.refreshDelegate){
26673 this.loaded = false;
26674 this.refreshDelegate();
26679 _setLoaded : function(){
26680 this.loaded = true;
26684 closeClick : function(e){
26687 this.fireEvent("beforeclose", this, o);
26688 if(o.cancel !== true){
26689 this.tabPanel.removeTab(this.id);
26693 * The text displayed in the tooltip for the close icon.
26696 closeText : "Close this tab"
26700 Roo.TabPanel.prototype.createStrip = function(container){
26701 var strip = document.createElement("div");
26702 strip.className = "x-tabs-wrap";
26703 container.appendChild(strip);
26707 Roo.TabPanel.prototype.createStripList = function(strip){
26708 // div wrapper for retard IE
26709 // returns the "tr" element.
26710 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
26711 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
26712 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
26713 return strip.firstChild.firstChild.firstChild.firstChild;
26716 Roo.TabPanel.prototype.createBody = function(container){
26717 var body = document.createElement("div");
26718 Roo.id(body, "tab-body");
26719 Roo.fly(body).addClass("x-tabs-body");
26720 container.appendChild(body);
26724 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
26725 var body = Roo.getDom(id);
26727 body = document.createElement("div");
26730 Roo.fly(body).addClass("x-tabs-item-body");
26731 bodyEl.insertBefore(body, bodyEl.firstChild);
26735 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
26736 var td = document.createElement("td");
26737 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
26738 //stripEl.appendChild(td);
26740 td.className = "x-tabs-closable";
26741 if(!this.closeTpl){
26742 this.closeTpl = new Roo.Template(
26743 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26744 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
26745 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
26748 var el = this.closeTpl.overwrite(td, {"text": text});
26749 var close = el.getElementsByTagName("div")[0];
26750 var inner = el.getElementsByTagName("em")[0];
26751 return {"el": el, "close": close, "inner": inner};
26754 this.tabTpl = new Roo.Template(
26755 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
26756 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
26759 var el = this.tabTpl.overwrite(td, {"text": text});
26760 var inner = el.getElementsByTagName("em")[0];
26761 return {"el": el, "inner": inner};
26765 * Ext JS Library 1.1.1
26766 * Copyright(c) 2006-2007, Ext JS, LLC.
26768 * Originally Released Under LGPL - original licence link has changed is not relivant.
26771 * <script type="text/javascript">
26775 * @class Roo.Button
26776 * @extends Roo.util.Observable
26777 * Simple Button class
26778 * @cfg {String} text The button text
26779 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
26780 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
26781 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
26782 * @cfg {Object} scope The scope of the handler
26783 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
26784 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
26785 * @cfg {Boolean} hidden True to start hidden (defaults to false)
26786 * @cfg {Boolean} disabled True to start disabled (defaults to false)
26787 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26788 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
26789 applies if enableToggle = true)
26790 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
26791 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
26792 an {@link Roo.util.ClickRepeater} config object (defaults to false).
26794 * Create a new button
26795 * @param {Object} config The config object
26797 Roo.Button = function(renderTo, config)
26801 renderTo = config.renderTo || false;
26804 Roo.apply(this, config);
26808 * Fires when this button is clicked
26809 * @param {Button} this
26810 * @param {EventObject} e The click event
26815 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
26816 * @param {Button} this
26817 * @param {Boolean} pressed
26822 * Fires when the mouse hovers over the button
26823 * @param {Button} this
26824 * @param {Event} e The event object
26826 'mouseover' : true,
26829 * Fires when the mouse exits the button
26830 * @param {Button} this
26831 * @param {Event} e The event object
26836 * Fires when the button is rendered
26837 * @param {Button} this
26842 this.menu = Roo.menu.MenuMgr.get(this.menu);
26844 // register listeners first!! - so render can be captured..
26845 Roo.util.Observable.call(this);
26847 this.render(renderTo);
26853 Roo.extend(Roo.Button, Roo.util.Observable, {
26859 * Read-only. True if this button is hidden
26864 * Read-only. True if this button is disabled
26869 * Read-only. True if this button is pressed (only if enableToggle = true)
26875 * @cfg {Number} tabIndex
26876 * The DOM tabIndex for this button (defaults to undefined)
26878 tabIndex : undefined,
26881 * @cfg {Boolean} enableToggle
26882 * True to enable pressed/not pressed toggling (defaults to false)
26884 enableToggle: false,
26886 * @cfg {Mixed} menu
26887 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
26891 * @cfg {String} menuAlign
26892 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
26894 menuAlign : "tl-bl?",
26897 * @cfg {String} iconCls
26898 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
26900 iconCls : undefined,
26902 * @cfg {String} type
26903 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
26908 menuClassTarget: 'tr',
26911 * @cfg {String} clickEvent
26912 * The type of event to map to the button's event handler (defaults to 'click')
26914 clickEvent : 'click',
26917 * @cfg {Boolean} handleMouseEvents
26918 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
26920 handleMouseEvents : true,
26923 * @cfg {String} tooltipType
26924 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
26926 tooltipType : 'qtip',
26929 * @cfg {String} cls
26930 * A CSS class to apply to the button's main element.
26934 * @cfg {Roo.Template} template (Optional)
26935 * An {@link Roo.Template} with which to create the Button's main element. This Template must
26936 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
26937 * require code modifications if required elements (e.g. a button) aren't present.
26941 render : function(renderTo){
26943 if(this.hideParent){
26944 this.parentEl = Roo.get(renderTo);
26946 if(!this.dhconfig){
26947 if(!this.template){
26948 if(!Roo.Button.buttonTemplate){
26949 // hideous table template
26950 Roo.Button.buttonTemplate = new Roo.Template(
26951 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
26952 '<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>',
26953 "</tr></tbody></table>");
26955 this.template = Roo.Button.buttonTemplate;
26957 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
26958 var btnEl = btn.child("button:first");
26959 btnEl.on('focus', this.onFocus, this);
26960 btnEl.on('blur', this.onBlur, this);
26962 btn.addClass(this.cls);
26965 btnEl.setStyle('background-image', 'url(' +this.icon +')');
26968 btnEl.addClass(this.iconCls);
26970 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
26973 if(this.tabIndex !== undefined){
26974 btnEl.dom.tabIndex = this.tabIndex;
26977 if(typeof this.tooltip == 'object'){
26978 Roo.QuickTips.tips(Roo.apply({
26982 btnEl.dom[this.tooltipType] = this.tooltip;
26986 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
26990 this.el.dom.id = this.el.id = this.id;
26993 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
26994 this.menu.on("show", this.onMenuShow, this);
26995 this.menu.on("hide", this.onMenuHide, this);
26997 btn.addClass("x-btn");
26998 if(Roo.isIE && !Roo.isIE7){
26999 this.autoWidth.defer(1, this);
27003 if(this.handleMouseEvents){
27004 btn.on("mouseover", this.onMouseOver, this);
27005 btn.on("mouseout", this.onMouseOut, this);
27006 btn.on("mousedown", this.onMouseDown, this);
27008 btn.on(this.clickEvent, this.onClick, this);
27009 //btn.on("mouseup", this.onMouseUp, this);
27016 Roo.ButtonToggleMgr.register(this);
27018 this.el.addClass("x-btn-pressed");
27021 var repeater = new Roo.util.ClickRepeater(btn,
27022 typeof this.repeat == "object" ? this.repeat : {}
27024 repeater.on("click", this.onClick, this);
27027 this.fireEvent('render', this);
27031 * Returns the button's underlying element
27032 * @return {Roo.Element} The element
27034 getEl : function(){
27039 * Destroys this Button and removes any listeners.
27041 destroy : function(){
27042 Roo.ButtonToggleMgr.unregister(this);
27043 this.el.removeAllListeners();
27044 this.purgeListeners();
27049 autoWidth : function(){
27051 this.el.setWidth("auto");
27052 if(Roo.isIE7 && Roo.isStrict){
27053 var ib = this.el.child('button');
27054 if(ib && ib.getWidth() > 20){
27056 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27061 this.el.beginMeasure();
27063 if(this.el.getWidth() < this.minWidth){
27064 this.el.setWidth(this.minWidth);
27067 this.el.endMeasure();
27074 * Assigns this button's click handler
27075 * @param {Function} handler The function to call when the button is clicked
27076 * @param {Object} scope (optional) Scope for the function passed in
27078 setHandler : function(handler, scope){
27079 this.handler = handler;
27080 this.scope = scope;
27084 * Sets this button's text
27085 * @param {String} text The button text
27087 setText : function(text){
27090 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27096 * Gets the text for this button
27097 * @return {String} The button text
27099 getText : function(){
27107 this.hidden = false;
27109 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27117 this.hidden = true;
27119 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27124 * Convenience function for boolean show/hide
27125 * @param {Boolean} visible True to show, false to hide
27127 setVisible: function(visible){
27136 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27137 * @param {Boolean} state (optional) Force a particular state
27139 toggle : function(state){
27140 state = state === undefined ? !this.pressed : state;
27141 if(state != this.pressed){
27143 this.el.addClass("x-btn-pressed");
27144 this.pressed = true;
27145 this.fireEvent("toggle", this, true);
27147 this.el.removeClass("x-btn-pressed");
27148 this.pressed = false;
27149 this.fireEvent("toggle", this, false);
27151 if(this.toggleHandler){
27152 this.toggleHandler.call(this.scope || this, this, state);
27160 focus : function(){
27161 this.el.child('button:first').focus();
27165 * Disable this button
27167 disable : function(){
27169 this.el.addClass("x-btn-disabled");
27171 this.disabled = true;
27175 * Enable this button
27177 enable : function(){
27179 this.el.removeClass("x-btn-disabled");
27181 this.disabled = false;
27185 * Convenience function for boolean enable/disable
27186 * @param {Boolean} enabled True to enable, false to disable
27188 setDisabled : function(v){
27189 this[v !== true ? "enable" : "disable"]();
27193 onClick : function(e){
27195 e.preventDefault();
27200 if(!this.disabled){
27201 if(this.enableToggle){
27204 if(this.menu && !this.menu.isVisible()){
27205 this.menu.show(this.el, this.menuAlign);
27207 this.fireEvent("click", this, e);
27209 this.el.removeClass("x-btn-over");
27210 this.handler.call(this.scope || this, this, e);
27215 onMouseOver : function(e){
27216 if(!this.disabled){
27217 this.el.addClass("x-btn-over");
27218 this.fireEvent('mouseover', this, e);
27222 onMouseOut : function(e){
27223 if(!e.within(this.el, true)){
27224 this.el.removeClass("x-btn-over");
27225 this.fireEvent('mouseout', this, e);
27229 onFocus : function(e){
27230 if(!this.disabled){
27231 this.el.addClass("x-btn-focus");
27235 onBlur : function(e){
27236 this.el.removeClass("x-btn-focus");
27239 onMouseDown : function(e){
27240 if(!this.disabled && e.button == 0){
27241 this.el.addClass("x-btn-click");
27242 Roo.get(document).on('mouseup', this.onMouseUp, this);
27246 onMouseUp : function(e){
27248 this.el.removeClass("x-btn-click");
27249 Roo.get(document).un('mouseup', this.onMouseUp, this);
27253 onMenuShow : function(e){
27254 this.el.addClass("x-btn-menu-active");
27257 onMenuHide : function(e){
27258 this.el.removeClass("x-btn-menu-active");
27262 // Private utility class used by Button
27263 Roo.ButtonToggleMgr = function(){
27266 function toggleGroup(btn, state){
27268 var g = groups[btn.toggleGroup];
27269 for(var i = 0, l = g.length; i < l; i++){
27271 g[i].toggle(false);
27278 register : function(btn){
27279 if(!btn.toggleGroup){
27282 var g = groups[btn.toggleGroup];
27284 g = groups[btn.toggleGroup] = [];
27287 btn.on("toggle", toggleGroup);
27290 unregister : function(btn){
27291 if(!btn.toggleGroup){
27294 var g = groups[btn.toggleGroup];
27297 btn.un("toggle", toggleGroup);
27303 * Ext JS Library 1.1.1
27304 * Copyright(c) 2006-2007, Ext JS, LLC.
27306 * Originally Released Under LGPL - original licence link has changed is not relivant.
27309 * <script type="text/javascript">
27313 * @class Roo.SplitButton
27314 * @extends Roo.Button
27315 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27316 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27317 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27318 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27319 * @cfg {String} arrowTooltip The title attribute of the arrow
27321 * Create a new menu button
27322 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27323 * @param {Object} config The config object
27325 Roo.SplitButton = function(renderTo, config){
27326 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27328 * @event arrowclick
27329 * Fires when this button's arrow is clicked
27330 * @param {SplitButton} this
27331 * @param {EventObject} e The click event
27333 this.addEvents({"arrowclick":true});
27336 Roo.extend(Roo.SplitButton, Roo.Button, {
27337 render : function(renderTo){
27338 // this is one sweet looking template!
27339 var tpl = new Roo.Template(
27340 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27341 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27342 '<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>',
27343 "</tbody></table></td><td>",
27344 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27345 '<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>',
27346 "</tbody></table></td></tr></table>"
27348 var btn = tpl.append(renderTo, [this.text, this.type], true);
27349 var btnEl = btn.child("button");
27351 btn.addClass(this.cls);
27354 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27357 btnEl.addClass(this.iconCls);
27359 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27363 if(this.handleMouseEvents){
27364 btn.on("mouseover", this.onMouseOver, this);
27365 btn.on("mouseout", this.onMouseOut, this);
27366 btn.on("mousedown", this.onMouseDown, this);
27367 btn.on("mouseup", this.onMouseUp, this);
27369 btn.on(this.clickEvent, this.onClick, this);
27371 if(typeof this.tooltip == 'object'){
27372 Roo.QuickTips.tips(Roo.apply({
27376 btnEl.dom[this.tooltipType] = this.tooltip;
27379 if(this.arrowTooltip){
27380 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27389 this.el.addClass("x-btn-pressed");
27391 if(Roo.isIE && !Roo.isIE7){
27392 this.autoWidth.defer(1, this);
27397 this.menu.on("show", this.onMenuShow, this);
27398 this.menu.on("hide", this.onMenuHide, this);
27400 this.fireEvent('render', this);
27404 autoWidth : function(){
27406 var tbl = this.el.child("table:first");
27407 var tbl2 = this.el.child("table:last");
27408 this.el.setWidth("auto");
27409 tbl.setWidth("auto");
27410 if(Roo.isIE7 && Roo.isStrict){
27411 var ib = this.el.child('button:first');
27412 if(ib && ib.getWidth() > 20){
27414 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27419 this.el.beginMeasure();
27421 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27422 tbl.setWidth(this.minWidth-tbl2.getWidth());
27425 this.el.endMeasure();
27428 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27432 * Sets this button's click handler
27433 * @param {Function} handler The function to call when the button is clicked
27434 * @param {Object} scope (optional) Scope for the function passed above
27436 setHandler : function(handler, scope){
27437 this.handler = handler;
27438 this.scope = scope;
27442 * Sets this button's arrow click handler
27443 * @param {Function} handler The function to call when the arrow is clicked
27444 * @param {Object} scope (optional) Scope for the function passed above
27446 setArrowHandler : function(handler, scope){
27447 this.arrowHandler = handler;
27448 this.scope = scope;
27454 focus : function(){
27456 this.el.child("button:first").focus();
27461 onClick : function(e){
27462 e.preventDefault();
27463 if(!this.disabled){
27464 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27465 if(this.menu && !this.menu.isVisible()){
27466 this.menu.show(this.el, this.menuAlign);
27468 this.fireEvent("arrowclick", this, e);
27469 if(this.arrowHandler){
27470 this.arrowHandler.call(this.scope || this, this, e);
27473 this.fireEvent("click", this, e);
27475 this.handler.call(this.scope || this, this, e);
27481 onMouseDown : function(e){
27482 if(!this.disabled){
27483 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27487 onMouseUp : function(e){
27488 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27493 // backwards compat
27494 Roo.MenuButton = Roo.SplitButton;/*
27496 * Ext JS Library 1.1.1
27497 * Copyright(c) 2006-2007, Ext JS, LLC.
27499 * Originally Released Under LGPL - original licence link has changed is not relivant.
27502 * <script type="text/javascript">
27506 * @class Roo.Toolbar
27507 * Basic Toolbar class.
27509 * Creates a new Toolbar
27510 * @param {Object} container The config object
27512 Roo.Toolbar = function(container, buttons, config)
27514 /// old consturctor format still supported..
27515 if(container instanceof Array){ // omit the container for later rendering
27516 buttons = container;
27520 if (typeof(container) == 'object' && container.xtype) {
27521 config = container;
27522 container = config.container;
27523 buttons = config.buttons || []; // not really - use items!!
27526 if (config && config.items) {
27527 xitems = config.items;
27528 delete config.items;
27530 Roo.apply(this, config);
27531 this.buttons = buttons;
27534 this.render(container);
27536 this.xitems = xitems;
27537 Roo.each(xitems, function(b) {
27543 Roo.Toolbar.prototype = {
27545 * @cfg {Array} items
27546 * array of button configs or elements to add (will be converted to a MixedCollection)
27550 * @cfg {String/HTMLElement/Element} container
27551 * The id or element that will contain the toolbar
27554 render : function(ct){
27555 this.el = Roo.get(ct);
27557 this.el.addClass(this.cls);
27559 // using a table allows for vertical alignment
27560 // 100% width is needed by Safari...
27561 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
27562 this.tr = this.el.child("tr", true);
27564 this.items = new Roo.util.MixedCollection(false, function(o){
27565 return o.id || ("item" + (++autoId));
27568 this.add.apply(this, this.buttons);
27569 delete this.buttons;
27574 * Adds element(s) to the toolbar -- this function takes a variable number of
27575 * arguments of mixed type and adds them to the toolbar.
27576 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
27578 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
27579 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
27580 * <li>Field: Any form field (equivalent to {@link #addField})</li>
27581 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
27582 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
27583 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
27584 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
27585 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
27586 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
27588 * @param {Mixed} arg2
27589 * @param {Mixed} etc.
27592 var a = arguments, l = a.length;
27593 for(var i = 0; i < l; i++){
27598 _add : function(el) {
27601 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
27604 if (el.applyTo){ // some kind of form field
27605 return this.addField(el);
27607 if (el.render){ // some kind of Toolbar.Item
27608 return this.addItem(el);
27610 if (typeof el == "string"){ // string
27611 if(el == "separator" || el == "-"){
27612 return this.addSeparator();
27615 return this.addSpacer();
27618 return this.addFill();
27620 return this.addText(el);
27623 if(el.tagName){ // element
27624 return this.addElement(el);
27626 if(typeof el == "object"){ // must be button config?
27627 return this.addButton(el);
27629 // and now what?!?!
27635 * Add an Xtype element
27636 * @param {Object} xtype Xtype Object
27637 * @return {Object} created Object
27639 addxtype : function(e){
27640 return this.add(e);
27644 * Returns the Element for this toolbar.
27645 * @return {Roo.Element}
27647 getEl : function(){
27653 * @return {Roo.Toolbar.Item} The separator item
27655 addSeparator : function(){
27656 return this.addItem(new Roo.Toolbar.Separator());
27660 * Adds a spacer element
27661 * @return {Roo.Toolbar.Spacer} The spacer item
27663 addSpacer : function(){
27664 return this.addItem(new Roo.Toolbar.Spacer());
27668 * Adds a fill element that forces subsequent additions to the right side of the toolbar
27669 * @return {Roo.Toolbar.Fill} The fill item
27671 addFill : function(){
27672 return this.addItem(new Roo.Toolbar.Fill());
27676 * Adds any standard HTML element to the toolbar
27677 * @param {String/HTMLElement/Element} el The element or id of the element to add
27678 * @return {Roo.Toolbar.Item} The element's item
27680 addElement : function(el){
27681 return this.addItem(new Roo.Toolbar.Item(el));
27684 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
27685 * @type Roo.util.MixedCollection
27690 * Adds any Toolbar.Item or subclass
27691 * @param {Roo.Toolbar.Item} item
27692 * @return {Roo.Toolbar.Item} The item
27694 addItem : function(item){
27695 var td = this.nextBlock();
27697 this.items.add(item);
27702 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
27703 * @param {Object/Array} config A button config or array of configs
27704 * @return {Roo.Toolbar.Button/Array}
27706 addButton : function(config){
27707 if(config instanceof Array){
27709 for(var i = 0, len = config.length; i < len; i++) {
27710 buttons.push(this.addButton(config[i]));
27715 if(!(config instanceof Roo.Toolbar.Button)){
27717 new Roo.Toolbar.SplitButton(config) :
27718 new Roo.Toolbar.Button(config);
27720 var td = this.nextBlock();
27727 * Adds text to the toolbar
27728 * @param {String} text The text to add
27729 * @return {Roo.Toolbar.Item} The element's item
27731 addText : function(text){
27732 return this.addItem(new Roo.Toolbar.TextItem(text));
27736 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
27737 * @param {Number} index The index where the item is to be inserted
27738 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
27739 * @return {Roo.Toolbar.Button/Item}
27741 insertButton : function(index, item){
27742 if(item instanceof Array){
27744 for(var i = 0, len = item.length; i < len; i++) {
27745 buttons.push(this.insertButton(index + i, item[i]));
27749 if (!(item instanceof Roo.Toolbar.Button)){
27750 item = new Roo.Toolbar.Button(item);
27752 var td = document.createElement("td");
27753 this.tr.insertBefore(td, this.tr.childNodes[index]);
27755 this.items.insert(index, item);
27760 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
27761 * @param {Object} config
27762 * @return {Roo.Toolbar.Item} The element's item
27764 addDom : function(config, returnEl){
27765 var td = this.nextBlock();
27766 Roo.DomHelper.overwrite(td, config);
27767 var ti = new Roo.Toolbar.Item(td.firstChild);
27769 this.items.add(ti);
27774 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
27775 * @type Roo.util.MixedCollection
27780 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
27781 * Note: the field should not have been rendered yet. For a field that has already been
27782 * rendered, use {@link #addElement}.
27783 * @param {Roo.form.Field} field
27784 * @return {Roo.ToolbarItem}
27788 addField : function(field) {
27789 if (!this.fields) {
27791 this.fields = new Roo.util.MixedCollection(false, function(o){
27792 return o.id || ("item" + (++autoId));
27797 var td = this.nextBlock();
27799 var ti = new Roo.Toolbar.Item(td.firstChild);
27801 this.items.add(ti);
27802 this.fields.add(field);
27813 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
27814 this.el.child('div').hide();
27822 this.el.child('div').show();
27826 nextBlock : function(){
27827 var td = document.createElement("td");
27828 this.tr.appendChild(td);
27833 destroy : function(){
27834 if(this.items){ // rendered?
27835 Roo.destroy.apply(Roo, this.items.items);
27837 if(this.fields){ // rendered?
27838 Roo.destroy.apply(Roo, this.fields.items);
27840 Roo.Element.uncache(this.el, this.tr);
27845 * @class Roo.Toolbar.Item
27846 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
27848 * Creates a new Item
27849 * @param {HTMLElement} el
27851 Roo.Toolbar.Item = function(el){
27852 this.el = Roo.getDom(el);
27853 this.id = Roo.id(this.el);
27854 this.hidden = false;
27857 Roo.Toolbar.Item.prototype = {
27860 * Get this item's HTML Element
27861 * @return {HTMLElement}
27863 getEl : function(){
27868 render : function(td){
27870 td.appendChild(this.el);
27874 * Removes and destroys this item.
27876 destroy : function(){
27877 this.td.parentNode.removeChild(this.td);
27884 this.hidden = false;
27885 this.td.style.display = "";
27892 this.hidden = true;
27893 this.td.style.display = "none";
27897 * Convenience function for boolean show/hide.
27898 * @param {Boolean} visible true to show/false to hide
27900 setVisible: function(visible){
27909 * Try to focus this item.
27911 focus : function(){
27912 Roo.fly(this.el).focus();
27916 * Disables this item.
27918 disable : function(){
27919 Roo.fly(this.td).addClass("x-item-disabled");
27920 this.disabled = true;
27921 this.el.disabled = true;
27925 * Enables this item.
27927 enable : function(){
27928 Roo.fly(this.td).removeClass("x-item-disabled");
27929 this.disabled = false;
27930 this.el.disabled = false;
27936 * @class Roo.Toolbar.Separator
27937 * @extends Roo.Toolbar.Item
27938 * A simple toolbar separator class
27940 * Creates a new Separator
27942 Roo.Toolbar.Separator = function(){
27943 var s = document.createElement("span");
27944 s.className = "ytb-sep";
27945 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
27947 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
27948 enable:Roo.emptyFn,
27949 disable:Roo.emptyFn,
27954 * @class Roo.Toolbar.Spacer
27955 * @extends Roo.Toolbar.Item
27956 * A simple element that adds extra horizontal space to a toolbar.
27958 * Creates a new Spacer
27960 Roo.Toolbar.Spacer = function(){
27961 var s = document.createElement("div");
27962 s.className = "ytb-spacer";
27963 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
27965 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
27966 enable:Roo.emptyFn,
27967 disable:Roo.emptyFn,
27972 * @class Roo.Toolbar.Fill
27973 * @extends Roo.Toolbar.Spacer
27974 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
27976 * Creates a new Spacer
27978 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
27980 render : function(td){
27981 td.style.width = '100%';
27982 Roo.Toolbar.Fill.superclass.render.call(this, td);
27987 * @class Roo.Toolbar.TextItem
27988 * @extends Roo.Toolbar.Item
27989 * A simple class that renders text directly into a toolbar.
27991 * Creates a new TextItem
27992 * @param {String} text
27994 Roo.Toolbar.TextItem = function(text){
27995 if (typeof(text) == 'object') {
27998 var s = document.createElement("span");
27999 s.className = "ytb-text";
28000 s.innerHTML = text;
28001 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28003 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28004 enable:Roo.emptyFn,
28005 disable:Roo.emptyFn,
28010 * @class Roo.Toolbar.Button
28011 * @extends Roo.Button
28012 * A button that renders into a toolbar.
28014 * Creates a new Button
28015 * @param {Object} config A standard {@link Roo.Button} config object
28017 Roo.Toolbar.Button = function(config){
28018 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28020 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28021 render : function(td){
28023 Roo.Toolbar.Button.superclass.render.call(this, td);
28027 * Removes and destroys this button
28029 destroy : function(){
28030 Roo.Toolbar.Button.superclass.destroy.call(this);
28031 this.td.parentNode.removeChild(this.td);
28035 * Shows this button
28038 this.hidden = false;
28039 this.td.style.display = "";
28043 * Hides this button
28046 this.hidden = true;
28047 this.td.style.display = "none";
28051 * Disables this item
28053 disable : function(){
28054 Roo.fly(this.td).addClass("x-item-disabled");
28055 this.disabled = true;
28059 * Enables this item
28061 enable : function(){
28062 Roo.fly(this.td).removeClass("x-item-disabled");
28063 this.disabled = false;
28066 // backwards compat
28067 Roo.ToolbarButton = Roo.Toolbar.Button;
28070 * @class Roo.Toolbar.SplitButton
28071 * @extends Roo.SplitButton
28072 * A menu button that renders into a toolbar.
28074 * Creates a new SplitButton
28075 * @param {Object} config A standard {@link Roo.SplitButton} config object
28077 Roo.Toolbar.SplitButton = function(config){
28078 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28080 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28081 render : function(td){
28083 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28087 * Removes and destroys this button
28089 destroy : function(){
28090 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28091 this.td.parentNode.removeChild(this.td);
28095 * Shows this button
28098 this.hidden = false;
28099 this.td.style.display = "";
28103 * Hides this button
28106 this.hidden = true;
28107 this.td.style.display = "none";
28111 // backwards compat
28112 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28114 * Ext JS Library 1.1.1
28115 * Copyright(c) 2006-2007, Ext JS, LLC.
28117 * Originally Released Under LGPL - original licence link has changed is not relivant.
28120 * <script type="text/javascript">
28124 * @class Roo.PagingToolbar
28125 * @extends Roo.Toolbar
28126 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28128 * Create a new PagingToolbar
28129 * @param {Object} config The config object
28131 Roo.PagingToolbar = function(el, ds, config)
28133 // old args format still supported... - xtype is prefered..
28134 if (typeof(el) == 'object' && el.xtype) {
28135 // created from xtype...
28137 ds = el.dataSource;
28138 el = config.container;
28141 if (config.items) {
28142 items = config.items;
28146 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28149 this.renderButtons(this.el);
28152 // supprot items array.
28154 Roo.each(items, function(e) {
28155 this.add(Roo.factory(e));
28160 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28162 * @cfg {Roo.data.Store} dataSource
28163 * The underlying data store providing the paged data
28166 * @cfg {String/HTMLElement/Element} container
28167 * container The id or element that will contain the toolbar
28170 * @cfg {Boolean} displayInfo
28171 * True to display the displayMsg (defaults to false)
28174 * @cfg {Number} pageSize
28175 * The number of records to display per page (defaults to 20)
28179 * @cfg {String} displayMsg
28180 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28182 displayMsg : 'Displaying {0} - {1} of {2}',
28184 * @cfg {String} emptyMsg
28185 * The message to display when no records are found (defaults to "No data to display")
28187 emptyMsg : 'No data to display',
28189 * Customizable piece of the default paging text (defaults to "Page")
28192 beforePageText : "Page",
28194 * Customizable piece of the default paging text (defaults to "of %0")
28197 afterPageText : "of {0}",
28199 * Customizable piece of the default paging text (defaults to "First Page")
28202 firstText : "First Page",
28204 * Customizable piece of the default paging text (defaults to "Previous Page")
28207 prevText : "Previous Page",
28209 * Customizable piece of the default paging text (defaults to "Next Page")
28212 nextText : "Next Page",
28214 * Customizable piece of the default paging text (defaults to "Last Page")
28217 lastText : "Last Page",
28219 * Customizable piece of the default paging text (defaults to "Refresh")
28222 refreshText : "Refresh",
28225 renderButtons : function(el){
28226 Roo.PagingToolbar.superclass.render.call(this, el);
28227 this.first = this.addButton({
28228 tooltip: this.firstText,
28229 cls: "x-btn-icon x-grid-page-first",
28231 handler: this.onClick.createDelegate(this, ["first"])
28233 this.prev = this.addButton({
28234 tooltip: this.prevText,
28235 cls: "x-btn-icon x-grid-page-prev",
28237 handler: this.onClick.createDelegate(this, ["prev"])
28239 //this.addSeparator();
28240 this.add(this.beforePageText);
28241 this.field = Roo.get(this.addDom({
28246 cls: "x-grid-page-number"
28248 this.field.on("keydown", this.onPagingKeydown, this);
28249 this.field.on("focus", function(){this.dom.select();});
28250 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28251 this.field.setHeight(18);
28252 //this.addSeparator();
28253 this.next = this.addButton({
28254 tooltip: this.nextText,
28255 cls: "x-btn-icon x-grid-page-next",
28257 handler: this.onClick.createDelegate(this, ["next"])
28259 this.last = this.addButton({
28260 tooltip: this.lastText,
28261 cls: "x-btn-icon x-grid-page-last",
28263 handler: this.onClick.createDelegate(this, ["last"])
28265 //this.addSeparator();
28266 this.loading = this.addButton({
28267 tooltip: this.refreshText,
28268 cls: "x-btn-icon x-grid-loading",
28269 handler: this.onClick.createDelegate(this, ["refresh"])
28272 if(this.displayInfo){
28273 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28278 updateInfo : function(){
28279 if(this.displayEl){
28280 var count = this.ds.getCount();
28281 var msg = count == 0 ?
28285 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28287 this.displayEl.update(msg);
28292 onLoad : function(ds, r, o){
28293 this.cursor = o.params ? o.params.start : 0;
28294 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28296 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28297 this.field.dom.value = ap;
28298 this.first.setDisabled(ap == 1);
28299 this.prev.setDisabled(ap == 1);
28300 this.next.setDisabled(ap == ps);
28301 this.last.setDisabled(ap == ps);
28302 this.loading.enable();
28307 getPageData : function(){
28308 var total = this.ds.getTotalCount();
28311 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28312 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28317 onLoadError : function(){
28318 this.loading.enable();
28322 onPagingKeydown : function(e){
28323 var k = e.getKey();
28324 var d = this.getPageData();
28326 var v = this.field.dom.value, pageNum;
28327 if(!v || isNaN(pageNum = parseInt(v, 10))){
28328 this.field.dom.value = d.activePage;
28331 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28332 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28335 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))
28337 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28338 this.field.dom.value = pageNum;
28339 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28342 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28344 var v = this.field.dom.value, pageNum;
28345 var increment = (e.shiftKey) ? 10 : 1;
28346 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28348 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28349 this.field.dom.value = d.activePage;
28352 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28354 this.field.dom.value = parseInt(v, 10) + increment;
28355 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28356 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28363 beforeLoad : function(){
28365 this.loading.disable();
28370 onClick : function(which){
28374 ds.load({params:{start: 0, limit: this.pageSize}});
28377 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28380 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28383 var total = ds.getTotalCount();
28384 var extra = total % this.pageSize;
28385 var lastStart = extra ? (total - extra) : total-this.pageSize;
28386 ds.load({params:{start: lastStart, limit: this.pageSize}});
28389 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28395 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28396 * @param {Roo.data.Store} store The data store to unbind
28398 unbind : function(ds){
28399 ds.un("beforeload", this.beforeLoad, this);
28400 ds.un("load", this.onLoad, this);
28401 ds.un("loadexception", this.onLoadError, this);
28402 ds.un("remove", this.updateInfo, this);
28403 ds.un("add", this.updateInfo, this);
28404 this.ds = undefined;
28408 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28409 * @param {Roo.data.Store} store The data store to bind
28411 bind : function(ds){
28412 ds.on("beforeload", this.beforeLoad, this);
28413 ds.on("load", this.onLoad, this);
28414 ds.on("loadexception", this.onLoadError, this);
28415 ds.on("remove", this.updateInfo, this);
28416 ds.on("add", this.updateInfo, this);
28421 * Ext JS Library 1.1.1
28422 * Copyright(c) 2006-2007, Ext JS, LLC.
28424 * Originally Released Under LGPL - original licence link has changed is not relivant.
28427 * <script type="text/javascript">
28431 * @class Roo.Resizable
28432 * @extends Roo.util.Observable
28433 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28434 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28435 * 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
28436 * the element will be wrapped for you automatically.</p>
28437 * <p>Here is the list of valid resize handles:</p>
28440 ------ -------------------
28449 'hd' horizontal drag
28452 * <p>Here's an example showing the creation of a typical Resizable:</p>
28454 var resizer = new Roo.Resizable("element-id", {
28462 resizer.on("resize", myHandler);
28464 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28465 * resizer.east.setDisplayed(false);</p>
28466 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28467 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28468 * resize operation's new size (defaults to [0, 0])
28469 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28470 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28471 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28472 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28473 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28474 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28475 * @cfg {Number} width The width of the element in pixels (defaults to null)
28476 * @cfg {Number} height The height of the element in pixels (defaults to null)
28477 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28478 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28479 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28480 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28481 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28482 * in favor of the handles config option (defaults to false)
28483 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28484 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28485 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28486 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28487 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28488 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28489 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28490 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28491 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28492 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28493 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28495 * Create a new resizable component
28496 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
28497 * @param {Object} config configuration options
28499 Roo.Resizable = function(el, config)
28501 this.el = Roo.get(el);
28503 if(config && config.wrap){
28504 config.resizeChild = this.el;
28505 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
28506 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
28507 this.el.setStyle("overflow", "hidden");
28508 this.el.setPositioning(config.resizeChild.getPositioning());
28509 config.resizeChild.clearPositioning();
28510 if(!config.width || !config.height){
28511 var csize = config.resizeChild.getSize();
28512 this.el.setSize(csize.width, csize.height);
28514 if(config.pinned && !config.adjustments){
28515 config.adjustments = "auto";
28519 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
28520 this.proxy.unselectable();
28521 this.proxy.enableDisplayMode('block');
28523 Roo.apply(this, config);
28526 this.disableTrackOver = true;
28527 this.el.addClass("x-resizable-pinned");
28529 // if the element isn't positioned, make it relative
28530 var position = this.el.getStyle("position");
28531 if(position != "absolute" && position != "fixed"){
28532 this.el.setStyle("position", "relative");
28534 if(!this.handles){ // no handles passed, must be legacy style
28535 this.handles = 's,e,se';
28536 if(this.multiDirectional){
28537 this.handles += ',n,w';
28540 if(this.handles == "all"){
28541 this.handles = "n s e w ne nw se sw";
28543 var hs = this.handles.split(/\s*?[,;]\s*?| /);
28544 var ps = Roo.Resizable.positions;
28545 for(var i = 0, len = hs.length; i < len; i++){
28546 if(hs[i] && ps[hs[i]]){
28547 var pos = ps[hs[i]];
28548 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
28552 this.corner = this.southeast;
28554 // updateBox = the box can move..
28555 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
28556 this.updateBox = true;
28559 this.activeHandle = null;
28561 if(this.resizeChild){
28562 if(typeof this.resizeChild == "boolean"){
28563 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
28565 this.resizeChild = Roo.get(this.resizeChild, true);
28569 if(this.adjustments == "auto"){
28570 var rc = this.resizeChild;
28571 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
28572 if(rc && (hw || hn)){
28573 rc.position("relative");
28574 rc.setLeft(hw ? hw.el.getWidth() : 0);
28575 rc.setTop(hn ? hn.el.getHeight() : 0);
28577 this.adjustments = [
28578 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
28579 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
28583 if(this.draggable){
28584 this.dd = this.dynamic ?
28585 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
28586 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
28592 * @event beforeresize
28593 * Fired before resize is allowed. Set enabled to false to cancel resize.
28594 * @param {Roo.Resizable} this
28595 * @param {Roo.EventObject} e The mousedown event
28597 "beforeresize" : true,
28600 * Fired after a resize.
28601 * @param {Roo.Resizable} this
28602 * @param {Number} width The new width
28603 * @param {Number} height The new height
28604 * @param {Roo.EventObject} e The mouseup event
28609 if(this.width !== null && this.height !== null){
28610 this.resizeTo(this.width, this.height);
28612 this.updateChildSize();
28615 this.el.dom.style.zoom = 1;
28617 Roo.Resizable.superclass.constructor.call(this);
28620 Roo.extend(Roo.Resizable, Roo.util.Observable, {
28621 resizeChild : false,
28622 adjustments : [0, 0],
28632 multiDirectional : false,
28633 disableTrackOver : false,
28634 easing : 'easeOutStrong',
28635 widthIncrement : 0,
28636 heightIncrement : 0,
28640 preserveRatio : false,
28641 transparent: false,
28647 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
28649 constrainTo: undefined,
28651 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
28653 resizeRegion: undefined,
28657 * Perform a manual resize
28658 * @param {Number} width
28659 * @param {Number} height
28661 resizeTo : function(width, height){
28662 this.el.setSize(width, height);
28663 this.updateChildSize();
28664 this.fireEvent("resize", this, width, height, null);
28668 startSizing : function(e, handle){
28669 this.fireEvent("beforeresize", this, e);
28670 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
28673 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
28674 this.overlay.unselectable();
28675 this.overlay.enableDisplayMode("block");
28676 this.overlay.on("mousemove", this.onMouseMove, this);
28677 this.overlay.on("mouseup", this.onMouseUp, this);
28679 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
28681 this.resizing = true;
28682 this.startBox = this.el.getBox();
28683 this.startPoint = e.getXY();
28684 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
28685 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
28687 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
28688 this.overlay.show();
28690 if(this.constrainTo) {
28691 var ct = Roo.get(this.constrainTo);
28692 this.resizeRegion = ct.getRegion().adjust(
28693 ct.getFrameWidth('t'),
28694 ct.getFrameWidth('l'),
28695 -ct.getFrameWidth('b'),
28696 -ct.getFrameWidth('r')
28700 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
28702 this.proxy.setBox(this.startBox);
28704 this.proxy.setStyle('visibility', 'visible');
28710 onMouseDown : function(handle, e){
28713 this.activeHandle = handle;
28714 this.startSizing(e, handle);
28719 onMouseUp : function(e){
28720 var size = this.resizeElement();
28721 this.resizing = false;
28723 this.overlay.hide();
28725 this.fireEvent("resize", this, size.width, size.height, e);
28729 updateChildSize : function(){
28731 if(this.resizeChild){
28733 var child = this.resizeChild;
28734 var adj = this.adjustments;
28735 if(el.dom.offsetWidth){
28736 var b = el.getSize(true);
28737 child.setSize(b.width+adj[0], b.height+adj[1]);
28739 // Second call here for IE
28740 // The first call enables instant resizing and
28741 // the second call corrects scroll bars if they
28744 setTimeout(function(){
28745 if(el.dom.offsetWidth){
28746 var b = el.getSize(true);
28747 child.setSize(b.width+adj[0], b.height+adj[1]);
28755 snap : function(value, inc, min){
28756 if(!inc || !value) return value;
28757 var newValue = value;
28758 var m = value % inc;
28761 newValue = value + (inc-m);
28763 newValue = value - m;
28766 return Math.max(min, newValue);
28770 resizeElement : function(){
28771 var box = this.proxy.getBox();
28772 if(this.updateBox){
28773 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
28775 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
28777 this.updateChildSize();
28785 constrain : function(v, diff, m, mx){
28788 }else if(v - diff > mx){
28795 onMouseMove : function(e){
28797 try{// try catch so if something goes wrong the user doesn't get hung
28799 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
28803 //var curXY = this.startPoint;
28804 var curSize = this.curSize || this.startBox;
28805 var x = this.startBox.x, y = this.startBox.y;
28806 var ox = x, oy = y;
28807 var w = curSize.width, h = curSize.height;
28808 var ow = w, oh = h;
28809 var mw = this.minWidth, mh = this.minHeight;
28810 var mxw = this.maxWidth, mxh = this.maxHeight;
28811 var wi = this.widthIncrement;
28812 var hi = this.heightIncrement;
28814 var eventXY = e.getXY();
28815 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
28816 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
28818 var pos = this.activeHandle.position;
28823 w = Math.min(Math.max(mw, w), mxw);
28828 h = Math.min(Math.max(mh, h), mxh);
28833 w = Math.min(Math.max(mw, w), mxw);
28834 h = Math.min(Math.max(mh, h), mxh);
28837 diffY = this.constrain(h, diffY, mh, mxh);
28844 var adiffX = Math.abs(diffX);
28845 var sub = (adiffX % wi); // how much
28846 if (sub > (wi/2)) { // far enough to snap
28847 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
28849 // remove difference..
28850 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
28854 x = Math.max(this.minX, x);
28857 diffX = this.constrain(w, diffX, mw, mxw);
28863 w = Math.min(Math.max(mw, w), mxw);
28864 diffY = this.constrain(h, diffY, mh, mxh);
28869 diffX = this.constrain(w, diffX, mw, mxw);
28870 diffY = this.constrain(h, diffY, mh, mxh);
28877 diffX = this.constrain(w, diffX, mw, mxw);
28879 h = Math.min(Math.max(mh, h), mxh);
28885 var sw = this.snap(w, wi, mw);
28886 var sh = this.snap(h, hi, mh);
28887 if(sw != w || sh != h){
28910 if(this.preserveRatio){
28915 h = Math.min(Math.max(mh, h), mxh);
28920 w = Math.min(Math.max(mw, w), mxw);
28925 w = Math.min(Math.max(mw, w), mxw);
28931 w = Math.min(Math.max(mw, w), mxw);
28937 h = Math.min(Math.max(mh, h), mxh);
28945 h = Math.min(Math.max(mh, h), mxh);
28955 h = Math.min(Math.max(mh, h), mxh);
28963 if (pos == 'hdrag') {
28966 this.proxy.setBounds(x, y, w, h);
28968 this.resizeElement();
28975 handleOver : function(){
28977 this.el.addClass("x-resizable-over");
28982 handleOut : function(){
28983 if(!this.resizing){
28984 this.el.removeClass("x-resizable-over");
28989 * Returns the element this component is bound to.
28990 * @return {Roo.Element}
28992 getEl : function(){
28997 * Returns the resizeChild element (or null).
28998 * @return {Roo.Element}
29000 getResizeChild : function(){
29001 return this.resizeChild;
29003 groupHandler : function()
29008 * Destroys this resizable. If the element was wrapped and
29009 * removeEl is not true then the element remains.
29010 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29012 destroy : function(removeEl){
29013 this.proxy.remove();
29015 this.overlay.removeAllListeners();
29016 this.overlay.remove();
29018 var ps = Roo.Resizable.positions;
29020 if(typeof ps[k] != "function" && this[ps[k]]){
29021 var h = this[ps[k]];
29022 h.el.removeAllListeners();
29027 this.el.update("");
29034 // hash to map config positions to true positions
29035 Roo.Resizable.positions = {
29036 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29041 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29043 // only initialize the template if resizable is used
29044 var tpl = Roo.DomHelper.createTemplate(
29045 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29048 Roo.Resizable.Handle.prototype.tpl = tpl;
29050 this.position = pos;
29052 // show north drag fro topdra
29053 var handlepos = pos == 'hdrag' ? 'north' : pos;
29055 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29056 if (pos == 'hdrag') {
29057 this.el.setStyle('cursor', 'pointer');
29059 this.el.unselectable();
29061 this.el.setOpacity(0);
29063 this.el.on("mousedown", this.onMouseDown, this);
29064 if(!disableTrackOver){
29065 this.el.on("mouseover", this.onMouseOver, this);
29066 this.el.on("mouseout", this.onMouseOut, this);
29071 Roo.Resizable.Handle.prototype = {
29072 afterResize : function(rz){
29076 onMouseDown : function(e){
29077 this.rz.onMouseDown(this, e);
29080 onMouseOver : function(e){
29081 this.rz.handleOver(this, e);
29084 onMouseOut : function(e){
29085 this.rz.handleOut(this, e);
29089 * Ext JS Library 1.1.1
29090 * Copyright(c) 2006-2007, Ext JS, LLC.
29092 * Originally Released Under LGPL - original licence link has changed is not relivant.
29095 * <script type="text/javascript">
29099 * @class Roo.Editor
29100 * @extends Roo.Component
29101 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29103 * Create a new Editor
29104 * @param {Roo.form.Field} field The Field object (or descendant)
29105 * @param {Object} config The config object
29107 Roo.Editor = function(field, config){
29108 Roo.Editor.superclass.constructor.call(this, config);
29109 this.field = field;
29112 * @event beforestartedit
29113 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29114 * false from the handler of this event.
29115 * @param {Editor} this
29116 * @param {Roo.Element} boundEl The underlying element bound to this editor
29117 * @param {Mixed} value The field value being set
29119 "beforestartedit" : true,
29122 * Fires when this editor is displayed
29123 * @param {Roo.Element} boundEl The underlying element bound to this editor
29124 * @param {Mixed} value The starting field value
29126 "startedit" : true,
29128 * @event beforecomplete
29129 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29130 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29131 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29132 * event will not fire since no edit actually occurred.
29133 * @param {Editor} this
29134 * @param {Mixed} value The current field value
29135 * @param {Mixed} startValue The original field value
29137 "beforecomplete" : true,
29140 * Fires after editing is complete and any changed value has been written to the underlying field.
29141 * @param {Editor} this
29142 * @param {Mixed} value The current field value
29143 * @param {Mixed} startValue The original field value
29147 * @event specialkey
29148 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29149 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29150 * @param {Roo.form.Field} this
29151 * @param {Roo.EventObject} e The event object
29153 "specialkey" : true
29157 Roo.extend(Roo.Editor, Roo.Component, {
29159 * @cfg {Boolean/String} autosize
29160 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29161 * or "height" to adopt the height only (defaults to false)
29164 * @cfg {Boolean} revertInvalid
29165 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29166 * validation fails (defaults to true)
29169 * @cfg {Boolean} ignoreNoChange
29170 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29171 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29172 * will never be ignored.
29175 * @cfg {Boolean} hideEl
29176 * False to keep the bound element visible while the editor is displayed (defaults to true)
29179 * @cfg {Mixed} value
29180 * The data value of the underlying field (defaults to "")
29184 * @cfg {String} alignment
29185 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29189 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29190 * for bottom-right shadow (defaults to "frame")
29194 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29198 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29200 completeOnEnter : false,
29202 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29204 cancelOnEsc : false,
29206 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29211 onRender : function(ct, position){
29212 this.el = new Roo.Layer({
29213 shadow: this.shadow,
29219 constrain: this.constrain
29221 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29222 if(this.field.msgTarget != 'title'){
29223 this.field.msgTarget = 'qtip';
29225 this.field.render(this.el);
29227 this.field.el.dom.setAttribute('autocomplete', 'off');
29229 this.field.on("specialkey", this.onSpecialKey, this);
29230 if(this.swallowKeys){
29231 this.field.el.swallowEvent(['keydown','keypress']);
29234 this.field.on("blur", this.onBlur, this);
29235 if(this.field.grow){
29236 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29240 onSpecialKey : function(field, e)
29242 //Roo.log('editor onSpecialKey');
29243 if(this.completeOnEnter && e.getKey() == e.ENTER){
29245 this.completeEdit();
29248 // do not fire special key otherwise it might hide close the editor...
29249 if(e.getKey() == e.ENTER){
29252 if(this.cancelOnEsc && e.getKey() == e.ESC){
29256 this.fireEvent('specialkey', field, e);
29261 * Starts the editing process and shows the editor.
29262 * @param {String/HTMLElement/Element} el The element to edit
29263 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29264 * to the innerHTML of el.
29266 startEdit : function(el, value){
29268 this.completeEdit();
29270 this.boundEl = Roo.get(el);
29271 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29272 if(!this.rendered){
29273 this.render(this.parentEl || document.body);
29275 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29278 this.startValue = v;
29279 this.field.setValue(v);
29281 var sz = this.boundEl.getSize();
29282 switch(this.autoSize){
29284 this.setSize(sz.width, "");
29287 this.setSize("", sz.height);
29290 this.setSize(sz.width, sz.height);
29293 this.el.alignTo(this.boundEl, this.alignment);
29294 this.editing = true;
29296 Roo.QuickTips.disable();
29302 * Sets the height and width of this editor.
29303 * @param {Number} width The new width
29304 * @param {Number} height The new height
29306 setSize : function(w, h){
29307 this.field.setSize(w, h);
29314 * Realigns the editor to the bound field based on the current alignment config value.
29316 realign : function(){
29317 this.el.alignTo(this.boundEl, this.alignment);
29321 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29322 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29324 completeEdit : function(remainVisible){
29328 var v = this.getValue();
29329 if(this.revertInvalid !== false && !this.field.isValid()){
29330 v = this.startValue;
29331 this.cancelEdit(true);
29333 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29334 this.editing = false;
29338 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29339 this.editing = false;
29340 if(this.updateEl && this.boundEl){
29341 this.boundEl.update(v);
29343 if(remainVisible !== true){
29346 this.fireEvent("complete", this, v, this.startValue);
29351 onShow : function(){
29353 if(this.hideEl !== false){
29354 this.boundEl.hide();
29357 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29358 this.fixIEFocus = true;
29359 this.deferredFocus.defer(50, this);
29361 this.field.focus();
29363 this.fireEvent("startedit", this.boundEl, this.startValue);
29366 deferredFocus : function(){
29368 this.field.focus();
29373 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29374 * reverted to the original starting value.
29375 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29376 * cancel (defaults to false)
29378 cancelEdit : function(remainVisible){
29380 this.setValue(this.startValue);
29381 if(remainVisible !== true){
29388 onBlur : function(){
29389 if(this.allowBlur !== true && this.editing){
29390 this.completeEdit();
29395 onHide : function(){
29397 this.completeEdit();
29401 if(this.field.collapse){
29402 this.field.collapse();
29405 if(this.hideEl !== false){
29406 this.boundEl.show();
29409 Roo.QuickTips.enable();
29414 * Sets the data value of the editor
29415 * @param {Mixed} value Any valid value supported by the underlying field
29417 setValue : function(v){
29418 this.field.setValue(v);
29422 * Gets the data value of the editor
29423 * @return {Mixed} The data value
29425 getValue : function(){
29426 return this.field.getValue();
29430 * Ext JS Library 1.1.1
29431 * Copyright(c) 2006-2007, Ext JS, LLC.
29433 * Originally Released Under LGPL - original licence link has changed is not relivant.
29436 * <script type="text/javascript">
29440 * @class Roo.BasicDialog
29441 * @extends Roo.util.Observable
29442 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29444 var dlg = new Roo.BasicDialog("my-dlg", {
29453 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29454 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29455 dlg.addButton('Cancel', dlg.hide, dlg);
29458 <b>A Dialog should always be a direct child of the body element.</b>
29459 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29460 * @cfg {String} title Default text to display in the title bar (defaults to null)
29461 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29462 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29463 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29464 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29465 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29466 * (defaults to null with no animation)
29467 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29468 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29469 * property for valid values (defaults to 'all')
29470 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29471 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29472 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29473 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29474 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29475 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29476 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29477 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29478 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29479 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29480 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29481 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
29482 * draggable = true (defaults to false)
29483 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
29484 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
29485 * shadow (defaults to false)
29486 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
29487 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
29488 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
29489 * @cfg {Array} buttons Array of buttons
29490 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
29492 * Create a new BasicDialog.
29493 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
29494 * @param {Object} config Configuration options
29496 Roo.BasicDialog = function(el, config){
29497 this.el = Roo.get(el);
29498 var dh = Roo.DomHelper;
29499 if(!this.el && config && config.autoCreate){
29500 if(typeof config.autoCreate == "object"){
29501 if(!config.autoCreate.id){
29502 config.autoCreate.id = el;
29504 this.el = dh.append(document.body,
29505 config.autoCreate, true);
29507 this.el = dh.append(document.body,
29508 {tag: "div", id: el, style:'visibility:hidden;'}, true);
29512 el.setDisplayed(true);
29513 el.hide = this.hideAction;
29515 el.addClass("x-dlg");
29517 Roo.apply(this, config);
29519 this.proxy = el.createProxy("x-dlg-proxy");
29520 this.proxy.hide = this.hideAction;
29521 this.proxy.setOpacity(.5);
29525 el.setWidth(config.width);
29528 el.setHeight(config.height);
29530 this.size = el.getSize();
29531 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
29532 this.xy = [config.x,config.y];
29534 this.xy = el.getCenterXY(true);
29536 /** The header element @type Roo.Element */
29537 this.header = el.child("> .x-dlg-hd");
29538 /** The body element @type Roo.Element */
29539 this.body = el.child("> .x-dlg-bd");
29540 /** The footer element @type Roo.Element */
29541 this.footer = el.child("> .x-dlg-ft");
29544 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
29547 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
29550 this.header.unselectable();
29552 this.header.update(this.title);
29554 // this element allows the dialog to be focused for keyboard event
29555 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
29556 this.focusEl.swallowEvent("click", true);
29558 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
29560 // wrap the body and footer for special rendering
29561 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
29563 this.bwrap.dom.appendChild(this.footer.dom);
29566 this.bg = this.el.createChild({
29567 tag: "div", cls:"x-dlg-bg",
29568 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
29570 this.centerBg = this.bg.child("div.x-dlg-bg-center");
29573 if(this.autoScroll !== false && !this.autoTabs){
29574 this.body.setStyle("overflow", "auto");
29577 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
29579 if(this.closable !== false){
29580 this.el.addClass("x-dlg-closable");
29581 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
29582 this.close.on("click", this.closeClick, this);
29583 this.close.addClassOnOver("x-dlg-close-over");
29585 if(this.collapsible !== false){
29586 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
29587 this.collapseBtn.on("click", this.collapseClick, this);
29588 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
29589 this.header.on("dblclick", this.collapseClick, this);
29591 if(this.resizable !== false){
29592 this.el.addClass("x-dlg-resizable");
29593 this.resizer = new Roo.Resizable(el, {
29594 minWidth: this.minWidth || 80,
29595 minHeight:this.minHeight || 80,
29596 handles: this.resizeHandles || "all",
29599 this.resizer.on("beforeresize", this.beforeResize, this);
29600 this.resizer.on("resize", this.onResize, this);
29602 if(this.draggable !== false){
29603 el.addClass("x-dlg-draggable");
29604 if (!this.proxyDrag) {
29605 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
29608 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
29610 dd.setHandleElId(this.header.id);
29611 dd.endDrag = this.endMove.createDelegate(this);
29612 dd.startDrag = this.startMove.createDelegate(this);
29613 dd.onDrag = this.onDrag.createDelegate(this);
29618 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
29619 this.mask.enableDisplayMode("block");
29621 this.el.addClass("x-dlg-modal");
29624 this.shadow = new Roo.Shadow({
29625 mode : typeof this.shadow == "string" ? this.shadow : "sides",
29626 offset : this.shadowOffset
29629 this.shadowOffset = 0;
29631 if(Roo.useShims && this.shim !== false){
29632 this.shim = this.el.createShim();
29633 this.shim.hide = this.hideAction;
29641 if (this.buttons) {
29642 var bts= this.buttons;
29644 Roo.each(bts, function(b) {
29653 * Fires when a key is pressed
29654 * @param {Roo.BasicDialog} this
29655 * @param {Roo.EventObject} e
29660 * Fires when this dialog is moved by the user.
29661 * @param {Roo.BasicDialog} this
29662 * @param {Number} x The new page X
29663 * @param {Number} y The new page Y
29668 * Fires when this dialog is resized by the user.
29669 * @param {Roo.BasicDialog} this
29670 * @param {Number} width The new width
29671 * @param {Number} height The new height
29675 * @event beforehide
29676 * Fires before this dialog is hidden.
29677 * @param {Roo.BasicDialog} this
29679 "beforehide" : true,
29682 * Fires when this dialog is hidden.
29683 * @param {Roo.BasicDialog} this
29687 * @event beforeshow
29688 * Fires before this dialog is shown.
29689 * @param {Roo.BasicDialog} this
29691 "beforeshow" : true,
29694 * Fires when this dialog is shown.
29695 * @param {Roo.BasicDialog} this
29699 el.on("keydown", this.onKeyDown, this);
29700 el.on("mousedown", this.toFront, this);
29701 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
29703 Roo.DialogManager.register(this);
29704 Roo.BasicDialog.superclass.constructor.call(this);
29707 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
29708 shadowOffset: Roo.isIE ? 6 : 5,
29711 minButtonWidth: 75,
29712 defaultButton: null,
29713 buttonAlign: "right",
29718 * Sets the dialog title text
29719 * @param {String} text The title text to display
29720 * @return {Roo.BasicDialog} this
29722 setTitle : function(text){
29723 this.header.update(text);
29728 closeClick : function(){
29733 collapseClick : function(){
29734 this[this.collapsed ? "expand" : "collapse"]();
29738 * Collapses the dialog to its minimized state (only the title bar is visible).
29739 * Equivalent to the user clicking the collapse dialog button.
29741 collapse : function(){
29742 if(!this.collapsed){
29743 this.collapsed = true;
29744 this.el.addClass("x-dlg-collapsed");
29745 this.restoreHeight = this.el.getHeight();
29746 this.resizeTo(this.el.getWidth(), this.header.getHeight());
29751 * Expands a collapsed dialog back to its normal state. Equivalent to the user
29752 * clicking the expand dialog button.
29754 expand : function(){
29755 if(this.collapsed){
29756 this.collapsed = false;
29757 this.el.removeClass("x-dlg-collapsed");
29758 this.resizeTo(this.el.getWidth(), this.restoreHeight);
29763 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
29764 * @return {Roo.TabPanel} The tabs component
29766 initTabs : function(){
29767 var tabs = this.getTabs();
29768 while(tabs.getTab(0)){
29771 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
29773 tabs.addTab(Roo.id(dom), dom.title);
29781 beforeResize : function(){
29782 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
29786 onResize : function(){
29787 this.refreshSize();
29788 this.syncBodyHeight();
29789 this.adjustAssets();
29791 this.fireEvent("resize", this, this.size.width, this.size.height);
29795 onKeyDown : function(e){
29796 if(this.isVisible()){
29797 this.fireEvent("keydown", this, e);
29802 * Resizes the dialog.
29803 * @param {Number} width
29804 * @param {Number} height
29805 * @return {Roo.BasicDialog} this
29807 resizeTo : function(width, height){
29808 this.el.setSize(width, height);
29809 this.size = {width: width, height: height};
29810 this.syncBodyHeight();
29811 if(this.fixedcenter){
29814 if(this.isVisible()){
29815 this.constrainXY();
29816 this.adjustAssets();
29818 this.fireEvent("resize", this, width, height);
29824 * Resizes the dialog to fit the specified content size.
29825 * @param {Number} width
29826 * @param {Number} height
29827 * @return {Roo.BasicDialog} this
29829 setContentSize : function(w, h){
29830 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
29831 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
29832 //if(!this.el.isBorderBox()){
29833 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
29834 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
29837 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
29838 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
29840 this.resizeTo(w, h);
29845 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
29846 * executed in response to a particular key being pressed while the dialog is active.
29847 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
29848 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
29849 * @param {Function} fn The function to call
29850 * @param {Object} scope (optional) The scope of the function
29851 * @return {Roo.BasicDialog} this
29853 addKeyListener : function(key, fn, scope){
29854 var keyCode, shift, ctrl, alt;
29855 if(typeof key == "object" && !(key instanceof Array)){
29856 keyCode = key["key"];
29857 shift = key["shift"];
29858 ctrl = key["ctrl"];
29863 var handler = function(dlg, e){
29864 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
29865 var k = e.getKey();
29866 if(keyCode instanceof Array){
29867 for(var i = 0, len = keyCode.length; i < len; i++){
29868 if(keyCode[i] == k){
29869 fn.call(scope || window, dlg, k, e);
29875 fn.call(scope || window, dlg, k, e);
29880 this.on("keydown", handler);
29885 * Returns the TabPanel component (creates it if it doesn't exist).
29886 * Note: If you wish to simply check for the existence of tabs without creating them,
29887 * check for a null 'tabs' property.
29888 * @return {Roo.TabPanel} The tabs component
29890 getTabs : function(){
29892 this.el.addClass("x-dlg-auto-tabs");
29893 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
29894 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
29900 * Adds a button to the footer section of the dialog.
29901 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
29902 * object or a valid Roo.DomHelper element config
29903 * @param {Function} handler The function called when the button is clicked
29904 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
29905 * @return {Roo.Button} The new button
29907 addButton : function(config, handler, scope){
29908 var dh = Roo.DomHelper;
29910 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
29912 if(!this.btnContainer){
29913 var tb = this.footer.createChild({
29915 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
29916 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
29918 this.btnContainer = tb.firstChild.firstChild.firstChild;
29923 minWidth: this.minButtonWidth,
29926 if(typeof config == "string"){
29927 bconfig.text = config;
29930 bconfig.dhconfig = config;
29932 Roo.apply(bconfig, config);
29936 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
29937 bconfig.position = Math.max(0, bconfig.position);
29938 fc = this.btnContainer.childNodes[bconfig.position];
29941 var btn = new Roo.Button(
29943 this.btnContainer.insertBefore(document.createElement("td"),fc)
29944 : this.btnContainer.appendChild(document.createElement("td")),
29945 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
29948 this.syncBodyHeight();
29951 * Array of all the buttons that have been added to this dialog via addButton
29956 this.buttons.push(btn);
29961 * Sets the default button to be focused when the dialog is displayed.
29962 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
29963 * @return {Roo.BasicDialog} this
29965 setDefaultButton : function(btn){
29966 this.defaultButton = btn;
29971 getHeaderFooterHeight : function(safe){
29974 height += this.header.getHeight();
29977 var fm = this.footer.getMargins();
29978 height += (this.footer.getHeight()+fm.top+fm.bottom);
29980 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
29981 height += this.centerBg.getPadding("tb");
29986 syncBodyHeight : function()
29988 var bd = this.body, // the text
29989 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
29991 var height = this.size.height - this.getHeaderFooterHeight(false);
29992 bd.setHeight(height-bd.getMargins("tb"));
29993 var hh = this.header.getHeight();
29994 var h = this.size.height-hh;
29997 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
29998 bw.setHeight(h-cb.getPadding("tb"));
30000 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30001 bd.setWidth(bw.getWidth(true));
30003 this.tabs.syncHeight();
30005 this.tabs.el.repaint();
30011 * Restores the previous state of the dialog if Roo.state is configured.
30012 * @return {Roo.BasicDialog} this
30014 restoreState : function(){
30015 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30016 if(box && box.width){
30017 this.xy = [box.x, box.y];
30018 this.resizeTo(box.width, box.height);
30024 beforeShow : function(){
30026 if(this.fixedcenter){
30027 this.xy = this.el.getCenterXY(true);
30030 Roo.get(document.body).addClass("x-body-masked");
30031 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30034 this.constrainXY();
30038 animShow : function(){
30039 var b = Roo.get(this.animateTarget).getBox();
30040 this.proxy.setSize(b.width, b.height);
30041 this.proxy.setLocation(b.x, b.y);
30043 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30044 true, .35, this.showEl.createDelegate(this));
30048 * Shows the dialog.
30049 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30050 * @return {Roo.BasicDialog} this
30052 show : function(animateTarget){
30053 if (this.fireEvent("beforeshow", this) === false){
30056 if(this.syncHeightBeforeShow){
30057 this.syncBodyHeight();
30058 }else if(this.firstShow){
30059 this.firstShow = false;
30060 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30062 this.animateTarget = animateTarget || this.animateTarget;
30063 if(!this.el.isVisible()){
30065 if(this.animateTarget && Roo.get(this.animateTarget)){
30075 showEl : function(){
30077 this.el.setXY(this.xy);
30079 this.adjustAssets(true);
30082 // IE peekaboo bug - fix found by Dave Fenwick
30086 this.fireEvent("show", this);
30090 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30091 * dialog itself will receive focus.
30093 focus : function(){
30094 if(this.defaultButton){
30095 this.defaultButton.focus();
30097 this.focusEl.focus();
30102 constrainXY : function(){
30103 if(this.constraintoviewport !== false){
30104 if(!this.viewSize){
30105 if(this.container){
30106 var s = this.container.getSize();
30107 this.viewSize = [s.width, s.height];
30109 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30112 var s = Roo.get(this.container||document).getScroll();
30114 var x = this.xy[0], y = this.xy[1];
30115 var w = this.size.width, h = this.size.height;
30116 var vw = this.viewSize[0], vh = this.viewSize[1];
30117 // only move it if it needs it
30119 // first validate right/bottom
30120 if(x + w > vw+s.left){
30124 if(y + h > vh+s.top){
30128 // then make sure top/left isn't negative
30140 if(this.isVisible()){
30141 this.el.setLocation(x, y);
30142 this.adjustAssets();
30149 onDrag : function(){
30150 if(!this.proxyDrag){
30151 this.xy = this.el.getXY();
30152 this.adjustAssets();
30157 adjustAssets : function(doShow){
30158 var x = this.xy[0], y = this.xy[1];
30159 var w = this.size.width, h = this.size.height;
30160 if(doShow === true){
30162 this.shadow.show(this.el);
30168 if(this.shadow && this.shadow.isVisible()){
30169 this.shadow.show(this.el);
30171 if(this.shim && this.shim.isVisible()){
30172 this.shim.setBounds(x, y, w, h);
30177 adjustViewport : function(w, h){
30179 w = Roo.lib.Dom.getViewWidth();
30180 h = Roo.lib.Dom.getViewHeight();
30183 this.viewSize = [w, h];
30184 if(this.modal && this.mask.isVisible()){
30185 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30186 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30188 if(this.isVisible()){
30189 this.constrainXY();
30194 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30195 * shadow, proxy, mask, etc.) Also removes all event listeners.
30196 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30198 destroy : function(removeEl){
30199 if(this.isVisible()){
30200 this.animateTarget = null;
30203 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30205 this.tabs.destroy(removeEl);
30218 for(var i = 0, len = this.buttons.length; i < len; i++){
30219 this.buttons[i].destroy();
30222 this.el.removeAllListeners();
30223 if(removeEl === true){
30224 this.el.update("");
30227 Roo.DialogManager.unregister(this);
30231 startMove : function(){
30232 if(this.proxyDrag){
30235 if(this.constraintoviewport !== false){
30236 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30241 endMove : function(){
30242 if(!this.proxyDrag){
30243 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30245 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30248 this.refreshSize();
30249 this.adjustAssets();
30251 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30255 * Brings this dialog to the front of any other visible dialogs
30256 * @return {Roo.BasicDialog} this
30258 toFront : function(){
30259 Roo.DialogManager.bringToFront(this);
30264 * Sends this dialog to the back (under) of any other visible dialogs
30265 * @return {Roo.BasicDialog} this
30267 toBack : function(){
30268 Roo.DialogManager.sendToBack(this);
30273 * Centers this dialog in the viewport
30274 * @return {Roo.BasicDialog} this
30276 center : function(){
30277 var xy = this.el.getCenterXY(true);
30278 this.moveTo(xy[0], xy[1]);
30283 * Moves the dialog's top-left corner to the specified point
30284 * @param {Number} x
30285 * @param {Number} y
30286 * @return {Roo.BasicDialog} this
30288 moveTo : function(x, y){
30290 if(this.isVisible()){
30291 this.el.setXY(this.xy);
30292 this.adjustAssets();
30298 * Aligns the dialog to the specified element
30299 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30300 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30301 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30302 * @return {Roo.BasicDialog} this
30304 alignTo : function(element, position, offsets){
30305 this.xy = this.el.getAlignToXY(element, position, offsets);
30306 if(this.isVisible()){
30307 this.el.setXY(this.xy);
30308 this.adjustAssets();
30314 * Anchors an element to another element and realigns it when the window is resized.
30315 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30316 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30317 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30318 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30319 * is a number, it is used as the buffer delay (defaults to 50ms).
30320 * @return {Roo.BasicDialog} this
30322 anchorTo : function(el, alignment, offsets, monitorScroll){
30323 var action = function(){
30324 this.alignTo(el, alignment, offsets);
30326 Roo.EventManager.onWindowResize(action, this);
30327 var tm = typeof monitorScroll;
30328 if(tm != 'undefined'){
30329 Roo.EventManager.on(window, 'scroll', action, this,
30330 {buffer: tm == 'number' ? monitorScroll : 50});
30337 * Returns true if the dialog is visible
30338 * @return {Boolean}
30340 isVisible : function(){
30341 return this.el.isVisible();
30345 animHide : function(callback){
30346 var b = Roo.get(this.animateTarget).getBox();
30348 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30350 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30351 this.hideEl.createDelegate(this, [callback]));
30355 * Hides the dialog.
30356 * @param {Function} callback (optional) Function to call when the dialog is hidden
30357 * @return {Roo.BasicDialog} this
30359 hide : function(callback){
30360 if (this.fireEvent("beforehide", this) === false){
30364 this.shadow.hide();
30369 // sometimes animateTarget seems to get set.. causing problems...
30370 // this just double checks..
30371 if(this.animateTarget && Roo.get(this.animateTarget)) {
30372 this.animHide(callback);
30375 this.hideEl(callback);
30381 hideEl : function(callback){
30385 Roo.get(document.body).removeClass("x-body-masked");
30387 this.fireEvent("hide", this);
30388 if(typeof callback == "function"){
30394 hideAction : function(){
30395 this.setLeft("-10000px");
30396 this.setTop("-10000px");
30397 this.setStyle("visibility", "hidden");
30401 refreshSize : function(){
30402 this.size = this.el.getSize();
30403 this.xy = this.el.getXY();
30404 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30408 // z-index is managed by the DialogManager and may be overwritten at any time
30409 setZIndex : function(index){
30411 this.mask.setStyle("z-index", index);
30414 this.shim.setStyle("z-index", ++index);
30417 this.shadow.setZIndex(++index);
30419 this.el.setStyle("z-index", ++index);
30421 this.proxy.setStyle("z-index", ++index);
30424 this.resizer.proxy.setStyle("z-index", ++index);
30427 this.lastZIndex = index;
30431 * Returns the element for this dialog
30432 * @return {Roo.Element} The underlying dialog Element
30434 getEl : function(){
30440 * @class Roo.DialogManager
30441 * Provides global access to BasicDialogs that have been created and
30442 * support for z-indexing (layering) multiple open dialogs.
30444 Roo.DialogManager = function(){
30446 var accessList = [];
30450 var sortDialogs = function(d1, d2){
30451 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30455 var orderDialogs = function(){
30456 accessList.sort(sortDialogs);
30457 var seed = Roo.DialogManager.zseed;
30458 for(var i = 0, len = accessList.length; i < len; i++){
30459 var dlg = accessList[i];
30461 dlg.setZIndex(seed + (i*10));
30468 * The starting z-index for BasicDialogs (defaults to 9000)
30469 * @type Number The z-index value
30474 register : function(dlg){
30475 list[dlg.id] = dlg;
30476 accessList.push(dlg);
30480 unregister : function(dlg){
30481 delete list[dlg.id];
30484 if(!accessList.indexOf){
30485 for( i = 0, len = accessList.length; i < len; i++){
30486 if(accessList[i] == dlg){
30487 accessList.splice(i, 1);
30492 i = accessList.indexOf(dlg);
30494 accessList.splice(i, 1);
30500 * Gets a registered dialog by id
30501 * @param {String/Object} id The id of the dialog or a dialog
30502 * @return {Roo.BasicDialog} this
30504 get : function(id){
30505 return typeof id == "object" ? id : list[id];
30509 * Brings the specified dialog to the front
30510 * @param {String/Object} dlg The id of the dialog or a dialog
30511 * @return {Roo.BasicDialog} this
30513 bringToFront : function(dlg){
30514 dlg = this.get(dlg);
30517 dlg._lastAccess = new Date().getTime();
30524 * Sends the specified dialog to the back
30525 * @param {String/Object} dlg The id of the dialog or a dialog
30526 * @return {Roo.BasicDialog} this
30528 sendToBack : function(dlg){
30529 dlg = this.get(dlg);
30530 dlg._lastAccess = -(new Date().getTime());
30536 * Hides all dialogs
30538 hideAll : function(){
30539 for(var id in list){
30540 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
30549 * @class Roo.LayoutDialog
30550 * @extends Roo.BasicDialog
30551 * Dialog which provides adjustments for working with a layout in a Dialog.
30552 * Add your necessary layout config options to the dialog's config.<br>
30553 * Example usage (including a nested layout):
30556 dialog = new Roo.LayoutDialog("download-dlg", {
30565 // layout config merges with the dialog config
30567 tabPosition: "top",
30568 alwaysShowTabs: true
30571 dialog.addKeyListener(27, dialog.hide, dialog);
30572 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
30573 dialog.addButton("Build It!", this.getDownload, this);
30575 // we can even add nested layouts
30576 var innerLayout = new Roo.BorderLayout("dl-inner", {
30586 innerLayout.beginUpdate();
30587 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
30588 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
30589 innerLayout.endUpdate(true);
30591 var layout = dialog.getLayout();
30592 layout.beginUpdate();
30593 layout.add("center", new Roo.ContentPanel("standard-panel",
30594 {title: "Download the Source", fitToFrame:true}));
30595 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
30596 {title: "Build your own roo.js"}));
30597 layout.getRegion("center").showPanel(sp);
30598 layout.endUpdate();
30602 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
30603 * @param {Object} config configuration options
30605 Roo.LayoutDialog = function(el, cfg){
30608 if (typeof(cfg) == 'undefined') {
30609 config = Roo.apply({}, el);
30610 // not sure why we use documentElement here.. - it should always be body.
30611 // IE7 borks horribly if we use documentElement.
30612 // webkit also does not like documentElement - it creates a body element...
30613 el = Roo.get( document.body || document.documentElement ).createChild();
30614 //config.autoCreate = true;
30618 config.autoTabs = false;
30619 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
30620 this.body.setStyle({overflow:"hidden", position:"relative"});
30621 this.layout = new Roo.BorderLayout(this.body.dom, config);
30622 this.layout.monitorWindowResize = false;
30623 this.el.addClass("x-dlg-auto-layout");
30624 // fix case when center region overwrites center function
30625 this.center = Roo.BasicDialog.prototype.center;
30626 this.on("show", this.layout.layout, this.layout, true);
30627 if (config.items) {
30628 var xitems = config.items;
30629 delete config.items;
30630 Roo.each(xitems, this.addxtype, this);
30635 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
30637 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
30640 endUpdate : function(){
30641 this.layout.endUpdate();
30645 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
30648 beginUpdate : function(){
30649 this.layout.beginUpdate();
30653 * Get the BorderLayout for this dialog
30654 * @return {Roo.BorderLayout}
30656 getLayout : function(){
30657 return this.layout;
30660 showEl : function(){
30661 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
30663 this.layout.layout();
30668 // Use the syncHeightBeforeShow config option to control this automatically
30669 syncBodyHeight : function(){
30670 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
30671 if(this.layout){this.layout.layout();}
30675 * Add an xtype element (actually adds to the layout.)
30676 * @return {Object} xdata xtype object data.
30679 addxtype : function(c) {
30680 return this.layout.addxtype(c);
30684 * Ext JS Library 1.1.1
30685 * Copyright(c) 2006-2007, Ext JS, LLC.
30687 * Originally Released Under LGPL - original licence link has changed is not relivant.
30690 * <script type="text/javascript">
30694 * @class Roo.MessageBox
30695 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
30699 Roo.Msg.alert('Status', 'Changes saved successfully.');
30701 // Prompt for user data:
30702 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
30704 // process text value...
30708 // Show a dialog using config options:
30710 title:'Save Changes?',
30711 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
30712 buttons: Roo.Msg.YESNOCANCEL,
30719 Roo.MessageBox = function(){
30720 var dlg, opt, mask, waitTimer;
30721 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
30722 var buttons, activeTextEl, bwidth;
30725 var handleButton = function(button){
30727 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
30731 var handleHide = function(){
30732 if(opt && opt.cls){
30733 dlg.el.removeClass(opt.cls);
30736 Roo.TaskMgr.stop(waitTimer);
30742 var updateButtons = function(b){
30745 buttons["ok"].hide();
30746 buttons["cancel"].hide();
30747 buttons["yes"].hide();
30748 buttons["no"].hide();
30749 dlg.footer.dom.style.display = 'none';
30752 dlg.footer.dom.style.display = '';
30753 for(var k in buttons){
30754 if(typeof buttons[k] != "function"){
30757 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
30758 width += buttons[k].el.getWidth()+15;
30768 var handleEsc = function(d, k, e){
30769 if(opt && opt.closable !== false){
30779 * Returns a reference to the underlying {@link Roo.BasicDialog} element
30780 * @return {Roo.BasicDialog} The BasicDialog element
30782 getDialog : function(){
30784 dlg = new Roo.BasicDialog("x-msg-box", {
30789 constraintoviewport:false,
30791 collapsible : false,
30794 width:400, height:100,
30795 buttonAlign:"center",
30796 closeClick : function(){
30797 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
30798 handleButton("no");
30800 handleButton("cancel");
30804 dlg.on("hide", handleHide);
30806 dlg.addKeyListener(27, handleEsc);
30808 var bt = this.buttonText;
30809 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
30810 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
30811 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
30812 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
30813 bodyEl = dlg.body.createChild({
30815 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>'
30817 msgEl = bodyEl.dom.firstChild;
30818 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
30819 textboxEl.enableDisplayMode();
30820 textboxEl.addKeyListener([10,13], function(){
30821 if(dlg.isVisible() && opt && opt.buttons){
30822 if(opt.buttons.ok){
30823 handleButton("ok");
30824 }else if(opt.buttons.yes){
30825 handleButton("yes");
30829 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
30830 textareaEl.enableDisplayMode();
30831 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
30832 progressEl.enableDisplayMode();
30833 var pf = progressEl.dom.firstChild;
30835 pp = Roo.get(pf.firstChild);
30836 pp.setHeight(pf.offsetHeight);
30844 * Updates the message box body text
30845 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
30846 * the XHTML-compliant non-breaking space character '&#160;')
30847 * @return {Roo.MessageBox} This message box
30849 updateText : function(text){
30850 if(!dlg.isVisible() && !opt.width){
30851 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
30853 msgEl.innerHTML = text || ' ';
30855 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
30856 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
30858 Math.min(opt.width || cw , this.maxWidth),
30859 Math.max(opt.minWidth || this.minWidth, bwidth)
30862 activeTextEl.setWidth(w);
30864 if(dlg.isVisible()){
30865 dlg.fixedcenter = false;
30867 // to big, make it scroll. = But as usual stupid IE does not support
30870 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
30871 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
30872 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
30874 bodyEl.dom.style.height = '';
30875 bodyEl.dom.style.overflowY = '';
30878 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
30880 bodyEl.dom.style.overflowX = '';
30883 dlg.setContentSize(w, bodyEl.getHeight());
30884 if(dlg.isVisible()){
30885 dlg.fixedcenter = true;
30891 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
30892 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
30893 * @param {Number} value Any number between 0 and 1 (e.g., .5)
30894 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
30895 * @return {Roo.MessageBox} This message box
30897 updateProgress : function(value, text){
30899 this.updateText(text);
30901 if (pp) { // weird bug on my firefox - for some reason this is not defined
30902 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
30908 * Returns true if the message box is currently displayed
30909 * @return {Boolean} True if the message box is visible, else false
30911 isVisible : function(){
30912 return dlg && dlg.isVisible();
30916 * Hides the message box if it is displayed
30919 if(this.isVisible()){
30925 * Displays a new message box, or reinitializes an existing message box, based on the config options
30926 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
30927 * The following config object properties are supported:
30929 Property Type Description
30930 ---------- --------------- ------------------------------------------------------------------------------------
30931 animEl String/Element An id or Element from which the message box should animate as it opens and
30932 closes (defaults to undefined)
30933 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
30934 cancel:'Bar'}), or false to not show any buttons (defaults to false)
30935 closable Boolean False to hide the top-right close button (defaults to true). Note that
30936 progress and wait dialogs will ignore this property and always hide the
30937 close button as they can only be closed programmatically.
30938 cls String A custom CSS class to apply to the message box element
30939 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
30940 displayed (defaults to 75)
30941 fn Function A callback function to execute after closing the dialog. The arguments to the
30942 function will be btn (the name of the button that was clicked, if applicable,
30943 e.g. "ok"), and text (the value of the active text field, if applicable).
30944 Progress and wait dialogs will ignore this option since they do not respond to
30945 user actions and can only be closed programmatically, so any required function
30946 should be called by the same code after it closes the dialog.
30947 icon String A CSS class that provides a background image to be used as an icon for
30948 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
30949 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
30950 minWidth Number The minimum width in pixels of the message box (defaults to 100)
30951 modal Boolean False to allow user interaction with the page while the message box is
30952 displayed (defaults to true)
30953 msg String A string that will replace the existing message box body text (defaults
30954 to the XHTML-compliant non-breaking space character ' ')
30955 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
30956 progress Boolean True to display a progress bar (defaults to false)
30957 progressText String The text to display inside the progress bar if progress = true (defaults to '')
30958 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
30959 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
30960 title String The title text
30961 value String The string value to set into the active textbox element if displayed
30962 wait Boolean True to display a progress bar (defaults to false)
30963 width Number The width of the dialog in pixels
30970 msg: 'Please enter your address:',
30972 buttons: Roo.MessageBox.OKCANCEL,
30975 animEl: 'addAddressBtn'
30978 * @param {Object} config Configuration options
30979 * @return {Roo.MessageBox} This message box
30981 show : function(options)
30984 // this causes nightmares if you show one dialog after another
30985 // especially on callbacks..
30987 if(this.isVisible()){
30990 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
30991 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
30992 Roo.log("New Dialog Message:" + options.msg )
30993 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
30994 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
30997 var d = this.getDialog();
30999 d.setTitle(opt.title || " ");
31000 d.close.setDisplayed(opt.closable !== false);
31001 activeTextEl = textboxEl;
31002 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31007 textareaEl.setHeight(typeof opt.multiline == "number" ?
31008 opt.multiline : this.defaultTextHeight);
31009 activeTextEl = textareaEl;
31018 progressEl.setDisplayed(opt.progress === true);
31019 this.updateProgress(0);
31020 activeTextEl.dom.value = opt.value || "";
31022 dlg.setDefaultButton(activeTextEl);
31024 var bs = opt.buttons;
31027 db = buttons["ok"];
31028 }else if(bs && bs.yes){
31029 db = buttons["yes"];
31031 dlg.setDefaultButton(db);
31033 bwidth = updateButtons(opt.buttons);
31034 this.updateText(opt.msg);
31036 d.el.addClass(opt.cls);
31038 d.proxyDrag = opt.proxyDrag === true;
31039 d.modal = opt.modal !== false;
31040 d.mask = opt.modal !== false ? mask : false;
31041 if(!d.isVisible()){
31042 // force it to the end of the z-index stack so it gets a cursor in FF
31043 document.body.appendChild(dlg.el.dom);
31044 d.animateTarget = null;
31045 d.show(options.animEl);
31051 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31052 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31053 * and closing the message box when the process is complete.
31054 * @param {String} title The title bar text
31055 * @param {String} msg The message box body text
31056 * @return {Roo.MessageBox} This message box
31058 progress : function(title, msg){
31065 minWidth: this.minProgressWidth,
31072 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31073 * If a callback function is passed it will be called after the user clicks the button, and the
31074 * id of the button that was clicked will be passed as the only parameter to the callback
31075 * (could also be the top-right close button).
31076 * @param {String} title The title bar text
31077 * @param {String} msg The message box body text
31078 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31079 * @param {Object} scope (optional) The scope of the callback function
31080 * @return {Roo.MessageBox} This message box
31082 alert : function(title, msg, fn, scope){
31095 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31096 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31097 * You are responsible for closing the message box when the process is complete.
31098 * @param {String} msg The message box body text
31099 * @param {String} title (optional) The title bar text
31100 * @return {Roo.MessageBox} This message box
31102 wait : function(msg, title){
31113 waitTimer = Roo.TaskMgr.start({
31115 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31123 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31124 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31125 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31126 * @param {String} title The title bar text
31127 * @param {String} msg The message box body text
31128 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31129 * @param {Object} scope (optional) The scope of the callback function
31130 * @return {Roo.MessageBox} This message box
31132 confirm : function(title, msg, fn, scope){
31136 buttons: this.YESNO,
31145 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31146 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31147 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31148 * (could also be the top-right close button) and the text that was entered will be passed as the two
31149 * parameters to the callback.
31150 * @param {String} title The title bar text
31151 * @param {String} msg The message box body text
31152 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31153 * @param {Object} scope (optional) The scope of the callback function
31154 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31155 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31156 * @return {Roo.MessageBox} This message box
31158 prompt : function(title, msg, fn, scope, multiline){
31162 buttons: this.OKCANCEL,
31167 multiline: multiline,
31174 * Button config that displays a single OK button
31179 * Button config that displays Yes and No buttons
31182 YESNO : {yes:true, no:true},
31184 * Button config that displays OK and Cancel buttons
31187 OKCANCEL : {ok:true, cancel:true},
31189 * Button config that displays Yes, No and Cancel buttons
31192 YESNOCANCEL : {yes:true, no:true, cancel:true},
31195 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31198 defaultTextHeight : 75,
31200 * The maximum width in pixels of the message box (defaults to 600)
31205 * The minimum width in pixels of the message box (defaults to 100)
31210 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31211 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31214 minProgressWidth : 250,
31216 * An object containing the default button text strings that can be overriden for localized language support.
31217 * Supported properties are: ok, cancel, yes and no.
31218 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31231 * Shorthand for {@link Roo.MessageBox}
31233 Roo.Msg = Roo.MessageBox;/*
31235 * Ext JS Library 1.1.1
31236 * Copyright(c) 2006-2007, Ext JS, LLC.
31238 * Originally Released Under LGPL - original licence link has changed is not relivant.
31241 * <script type="text/javascript">
31244 * @class Roo.QuickTips
31245 * Provides attractive and customizable tooltips for any element.
31248 Roo.QuickTips = function(){
31249 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31250 var ce, bd, xy, dd;
31251 var visible = false, disabled = true, inited = false;
31252 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31254 var onOver = function(e){
31258 var t = e.getTarget();
31259 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31262 if(ce && t == ce.el){
31263 clearTimeout(hideProc);
31266 if(t && tagEls[t.id]){
31267 tagEls[t.id].el = t;
31268 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31271 var ttp, et = Roo.fly(t);
31272 var ns = cfg.namespace;
31273 if(tm.interceptTitles && t.title){
31276 t.removeAttribute("title");
31277 e.preventDefault();
31279 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31282 showProc = show.defer(tm.showDelay, tm, [{
31285 width: et.getAttributeNS(ns, cfg.width),
31286 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31287 title: et.getAttributeNS(ns, cfg.title),
31288 cls: et.getAttributeNS(ns, cfg.cls)
31293 var onOut = function(e){
31294 clearTimeout(showProc);
31295 var t = e.getTarget();
31296 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31297 hideProc = setTimeout(hide, tm.hideDelay);
31301 var onMove = function(e){
31307 if(tm.trackMouse && ce){
31312 var onDown = function(e){
31313 clearTimeout(showProc);
31314 clearTimeout(hideProc);
31316 if(tm.hideOnClick){
31319 tm.enable.defer(100, tm);
31324 var getPad = function(){
31325 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31328 var show = function(o){
31332 clearTimeout(dismissProc);
31334 if(removeCls){ // in case manually hidden
31335 el.removeClass(removeCls);
31339 el.addClass(ce.cls);
31340 removeCls = ce.cls;
31343 tipTitle.update(ce.title);
31346 tipTitle.update('');
31349 el.dom.style.width = tm.maxWidth+'px';
31350 //tipBody.dom.style.width = '';
31351 tipBodyText.update(o.text);
31352 var p = getPad(), w = ce.width;
31354 var td = tipBodyText.dom;
31355 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31356 if(aw > tm.maxWidth){
31358 }else if(aw < tm.minWidth){
31364 //tipBody.setWidth(w);
31365 el.setWidth(parseInt(w, 10) + p);
31366 if(ce.autoHide === false){
31367 close.setDisplayed(true);
31372 close.setDisplayed(false);
31378 el.avoidY = xy[1]-18;
31383 el.setStyle("visibility", "visible");
31384 el.fadeIn({callback: afterShow});
31390 var afterShow = function(){
31394 if(tm.autoDismiss && ce.autoHide !== false){
31395 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31400 var hide = function(noanim){
31401 clearTimeout(dismissProc);
31402 clearTimeout(hideProc);
31404 if(el.isVisible()){
31406 if(noanim !== true && tm.animate){
31407 el.fadeOut({callback: afterHide});
31414 var afterHide = function(){
31417 el.removeClass(removeCls);
31424 * @cfg {Number} minWidth
31425 * The minimum width of the quick tip (defaults to 40)
31429 * @cfg {Number} maxWidth
31430 * The maximum width of the quick tip (defaults to 300)
31434 * @cfg {Boolean} interceptTitles
31435 * True to automatically use the element's DOM title value if available (defaults to false)
31437 interceptTitles : false,
31439 * @cfg {Boolean} trackMouse
31440 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31442 trackMouse : false,
31444 * @cfg {Boolean} hideOnClick
31445 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31447 hideOnClick : true,
31449 * @cfg {Number} showDelay
31450 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31454 * @cfg {Number} hideDelay
31455 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31459 * @cfg {Boolean} autoHide
31460 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31461 * Used in conjunction with hideDelay.
31466 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31467 * (defaults to true). Used in conjunction with autoDismissDelay.
31469 autoDismiss : true,
31472 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31474 autoDismissDelay : 5000,
31476 * @cfg {Boolean} animate
31477 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
31482 * @cfg {String} title
31483 * Title text to display (defaults to ''). This can be any valid HTML markup.
31487 * @cfg {String} text
31488 * Body text to display (defaults to ''). This can be any valid HTML markup.
31492 * @cfg {String} cls
31493 * A CSS class to apply to the base quick tip element (defaults to '').
31497 * @cfg {Number} width
31498 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
31499 * minWidth or maxWidth.
31504 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
31505 * or display QuickTips in a page.
31508 tm = Roo.QuickTips;
31509 cfg = tm.tagConfig;
31511 if(!Roo.isReady){ // allow calling of init() before onReady
31512 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
31515 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
31516 el.fxDefaults = {stopFx: true};
31517 // maximum custom styling
31518 //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>');
31519 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>');
31520 tipTitle = el.child('h3');
31521 tipTitle.enableDisplayMode("block");
31522 tipBody = el.child('div.x-tip-bd');
31523 tipBodyText = el.child('div.x-tip-bd-inner');
31524 //bdLeft = el.child('div.x-tip-bd-left');
31525 //bdRight = el.child('div.x-tip-bd-right');
31526 close = el.child('div.x-tip-close');
31527 close.enableDisplayMode("block");
31528 close.on("click", hide);
31529 var d = Roo.get(document);
31530 d.on("mousedown", onDown);
31531 d.on("mouseover", onOver);
31532 d.on("mouseout", onOut);
31533 d.on("mousemove", onMove);
31534 esc = d.addKeyListener(27, hide);
31537 dd = el.initDD("default", null, {
31538 onDrag : function(){
31542 dd.setHandleElId(tipTitle.id);
31551 * Configures a new quick tip instance and assigns it to a target element. The following config options
31554 Property Type Description
31555 ---------- --------------------- ------------------------------------------------------------------------
31556 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
31558 * @param {Object} config The config object
31560 register : function(config){
31561 var cs = config instanceof Array ? config : arguments;
31562 for(var i = 0, len = cs.length; i < len; i++) {
31564 var target = c.target;
31566 if(target instanceof Array){
31567 for(var j = 0, jlen = target.length; j < jlen; j++){
31568 tagEls[target[j]] = c;
31571 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
31578 * Removes this quick tip from its element and destroys it.
31579 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
31581 unregister : function(el){
31582 delete tagEls[Roo.id(el)];
31586 * Enable this quick tip.
31588 enable : function(){
31589 if(inited && disabled){
31591 if(locks.length < 1){
31598 * Disable this quick tip.
31600 disable : function(){
31602 clearTimeout(showProc);
31603 clearTimeout(hideProc);
31604 clearTimeout(dismissProc);
31612 * Returns true if the quick tip is enabled, else false.
31614 isEnabled : function(){
31621 attribute : "qtip",
31631 // backwards compat
31632 Roo.QuickTips.tips = Roo.QuickTips.register;/*
31634 * Ext JS Library 1.1.1
31635 * Copyright(c) 2006-2007, Ext JS, LLC.
31637 * Originally Released Under LGPL - original licence link has changed is not relivant.
31640 * <script type="text/javascript">
31645 * @class Roo.tree.TreePanel
31646 * @extends Roo.data.Tree
31648 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
31649 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
31650 * @cfg {Boolean} enableDD true to enable drag and drop
31651 * @cfg {Boolean} enableDrag true to enable just drag
31652 * @cfg {Boolean} enableDrop true to enable just drop
31653 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
31654 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
31655 * @cfg {String} ddGroup The DD group this TreePanel belongs to
31656 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
31657 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
31658 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
31659 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
31660 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
31661 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
31662 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
31663 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
31664 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
31665 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
31666 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
31667 * @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>
31668 * @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>
31671 * @param {String/HTMLElement/Element} el The container element
31672 * @param {Object} config
31674 Roo.tree.TreePanel = function(el, config){
31676 var loader = false;
31678 root = config.root;
31679 delete config.root;
31681 if (config.loader) {
31682 loader = config.loader;
31683 delete config.loader;
31686 Roo.apply(this, config);
31687 Roo.tree.TreePanel.superclass.constructor.call(this);
31688 this.el = Roo.get(el);
31689 this.el.addClass('x-tree');
31690 //console.log(root);
31692 this.setRootNode( Roo.factory(root, Roo.tree));
31695 this.loader = Roo.factory(loader, Roo.tree);
31698 * Read-only. The id of the container element becomes this TreePanel's id.
31700 this.id = this.el.id;
31703 * @event beforeload
31704 * Fires before a node is loaded, return false to cancel
31705 * @param {Node} node The node being loaded
31707 "beforeload" : true,
31710 * Fires when a node is loaded
31711 * @param {Node} node The node that was loaded
31715 * @event textchange
31716 * Fires when the text for a node is changed
31717 * @param {Node} node The node
31718 * @param {String} text The new text
31719 * @param {String} oldText The old text
31721 "textchange" : true,
31723 * @event beforeexpand
31724 * Fires before a node is expanded, return false to cancel.
31725 * @param {Node} node The node
31726 * @param {Boolean} deep
31727 * @param {Boolean} anim
31729 "beforeexpand" : true,
31731 * @event beforecollapse
31732 * Fires before a node is collapsed, return false to cancel.
31733 * @param {Node} node The node
31734 * @param {Boolean} deep
31735 * @param {Boolean} anim
31737 "beforecollapse" : true,
31740 * Fires when a node is expanded
31741 * @param {Node} node The node
31745 * @event disabledchange
31746 * Fires when the disabled status of a node changes
31747 * @param {Node} node The node
31748 * @param {Boolean} disabled
31750 "disabledchange" : true,
31753 * Fires when a node is collapsed
31754 * @param {Node} node The node
31758 * @event beforeclick
31759 * Fires before click processing on a node. Return false to cancel the default action.
31760 * @param {Node} node The node
31761 * @param {Roo.EventObject} e The event object
31763 "beforeclick":true,
31765 * @event checkchange
31766 * Fires when a node with a checkbox's checked property changes
31767 * @param {Node} this This node
31768 * @param {Boolean} checked
31770 "checkchange":true,
31773 * Fires when a node is clicked
31774 * @param {Node} node The node
31775 * @param {Roo.EventObject} e The event object
31780 * Fires when a node is double clicked
31781 * @param {Node} node The node
31782 * @param {Roo.EventObject} e The event object
31786 * @event contextmenu
31787 * Fires when a node is right clicked
31788 * @param {Node} node The node
31789 * @param {Roo.EventObject} e The event object
31791 "contextmenu":true,
31793 * @event beforechildrenrendered
31794 * Fires right before the child nodes for a node are rendered
31795 * @param {Node} node The node
31797 "beforechildrenrendered":true,
31800 * Fires when a node starts being dragged
31801 * @param {Roo.tree.TreePanel} this
31802 * @param {Roo.tree.TreeNode} node
31803 * @param {event} e The raw browser event
31805 "startdrag" : true,
31808 * Fires when a drag operation is complete
31809 * @param {Roo.tree.TreePanel} this
31810 * @param {Roo.tree.TreeNode} node
31811 * @param {event} e The raw browser event
31816 * Fires when a dragged node is dropped on a valid DD target
31817 * @param {Roo.tree.TreePanel} this
31818 * @param {Roo.tree.TreeNode} node
31819 * @param {DD} dd The dd it was dropped on
31820 * @param {event} e The raw browser event
31824 * @event beforenodedrop
31825 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
31826 * passed to handlers has the following properties:<br />
31827 * <ul style="padding:5px;padding-left:16px;">
31828 * <li>tree - The TreePanel</li>
31829 * <li>target - The node being targeted for the drop</li>
31830 * <li>data - The drag data from the drag source</li>
31831 * <li>point - The point of the drop - append, above or below</li>
31832 * <li>source - The drag source</li>
31833 * <li>rawEvent - Raw mouse event</li>
31834 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
31835 * to be inserted by setting them on this object.</li>
31836 * <li>cancel - Set this to true to cancel the drop.</li>
31838 * @param {Object} dropEvent
31840 "beforenodedrop" : true,
31843 * Fires after a DD object is dropped on a node in this tree. The dropEvent
31844 * passed to handlers has the following properties:<br />
31845 * <ul style="padding:5px;padding-left:16px;">
31846 * <li>tree - The TreePanel</li>
31847 * <li>target - The node being targeted for the drop</li>
31848 * <li>data - The drag data from the drag source</li>
31849 * <li>point - The point of the drop - append, above or below</li>
31850 * <li>source - The drag source</li>
31851 * <li>rawEvent - Raw mouse event</li>
31852 * <li>dropNode - Dropped node(s).</li>
31854 * @param {Object} dropEvent
31858 * @event nodedragover
31859 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
31860 * passed to handlers has the following properties:<br />
31861 * <ul style="padding:5px;padding-left:16px;">
31862 * <li>tree - The TreePanel</li>
31863 * <li>target - The node being targeted for the drop</li>
31864 * <li>data - The drag data from the drag source</li>
31865 * <li>point - The point of the drop - append, above or below</li>
31866 * <li>source - The drag source</li>
31867 * <li>rawEvent - Raw mouse event</li>
31868 * <li>dropNode - Drop node(s) provided by the source.</li>
31869 * <li>cancel - Set this to true to signal drop not allowed.</li>
31871 * @param {Object} dragOverEvent
31873 "nodedragover" : true
31876 if(this.singleExpand){
31877 this.on("beforeexpand", this.restrictExpand, this);
31880 this.editor.tree = this;
31881 this.editor = Roo.factory(this.editor, Roo.tree);
31884 if (this.selModel) {
31885 this.selModel = Roo.factory(this.selModel, Roo.tree);
31889 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
31890 rootVisible : true,
31891 animate: Roo.enableFx,
31894 hlDrop : Roo.enableFx,
31898 rendererTip: false,
31900 restrictExpand : function(node){
31901 var p = node.parentNode;
31903 if(p.expandedChild && p.expandedChild.parentNode == p){
31904 p.expandedChild.collapse();
31906 p.expandedChild = node;
31910 // private override
31911 setRootNode : function(node){
31912 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
31913 if(!this.rootVisible){
31914 node.ui = new Roo.tree.RootTreeNodeUI(node);
31920 * Returns the container element for this TreePanel
31922 getEl : function(){
31927 * Returns the default TreeLoader for this TreePanel
31929 getLoader : function(){
31930 return this.loader;
31936 expandAll : function(){
31937 this.root.expand(true);
31941 * Collapse all nodes
31943 collapseAll : function(){
31944 this.root.collapse(true);
31948 * Returns the selection model used by this TreePanel
31950 getSelectionModel : function(){
31951 if(!this.selModel){
31952 this.selModel = new Roo.tree.DefaultSelectionModel();
31954 return this.selModel;
31958 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
31959 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
31960 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
31963 getChecked : function(a, startNode){
31964 startNode = startNode || this.root;
31966 var f = function(){
31967 if(this.attributes.checked){
31968 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
31971 startNode.cascade(f);
31976 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
31977 * @param {String} path
31978 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
31979 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
31980 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
31982 expandPath : function(path, attr, callback){
31983 attr = attr || "id";
31984 var keys = path.split(this.pathSeparator);
31985 var curNode = this.root;
31986 if(curNode.attributes[attr] != keys[1]){ // invalid root
31988 callback(false, null);
31993 var f = function(){
31994 if(++index == keys.length){
31996 callback(true, curNode);
32000 var c = curNode.findChild(attr, keys[index]);
32003 callback(false, curNode);
32008 c.expand(false, false, f);
32010 curNode.expand(false, false, f);
32014 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32015 * @param {String} path
32016 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32017 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32018 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32020 selectPath : function(path, attr, callback){
32021 attr = attr || "id";
32022 var keys = path.split(this.pathSeparator);
32023 var v = keys.pop();
32024 if(keys.length > 0){
32025 var f = function(success, node){
32026 if(success && node){
32027 var n = node.findChild(attr, v);
32033 }else if(callback){
32034 callback(false, n);
32038 callback(false, n);
32042 this.expandPath(keys.join(this.pathSeparator), attr, f);
32044 this.root.select();
32046 callback(true, this.root);
32051 getTreeEl : function(){
32056 * Trigger rendering of this TreePanel
32058 render : function(){
32059 if (this.innerCt) {
32060 return this; // stop it rendering more than once!!
32063 this.innerCt = this.el.createChild({tag:"ul",
32064 cls:"x-tree-root-ct " +
32065 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32067 if(this.containerScroll){
32068 Roo.dd.ScrollManager.register(this.el);
32070 if((this.enableDD || this.enableDrop) && !this.dropZone){
32072 * The dropZone used by this tree if drop is enabled
32073 * @type Roo.tree.TreeDropZone
32075 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32076 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32079 if((this.enableDD || this.enableDrag) && !this.dragZone){
32081 * The dragZone used by this tree if drag is enabled
32082 * @type Roo.tree.TreeDragZone
32084 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32085 ddGroup: this.ddGroup || "TreeDD",
32086 scroll: this.ddScroll
32089 this.getSelectionModel().init(this);
32091 Roo.log("ROOT not set in tree");
32094 this.root.render();
32095 if(!this.rootVisible){
32096 this.root.renderChildren();
32102 * Ext JS Library 1.1.1
32103 * Copyright(c) 2006-2007, Ext JS, LLC.
32105 * Originally Released Under LGPL - original licence link has changed is not relivant.
32108 * <script type="text/javascript">
32113 * @class Roo.tree.DefaultSelectionModel
32114 * @extends Roo.util.Observable
32115 * The default single selection for a TreePanel.
32116 * @param {Object} cfg Configuration
32118 Roo.tree.DefaultSelectionModel = function(cfg){
32119 this.selNode = null;
32125 * @event selectionchange
32126 * Fires when the selected node changes
32127 * @param {DefaultSelectionModel} this
32128 * @param {TreeNode} node the new selection
32130 "selectionchange" : true,
32133 * @event beforeselect
32134 * Fires before the selected node changes, return false to cancel the change
32135 * @param {DefaultSelectionModel} this
32136 * @param {TreeNode} node the new selection
32137 * @param {TreeNode} node the old selection
32139 "beforeselect" : true
32142 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32145 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32146 init : function(tree){
32148 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32149 tree.on("click", this.onNodeClick, this);
32152 onNodeClick : function(node, e){
32153 if (e.ctrlKey && this.selNode == node) {
32154 this.unselect(node);
32162 * @param {TreeNode} node The node to select
32163 * @return {TreeNode} The selected node
32165 select : function(node){
32166 var last = this.selNode;
32167 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32169 last.ui.onSelectedChange(false);
32171 this.selNode = node;
32172 node.ui.onSelectedChange(true);
32173 this.fireEvent("selectionchange", this, node, last);
32180 * @param {TreeNode} node The node to unselect
32182 unselect : function(node){
32183 if(this.selNode == node){
32184 this.clearSelections();
32189 * Clear all selections
32191 clearSelections : function(){
32192 var n = this.selNode;
32194 n.ui.onSelectedChange(false);
32195 this.selNode = null;
32196 this.fireEvent("selectionchange", this, null);
32202 * Get the selected node
32203 * @return {TreeNode} The selected node
32205 getSelectedNode : function(){
32206 return this.selNode;
32210 * Returns true if the node is selected
32211 * @param {TreeNode} node The node to check
32212 * @return {Boolean}
32214 isSelected : function(node){
32215 return this.selNode == node;
32219 * Selects the node above the selected node in the tree, intelligently walking the nodes
32220 * @return TreeNode The new selection
32222 selectPrevious : function(){
32223 var s = this.selNode || this.lastSelNode;
32227 var ps = s.previousSibling;
32229 if(!ps.isExpanded() || ps.childNodes.length < 1){
32230 return this.select(ps);
32232 var lc = ps.lastChild;
32233 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32236 return this.select(lc);
32238 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32239 return this.select(s.parentNode);
32245 * Selects the node above the selected node in the tree, intelligently walking the nodes
32246 * @return TreeNode The new selection
32248 selectNext : function(){
32249 var s = this.selNode || this.lastSelNode;
32253 if(s.firstChild && s.isExpanded()){
32254 return this.select(s.firstChild);
32255 }else if(s.nextSibling){
32256 return this.select(s.nextSibling);
32257 }else if(s.parentNode){
32259 s.parentNode.bubble(function(){
32260 if(this.nextSibling){
32261 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32270 onKeyDown : function(e){
32271 var s = this.selNode || this.lastSelNode;
32272 // undesirable, but required
32277 var k = e.getKey();
32285 this.selectPrevious();
32288 e.preventDefault();
32289 if(s.hasChildNodes()){
32290 if(!s.isExpanded()){
32292 }else if(s.firstChild){
32293 this.select(s.firstChild, e);
32298 e.preventDefault();
32299 if(s.hasChildNodes() && s.isExpanded()){
32301 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32302 this.select(s.parentNode, e);
32310 * @class Roo.tree.MultiSelectionModel
32311 * @extends Roo.util.Observable
32312 * Multi selection for a TreePanel.
32313 * @param {Object} cfg Configuration
32315 Roo.tree.MultiSelectionModel = function(){
32316 this.selNodes = [];
32320 * @event selectionchange
32321 * Fires when the selected nodes change
32322 * @param {MultiSelectionModel} this
32323 * @param {Array} nodes Array of the selected nodes
32325 "selectionchange" : true
32327 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32331 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32332 init : function(tree){
32334 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32335 tree.on("click", this.onNodeClick, this);
32338 onNodeClick : function(node, e){
32339 this.select(node, e, e.ctrlKey);
32344 * @param {TreeNode} node The node to select
32345 * @param {EventObject} e (optional) An event associated with the selection
32346 * @param {Boolean} keepExisting True to retain existing selections
32347 * @return {TreeNode} The selected node
32349 select : function(node, e, keepExisting){
32350 if(keepExisting !== true){
32351 this.clearSelections(true);
32353 if(this.isSelected(node)){
32354 this.lastSelNode = node;
32357 this.selNodes.push(node);
32358 this.selMap[node.id] = node;
32359 this.lastSelNode = node;
32360 node.ui.onSelectedChange(true);
32361 this.fireEvent("selectionchange", this, this.selNodes);
32367 * @param {TreeNode} node The node to unselect
32369 unselect : function(node){
32370 if(this.selMap[node.id]){
32371 node.ui.onSelectedChange(false);
32372 var sn = this.selNodes;
32375 index = sn.indexOf(node);
32377 for(var i = 0, len = sn.length; i < len; i++){
32385 this.selNodes.splice(index, 1);
32387 delete this.selMap[node.id];
32388 this.fireEvent("selectionchange", this, this.selNodes);
32393 * Clear all selections
32395 clearSelections : function(suppressEvent){
32396 var sn = this.selNodes;
32398 for(var i = 0, len = sn.length; i < len; i++){
32399 sn[i].ui.onSelectedChange(false);
32401 this.selNodes = [];
32403 if(suppressEvent !== true){
32404 this.fireEvent("selectionchange", this, this.selNodes);
32410 * Returns true if the node is selected
32411 * @param {TreeNode} node The node to check
32412 * @return {Boolean}
32414 isSelected : function(node){
32415 return this.selMap[node.id] ? true : false;
32419 * Returns an array of the selected nodes
32422 getSelectedNodes : function(){
32423 return this.selNodes;
32426 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32428 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32430 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32433 * Ext JS Library 1.1.1
32434 * Copyright(c) 2006-2007, Ext JS, LLC.
32436 * Originally Released Under LGPL - original licence link has changed is not relivant.
32439 * <script type="text/javascript">
32443 * @class Roo.tree.TreeNode
32444 * @extends Roo.data.Node
32445 * @cfg {String} text The text for this node
32446 * @cfg {Boolean} expanded true to start the node expanded
32447 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32448 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32449 * @cfg {Boolean} disabled true to start the node disabled
32450 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32451 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32452 * @cfg {String} cls A css class to be added to the node
32453 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32454 * @cfg {String} href URL of the link used for the node (defaults to #)
32455 * @cfg {String} hrefTarget target frame for the link
32456 * @cfg {String} qtip An Ext QuickTip for the node
32457 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32458 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32459 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32460 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32461 * (defaults to undefined with no checkbox rendered)
32463 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32465 Roo.tree.TreeNode = function(attributes){
32466 attributes = attributes || {};
32467 if(typeof attributes == "string"){
32468 attributes = {text: attributes};
32470 this.childrenRendered = false;
32471 this.rendered = false;
32472 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32473 this.expanded = attributes.expanded === true;
32474 this.isTarget = attributes.isTarget !== false;
32475 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32476 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32479 * Read-only. The text for this node. To change it use setText().
32482 this.text = attributes.text;
32484 * True if this node is disabled.
32487 this.disabled = attributes.disabled === true;
32491 * @event textchange
32492 * Fires when the text for this node is changed
32493 * @param {Node} this This node
32494 * @param {String} text The new text
32495 * @param {String} oldText The old text
32497 "textchange" : true,
32499 * @event beforeexpand
32500 * Fires before this node is expanded, return false to cancel.
32501 * @param {Node} this This node
32502 * @param {Boolean} deep
32503 * @param {Boolean} anim
32505 "beforeexpand" : true,
32507 * @event beforecollapse
32508 * Fires before this node is collapsed, return false to cancel.
32509 * @param {Node} this This node
32510 * @param {Boolean} deep
32511 * @param {Boolean} anim
32513 "beforecollapse" : true,
32516 * Fires when this node is expanded
32517 * @param {Node} this This node
32521 * @event disabledchange
32522 * Fires when the disabled status of this node changes
32523 * @param {Node} this This node
32524 * @param {Boolean} disabled
32526 "disabledchange" : true,
32529 * Fires when this node is collapsed
32530 * @param {Node} this This node
32534 * @event beforeclick
32535 * Fires before click processing. Return false to cancel the default action.
32536 * @param {Node} this This node
32537 * @param {Roo.EventObject} e The event object
32539 "beforeclick":true,
32541 * @event checkchange
32542 * Fires when a node with a checkbox's checked property changes
32543 * @param {Node} this This node
32544 * @param {Boolean} checked
32546 "checkchange":true,
32549 * Fires when this node is clicked
32550 * @param {Node} this This node
32551 * @param {Roo.EventObject} e The event object
32556 * Fires when this node is double clicked
32557 * @param {Node} this This node
32558 * @param {Roo.EventObject} e The event object
32562 * @event contextmenu
32563 * Fires when this node is right clicked
32564 * @param {Node} this This node
32565 * @param {Roo.EventObject} e The event object
32567 "contextmenu":true,
32569 * @event beforechildrenrendered
32570 * Fires right before the child nodes for this node are rendered
32571 * @param {Node} this This node
32573 "beforechildrenrendered":true
32576 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
32579 * Read-only. The UI for this node
32582 this.ui = new uiClass(this);
32584 // finally support items[]
32585 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
32590 Roo.each(this.attributes.items, function(c) {
32591 this.appendChild(Roo.factory(c,Roo.Tree));
32593 delete this.attributes.items;
32598 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
32599 preventHScroll: true,
32601 * Returns true if this node is expanded
32602 * @return {Boolean}
32604 isExpanded : function(){
32605 return this.expanded;
32609 * Returns the UI object for this node
32610 * @return {TreeNodeUI}
32612 getUI : function(){
32616 // private override
32617 setFirstChild : function(node){
32618 var of = this.firstChild;
32619 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
32620 if(this.childrenRendered && of && node != of){
32621 of.renderIndent(true, true);
32624 this.renderIndent(true, true);
32628 // private override
32629 setLastChild : function(node){
32630 var ol = this.lastChild;
32631 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
32632 if(this.childrenRendered && ol && node != ol){
32633 ol.renderIndent(true, true);
32636 this.renderIndent(true, true);
32640 // these methods are overridden to provide lazy rendering support
32641 // private override
32642 appendChild : function()
32644 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
32645 if(node && this.childrenRendered){
32648 this.ui.updateExpandIcon();
32652 // private override
32653 removeChild : function(node){
32654 this.ownerTree.getSelectionModel().unselect(node);
32655 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
32656 // if it's been rendered remove dom node
32657 if(this.childrenRendered){
32660 if(this.childNodes.length < 1){
32661 this.collapse(false, false);
32663 this.ui.updateExpandIcon();
32665 if(!this.firstChild) {
32666 this.childrenRendered = false;
32671 // private override
32672 insertBefore : function(node, refNode){
32673 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
32674 if(newNode && refNode && this.childrenRendered){
32677 this.ui.updateExpandIcon();
32682 * Sets the text for this node
32683 * @param {String} text
32685 setText : function(text){
32686 var oldText = this.text;
32688 this.attributes.text = text;
32689 if(this.rendered){ // event without subscribing
32690 this.ui.onTextChange(this, text, oldText);
32692 this.fireEvent("textchange", this, text, oldText);
32696 * Triggers selection of this node
32698 select : function(){
32699 this.getOwnerTree().getSelectionModel().select(this);
32703 * Triggers deselection of this node
32705 unselect : function(){
32706 this.getOwnerTree().getSelectionModel().unselect(this);
32710 * Returns true if this node is selected
32711 * @return {Boolean}
32713 isSelected : function(){
32714 return this.getOwnerTree().getSelectionModel().isSelected(this);
32718 * Expand this node.
32719 * @param {Boolean} deep (optional) True to expand all children as well
32720 * @param {Boolean} anim (optional) false to cancel the default animation
32721 * @param {Function} callback (optional) A callback to be called when
32722 * expanding this node completes (does not wait for deep expand to complete).
32723 * Called with 1 parameter, this node.
32725 expand : function(deep, anim, callback){
32726 if(!this.expanded){
32727 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
32730 if(!this.childrenRendered){
32731 this.renderChildren();
32733 this.expanded = true;
32734 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
32735 this.ui.animExpand(function(){
32736 this.fireEvent("expand", this);
32737 if(typeof callback == "function"){
32741 this.expandChildNodes(true);
32743 }.createDelegate(this));
32747 this.fireEvent("expand", this);
32748 if(typeof callback == "function"){
32753 if(typeof callback == "function"){
32758 this.expandChildNodes(true);
32762 isHiddenRoot : function(){
32763 return this.isRoot && !this.getOwnerTree().rootVisible;
32767 * Collapse this node.
32768 * @param {Boolean} deep (optional) True to collapse all children as well
32769 * @param {Boolean} anim (optional) false to cancel the default animation
32771 collapse : function(deep, anim){
32772 if(this.expanded && !this.isHiddenRoot()){
32773 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
32776 this.expanded = false;
32777 if((this.getOwnerTree().animate && anim !== false) || anim){
32778 this.ui.animCollapse(function(){
32779 this.fireEvent("collapse", this);
32781 this.collapseChildNodes(true);
32783 }.createDelegate(this));
32786 this.ui.collapse();
32787 this.fireEvent("collapse", this);
32791 var cs = this.childNodes;
32792 for(var i = 0, len = cs.length; i < len; i++) {
32793 cs[i].collapse(true, false);
32799 delayedExpand : function(delay){
32800 if(!this.expandProcId){
32801 this.expandProcId = this.expand.defer(delay, this);
32806 cancelExpand : function(){
32807 if(this.expandProcId){
32808 clearTimeout(this.expandProcId);
32810 this.expandProcId = false;
32814 * Toggles expanded/collapsed state of the node
32816 toggle : function(){
32825 * Ensures all parent nodes are expanded
32827 ensureVisible : function(callback){
32828 var tree = this.getOwnerTree();
32829 tree.expandPath(this.parentNode.getPath(), false, function(){
32830 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
32831 Roo.callback(callback);
32832 }.createDelegate(this));
32836 * Expand all child nodes
32837 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
32839 expandChildNodes : function(deep){
32840 var cs = this.childNodes;
32841 for(var i = 0, len = cs.length; i < len; i++) {
32842 cs[i].expand(deep);
32847 * Collapse all child nodes
32848 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
32850 collapseChildNodes : function(deep){
32851 var cs = this.childNodes;
32852 for(var i = 0, len = cs.length; i < len; i++) {
32853 cs[i].collapse(deep);
32858 * Disables this node
32860 disable : function(){
32861 this.disabled = true;
32863 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32864 this.ui.onDisableChange(this, true);
32866 this.fireEvent("disabledchange", this, true);
32870 * Enables this node
32872 enable : function(){
32873 this.disabled = false;
32874 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
32875 this.ui.onDisableChange(this, false);
32877 this.fireEvent("disabledchange", this, false);
32881 renderChildren : function(suppressEvent){
32882 if(suppressEvent !== false){
32883 this.fireEvent("beforechildrenrendered", this);
32885 var cs = this.childNodes;
32886 for(var i = 0, len = cs.length; i < len; i++){
32887 cs[i].render(true);
32889 this.childrenRendered = true;
32893 sort : function(fn, scope){
32894 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
32895 if(this.childrenRendered){
32896 var cs = this.childNodes;
32897 for(var i = 0, len = cs.length; i < len; i++){
32898 cs[i].render(true);
32904 render : function(bulkRender){
32905 this.ui.render(bulkRender);
32906 if(!this.rendered){
32907 this.rendered = true;
32909 this.expanded = false;
32910 this.expand(false, false);
32916 renderIndent : function(deep, refresh){
32918 this.ui.childIndent = null;
32920 this.ui.renderIndent();
32921 if(deep === true && this.childrenRendered){
32922 var cs = this.childNodes;
32923 for(var i = 0, len = cs.length; i < len; i++){
32924 cs[i].renderIndent(true, refresh);
32930 * Ext JS Library 1.1.1
32931 * Copyright(c) 2006-2007, Ext JS, LLC.
32933 * Originally Released Under LGPL - original licence link has changed is not relivant.
32936 * <script type="text/javascript">
32940 * @class Roo.tree.AsyncTreeNode
32941 * @extends Roo.tree.TreeNode
32942 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
32944 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32946 Roo.tree.AsyncTreeNode = function(config){
32947 this.loaded = false;
32948 this.loading = false;
32949 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
32951 * @event beforeload
32952 * Fires before this node is loaded, return false to cancel
32953 * @param {Node} this This node
32955 this.addEvents({'beforeload':true, 'load': true});
32958 * Fires when this node is loaded
32959 * @param {Node} this This node
32962 * The loader used by this node (defaults to using the tree's defined loader)
32967 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
32968 expand : function(deep, anim, callback){
32969 if(this.loading){ // if an async load is already running, waiting til it's done
32971 var f = function(){
32972 if(!this.loading){ // done loading
32973 clearInterval(timer);
32974 this.expand(deep, anim, callback);
32976 }.createDelegate(this);
32977 timer = setInterval(f, 200);
32981 if(this.fireEvent("beforeload", this) === false){
32984 this.loading = true;
32985 this.ui.beforeLoad(this);
32986 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
32988 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
32992 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
32996 * Returns true if this node is currently loading
32997 * @return {Boolean}
32999 isLoading : function(){
33000 return this.loading;
33003 loadComplete : function(deep, anim, callback){
33004 this.loading = false;
33005 this.loaded = true;
33006 this.ui.afterLoad(this);
33007 this.fireEvent("load", this);
33008 this.expand(deep, anim, callback);
33012 * Returns true if this node has been loaded
33013 * @return {Boolean}
33015 isLoaded : function(){
33016 return this.loaded;
33019 hasChildNodes : function(){
33020 if(!this.isLeaf() && !this.loaded){
33023 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33028 * Trigger a reload for this node
33029 * @param {Function} callback
33031 reload : function(callback){
33032 this.collapse(false, false);
33033 while(this.firstChild){
33034 this.removeChild(this.firstChild);
33036 this.childrenRendered = false;
33037 this.loaded = false;
33038 if(this.isHiddenRoot()){
33039 this.expanded = false;
33041 this.expand(false, false, callback);
33045 * Ext JS Library 1.1.1
33046 * Copyright(c) 2006-2007, Ext JS, LLC.
33048 * Originally Released Under LGPL - original licence link has changed is not relivant.
33051 * <script type="text/javascript">
33055 * @class Roo.tree.TreeNodeUI
33057 * @param {Object} node The node to render
33058 * The TreeNode UI implementation is separate from the
33059 * tree implementation. Unless you are customizing the tree UI,
33060 * you should never have to use this directly.
33062 Roo.tree.TreeNodeUI = function(node){
33064 this.rendered = false;
33065 this.animating = false;
33066 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33069 Roo.tree.TreeNodeUI.prototype = {
33070 removeChild : function(node){
33072 this.ctNode.removeChild(node.ui.getEl());
33076 beforeLoad : function(){
33077 this.addClass("x-tree-node-loading");
33080 afterLoad : function(){
33081 this.removeClass("x-tree-node-loading");
33084 onTextChange : function(node, text, oldText){
33086 this.textNode.innerHTML = text;
33090 onDisableChange : function(node, state){
33091 this.disabled = state;
33093 this.addClass("x-tree-node-disabled");
33095 this.removeClass("x-tree-node-disabled");
33099 onSelectedChange : function(state){
33102 this.addClass("x-tree-selected");
33105 this.removeClass("x-tree-selected");
33109 onMove : function(tree, node, oldParent, newParent, index, refNode){
33110 this.childIndent = null;
33112 var targetNode = newParent.ui.getContainer();
33113 if(!targetNode){//target not rendered
33114 this.holder = document.createElement("div");
33115 this.holder.appendChild(this.wrap);
33118 var insertBefore = refNode ? refNode.ui.getEl() : null;
33120 targetNode.insertBefore(this.wrap, insertBefore);
33122 targetNode.appendChild(this.wrap);
33124 this.node.renderIndent(true);
33128 addClass : function(cls){
33130 Roo.fly(this.elNode).addClass(cls);
33134 removeClass : function(cls){
33136 Roo.fly(this.elNode).removeClass(cls);
33140 remove : function(){
33142 this.holder = document.createElement("div");
33143 this.holder.appendChild(this.wrap);
33147 fireEvent : function(){
33148 return this.node.fireEvent.apply(this.node, arguments);
33151 initEvents : function(){
33152 this.node.on("move", this.onMove, this);
33153 var E = Roo.EventManager;
33154 var a = this.anchor;
33156 var el = Roo.fly(a, '_treeui');
33158 if(Roo.isOpera){ // opera render bug ignores the CSS
33159 el.setStyle("text-decoration", "none");
33162 el.on("click", this.onClick, this);
33163 el.on("dblclick", this.onDblClick, this);
33166 Roo.EventManager.on(this.checkbox,
33167 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33170 el.on("contextmenu", this.onContextMenu, this);
33172 var icon = Roo.fly(this.iconNode);
33173 icon.on("click", this.onClick, this);
33174 icon.on("dblclick", this.onDblClick, this);
33175 icon.on("contextmenu", this.onContextMenu, this);
33176 E.on(this.ecNode, "click", this.ecClick, this, true);
33178 if(this.node.disabled){
33179 this.addClass("x-tree-node-disabled");
33181 if(this.node.hidden){
33182 this.addClass("x-tree-node-disabled");
33184 var ot = this.node.getOwnerTree();
33185 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33186 if(dd && (!this.node.isRoot || ot.rootVisible)){
33187 Roo.dd.Registry.register(this.elNode, {
33189 handles: this.getDDHandles(),
33195 getDDHandles : function(){
33196 return [this.iconNode, this.textNode];
33201 this.wrap.style.display = "none";
33207 this.wrap.style.display = "";
33211 onContextMenu : function(e){
33212 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33213 e.preventDefault();
33215 this.fireEvent("contextmenu", this.node, e);
33219 onClick : function(e){
33224 if(this.fireEvent("beforeclick", this.node, e) !== false){
33225 if(!this.disabled && this.node.attributes.href){
33226 this.fireEvent("click", this.node, e);
33229 e.preventDefault();
33234 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33235 this.node.toggle();
33238 this.fireEvent("click", this.node, e);
33244 onDblClick : function(e){
33245 e.preventDefault();
33250 this.toggleCheck();
33252 if(!this.animating && this.node.hasChildNodes()){
33253 this.node.toggle();
33255 this.fireEvent("dblclick", this.node, e);
33258 onCheckChange : function(){
33259 var checked = this.checkbox.checked;
33260 this.node.attributes.checked = checked;
33261 this.fireEvent('checkchange', this.node, checked);
33264 ecClick : function(e){
33265 if(!this.animating && this.node.hasChildNodes()){
33266 this.node.toggle();
33270 startDrop : function(){
33271 this.dropping = true;
33274 // delayed drop so the click event doesn't get fired on a drop
33275 endDrop : function(){
33276 setTimeout(function(){
33277 this.dropping = false;
33278 }.createDelegate(this), 50);
33281 expand : function(){
33282 this.updateExpandIcon();
33283 this.ctNode.style.display = "";
33286 focus : function(){
33287 if(!this.node.preventHScroll){
33288 try{this.anchor.focus();
33290 }else if(!Roo.isIE){
33292 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33293 var l = noscroll.scrollLeft;
33294 this.anchor.focus();
33295 noscroll.scrollLeft = l;
33300 toggleCheck : function(value){
33301 var cb = this.checkbox;
33303 cb.checked = (value === undefined ? !cb.checked : value);
33309 this.anchor.blur();
33313 animExpand : function(callback){
33314 var ct = Roo.get(this.ctNode);
33316 if(!this.node.hasChildNodes()){
33317 this.updateExpandIcon();
33318 this.ctNode.style.display = "";
33319 Roo.callback(callback);
33322 this.animating = true;
33323 this.updateExpandIcon();
33326 callback : function(){
33327 this.animating = false;
33328 Roo.callback(callback);
33331 duration: this.node.ownerTree.duration || .25
33335 highlight : function(){
33336 var tree = this.node.getOwnerTree();
33337 Roo.fly(this.wrap).highlight(
33338 tree.hlColor || "C3DAF9",
33339 {endColor: tree.hlBaseColor}
33343 collapse : function(){
33344 this.updateExpandIcon();
33345 this.ctNode.style.display = "none";
33348 animCollapse : function(callback){
33349 var ct = Roo.get(this.ctNode);
33350 ct.enableDisplayMode('block');
33353 this.animating = true;
33354 this.updateExpandIcon();
33357 callback : function(){
33358 this.animating = false;
33359 Roo.callback(callback);
33362 duration: this.node.ownerTree.duration || .25
33366 getContainer : function(){
33367 return this.ctNode;
33370 getEl : function(){
33374 appendDDGhost : function(ghostNode){
33375 ghostNode.appendChild(this.elNode.cloneNode(true));
33378 getDDRepairXY : function(){
33379 return Roo.lib.Dom.getXY(this.iconNode);
33382 onRender : function(){
33386 render : function(bulkRender){
33387 var n = this.node, a = n.attributes;
33388 var targetNode = n.parentNode ?
33389 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33391 if(!this.rendered){
33392 this.rendered = true;
33394 this.renderElements(n, a, targetNode, bulkRender);
33397 if(this.textNode.setAttributeNS){
33398 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33400 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33403 this.textNode.setAttribute("ext:qtip", a.qtip);
33405 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33408 }else if(a.qtipCfg){
33409 a.qtipCfg.target = Roo.id(this.textNode);
33410 Roo.QuickTips.register(a.qtipCfg);
33413 if(!this.node.expanded){
33414 this.updateExpandIcon();
33417 if(bulkRender === true) {
33418 targetNode.appendChild(this.wrap);
33423 renderElements : function(n, a, targetNode, bulkRender)
33425 // add some indent caching, this helps performance when rendering a large tree
33426 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33427 var t = n.getOwnerTree();
33428 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33429 if (typeof(n.attributes.html) != 'undefined') {
33430 txt = n.attributes.html;
33432 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33433 var cb = typeof a.checked == 'boolean';
33434 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33435 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33436 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33437 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33438 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33439 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33440 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33441 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33442 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33443 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33446 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33447 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33448 n.nextSibling.ui.getEl(), buf.join(""));
33450 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33453 this.elNode = this.wrap.childNodes[0];
33454 this.ctNode = this.wrap.childNodes[1];
33455 var cs = this.elNode.childNodes;
33456 this.indentNode = cs[0];
33457 this.ecNode = cs[1];
33458 this.iconNode = cs[2];
33461 this.checkbox = cs[3];
33464 this.anchor = cs[index];
33465 this.textNode = cs[index].firstChild;
33468 getAnchor : function(){
33469 return this.anchor;
33472 getTextEl : function(){
33473 return this.textNode;
33476 getIconEl : function(){
33477 return this.iconNode;
33480 isChecked : function(){
33481 return this.checkbox ? this.checkbox.checked : false;
33484 updateExpandIcon : function(){
33486 var n = this.node, c1, c2;
33487 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
33488 var hasChild = n.hasChildNodes();
33492 c1 = "x-tree-node-collapsed";
33493 c2 = "x-tree-node-expanded";
33496 c1 = "x-tree-node-expanded";
33497 c2 = "x-tree-node-collapsed";
33500 this.removeClass("x-tree-node-leaf");
33501 this.wasLeaf = false;
33503 if(this.c1 != c1 || this.c2 != c2){
33504 Roo.fly(this.elNode).replaceClass(c1, c2);
33505 this.c1 = c1; this.c2 = c2;
33508 // this changes non-leafs into leafs if they have no children.
33509 // it's not very rational behaviour..
33511 if(!this.wasLeaf && this.node.leaf){
33512 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
33515 this.wasLeaf = true;
33518 var ecc = "x-tree-ec-icon "+cls;
33519 if(this.ecc != ecc){
33520 this.ecNode.className = ecc;
33526 getChildIndent : function(){
33527 if(!this.childIndent){
33531 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
33533 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
33535 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
33540 this.childIndent = buf.join("");
33542 return this.childIndent;
33545 renderIndent : function(){
33548 var p = this.node.parentNode;
33550 indent = p.ui.getChildIndent();
33552 if(this.indentMarkup != indent){ // don't rerender if not required
33553 this.indentNode.innerHTML = indent;
33554 this.indentMarkup = indent;
33556 this.updateExpandIcon();
33561 Roo.tree.RootTreeNodeUI = function(){
33562 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
33564 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
33565 render : function(){
33566 if(!this.rendered){
33567 var targetNode = this.node.ownerTree.innerCt.dom;
33568 this.node.expanded = true;
33569 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
33570 this.wrap = this.ctNode = targetNode.firstChild;
33573 collapse : function(){
33575 expand : function(){
33579 * Ext JS Library 1.1.1
33580 * Copyright(c) 2006-2007, Ext JS, LLC.
33582 * Originally Released Under LGPL - original licence link has changed is not relivant.
33585 * <script type="text/javascript">
33588 * @class Roo.tree.TreeLoader
33589 * @extends Roo.util.Observable
33590 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
33591 * nodes from a specified URL. The response must be a javascript Array definition
33592 * who's elements are node definition objects. eg:
33597 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
33598 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
33605 * The old style respose with just an array is still supported, but not recommended.
33608 * A server request is sent, and child nodes are loaded only when a node is expanded.
33609 * The loading node's id is passed to the server under the parameter name "node" to
33610 * enable the server to produce the correct child nodes.
33612 * To pass extra parameters, an event handler may be attached to the "beforeload"
33613 * event, and the parameters specified in the TreeLoader's baseParams property:
33615 myTreeLoader.on("beforeload", function(treeLoader, node) {
33616 this.baseParams.category = node.attributes.category;
33619 * This would pass an HTTP parameter called "category" to the server containing
33620 * the value of the Node's "category" attribute.
33622 * Creates a new Treeloader.
33623 * @param {Object} config A config object containing config properties.
33625 Roo.tree.TreeLoader = function(config){
33626 this.baseParams = {};
33627 this.requestMethod = "POST";
33628 Roo.apply(this, config);
33633 * @event beforeload
33634 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
33635 * @param {Object} This TreeLoader object.
33636 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33637 * @param {Object} callback The callback function specified in the {@link #load} call.
33642 * Fires when the node has been successfuly loaded.
33643 * @param {Object} This TreeLoader object.
33644 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33645 * @param {Object} response The response object containing the data from the server.
33649 * @event loadexception
33650 * Fires if the network request failed.
33651 * @param {Object} This TreeLoader object.
33652 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
33653 * @param {Object} response The response object containing the data from the server.
33655 loadexception : true,
33658 * Fires before a node is created, enabling you to return custom Node types
33659 * @param {Object} This TreeLoader object.
33660 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
33665 Roo.tree.TreeLoader.superclass.constructor.call(this);
33668 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
33670 * @cfg {String} dataUrl The URL from which to request a Json string which
33671 * specifies an array of node definition object representing the child nodes
33675 * @cfg {String} requestMethod either GET or POST
33676 * defaults to POST (due to BC)
33680 * @cfg {Object} baseParams (optional) An object containing properties which
33681 * specify HTTP parameters to be passed to each request for child nodes.
33684 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
33685 * created by this loader. If the attributes sent by the server have an attribute in this object,
33686 * they take priority.
33689 * @cfg {Object} uiProviders (optional) An object containing properties which
33691 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
33692 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
33693 * <i>uiProvider</i> attribute of a returned child node is a string rather
33694 * than a reference to a TreeNodeUI implementation, this that string value
33695 * is used as a property name in the uiProviders object. You can define the provider named
33696 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
33701 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
33702 * child nodes before loading.
33704 clearOnLoad : true,
33707 * @cfg {String} root (optional) Default to false. Use this to read data from an object
33708 * property on loading, rather than expecting an array. (eg. more compatible to a standard
33709 * Grid query { data : [ .....] }
33714 * @cfg {String} queryParam (optional)
33715 * Name of the query as it will be passed on the querystring (defaults to 'node')
33716 * eg. the request will be ?node=[id]
33723 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
33724 * This is called automatically when a node is expanded, but may be used to reload
33725 * a node (or append new children if the {@link #clearOnLoad} option is false.)
33726 * @param {Roo.tree.TreeNode} node
33727 * @param {Function} callback
33729 load : function(node, callback){
33730 if(this.clearOnLoad){
33731 while(node.firstChild){
33732 node.removeChild(node.firstChild);
33735 if(node.attributes.children){ // preloaded json children
33736 var cs = node.attributes.children;
33737 for(var i = 0, len = cs.length; i < len; i++){
33738 node.appendChild(this.createNode(cs[i]));
33740 if(typeof callback == "function"){
33743 }else if(this.dataUrl){
33744 this.requestData(node, callback);
33748 getParams: function(node){
33749 var buf = [], bp = this.baseParams;
33750 for(var key in bp){
33751 if(typeof bp[key] != "function"){
33752 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
33755 var n = this.queryParam === false ? 'node' : this.queryParam;
33756 buf.push(n + "=", encodeURIComponent(node.id));
33757 return buf.join("");
33760 requestData : function(node, callback){
33761 if(this.fireEvent("beforeload", this, node, callback) !== false){
33762 this.transId = Roo.Ajax.request({
33763 method:this.requestMethod,
33764 url: this.dataUrl||this.url,
33765 success: this.handleResponse,
33766 failure: this.handleFailure,
33768 argument: {callback: callback, node: node},
33769 params: this.getParams(node)
33772 // if the load is cancelled, make sure we notify
33773 // the node that we are done
33774 if(typeof callback == "function"){
33780 isLoading : function(){
33781 return this.transId ? true : false;
33784 abort : function(){
33785 if(this.isLoading()){
33786 Roo.Ajax.abort(this.transId);
33791 createNode : function(attr)
33793 // apply baseAttrs, nice idea Corey!
33794 if(this.baseAttrs){
33795 Roo.applyIf(attr, this.baseAttrs);
33797 if(this.applyLoader !== false){
33798 attr.loader = this;
33800 // uiProvider = depreciated..
33802 if(typeof(attr.uiProvider) == 'string'){
33803 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
33804 /** eval:var:attr */ eval(attr.uiProvider);
33806 if(typeof(this.uiProviders['default']) != 'undefined') {
33807 attr.uiProvider = this.uiProviders['default'];
33810 this.fireEvent('create', this, attr);
33812 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
33814 new Roo.tree.TreeNode(attr) :
33815 new Roo.tree.AsyncTreeNode(attr));
33818 processResponse : function(response, node, callback)
33820 var json = response.responseText;
33823 var o = Roo.decode(json);
33825 if (this.root === false && typeof(o.success) != undefined) {
33826 this.root = 'data'; // the default behaviour for list like data..
33829 if (this.root !== false && !o.success) {
33830 // it's a failure condition.
33831 var a = response.argument;
33832 this.fireEvent("loadexception", this, a.node, response);
33833 Roo.log("Load failed - should have a handler really");
33839 if (this.root !== false) {
33843 for(var i = 0, len = o.length; i < len; i++){
33844 var n = this.createNode(o[i]);
33846 node.appendChild(n);
33849 if(typeof callback == "function"){
33850 callback(this, node);
33853 this.handleFailure(response);
33857 handleResponse : function(response){
33858 this.transId = false;
33859 var a = response.argument;
33860 this.processResponse(response, a.node, a.callback);
33861 this.fireEvent("load", this, a.node, response);
33864 handleFailure : function(response)
33866 // should handle failure better..
33867 this.transId = false;
33868 var a = response.argument;
33869 this.fireEvent("loadexception", this, a.node, response);
33870 if(typeof a.callback == "function"){
33871 a.callback(this, a.node);
33876 * Ext JS Library 1.1.1
33877 * Copyright(c) 2006-2007, Ext JS, LLC.
33879 * Originally Released Under LGPL - original licence link has changed is not relivant.
33882 * <script type="text/javascript">
33886 * @class Roo.tree.TreeFilter
33887 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
33888 * @param {TreePanel} tree
33889 * @param {Object} config (optional)
33891 Roo.tree.TreeFilter = function(tree, config){
33893 this.filtered = {};
33894 Roo.apply(this, config);
33897 Roo.tree.TreeFilter.prototype = {
33904 * Filter the data by a specific attribute.
33905 * @param {String/RegExp} value Either string that the attribute value
33906 * should start with or a RegExp to test against the attribute
33907 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
33908 * @param {TreeNode} startNode (optional) The node to start the filter at.
33910 filter : function(value, attr, startNode){
33911 attr = attr || "text";
33913 if(typeof value == "string"){
33914 var vlen = value.length;
33915 // auto clear empty filter
33916 if(vlen == 0 && this.clearBlank){
33920 value = value.toLowerCase();
33922 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
33924 }else if(value.exec){ // regex?
33926 return value.test(n.attributes[attr]);
33929 throw 'Illegal filter type, must be string or regex';
33931 this.filterBy(f, null, startNode);
33935 * Filter by a function. The passed function will be called with each
33936 * node in the tree (or from the startNode). If the function returns true, the node is kept
33937 * otherwise it is filtered. If a node is filtered, its children are also filtered.
33938 * @param {Function} fn The filter function
33939 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
33941 filterBy : function(fn, scope, startNode){
33942 startNode = startNode || this.tree.root;
33943 if(this.autoClear){
33946 var af = this.filtered, rv = this.reverse;
33947 var f = function(n){
33948 if(n == startNode){
33954 var m = fn.call(scope || n, n);
33962 startNode.cascade(f);
33965 if(typeof id != "function"){
33967 if(n && n.parentNode){
33968 n.parentNode.removeChild(n);
33976 * Clears the current filter. Note: with the "remove" option
33977 * set a filter cannot be cleared.
33979 clear : function(){
33981 var af = this.filtered;
33983 if(typeof id != "function"){
33990 this.filtered = {};
33995 * Ext JS Library 1.1.1
33996 * Copyright(c) 2006-2007, Ext JS, LLC.
33998 * Originally Released Under LGPL - original licence link has changed is not relivant.
34001 * <script type="text/javascript">
34006 * @class Roo.tree.TreeSorter
34007 * Provides sorting of nodes in a TreePanel
34009 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34010 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34011 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34012 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34013 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34014 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34016 * @param {TreePanel} tree
34017 * @param {Object} config
34019 Roo.tree.TreeSorter = function(tree, config){
34020 Roo.apply(this, config);
34021 tree.on("beforechildrenrendered", this.doSort, this);
34022 tree.on("append", this.updateSort, this);
34023 tree.on("insert", this.updateSort, this);
34025 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34026 var p = this.property || "text";
34027 var sortType = this.sortType;
34028 var fs = this.folderSort;
34029 var cs = this.caseSensitive === true;
34030 var leafAttr = this.leafAttr || 'leaf';
34032 this.sortFn = function(n1, n2){
34034 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34037 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34041 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34042 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34044 return dsc ? +1 : -1;
34046 return dsc ? -1 : +1;
34053 Roo.tree.TreeSorter.prototype = {
34054 doSort : function(node){
34055 node.sort(this.sortFn);
34058 compareNodes : function(n1, n2){
34059 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34062 updateSort : function(tree, node){
34063 if(node.childrenRendered){
34064 this.doSort.defer(1, this, [node]);
34069 * Ext JS Library 1.1.1
34070 * Copyright(c) 2006-2007, Ext JS, LLC.
34072 * Originally Released Under LGPL - original licence link has changed is not relivant.
34075 * <script type="text/javascript">
34078 if(Roo.dd.DropZone){
34080 Roo.tree.TreeDropZone = function(tree, config){
34081 this.allowParentInsert = false;
34082 this.allowContainerDrop = false;
34083 this.appendOnly = false;
34084 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34086 this.lastInsertClass = "x-tree-no-status";
34087 this.dragOverData = {};
34090 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34091 ddGroup : "TreeDD",
34094 expandDelay : 1000,
34096 expandNode : function(node){
34097 if(node.hasChildNodes() && !node.isExpanded()){
34098 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34102 queueExpand : function(node){
34103 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34106 cancelExpand : function(){
34107 if(this.expandProcId){
34108 clearTimeout(this.expandProcId);
34109 this.expandProcId = false;
34113 isValidDropPoint : function(n, pt, dd, e, data){
34114 if(!n || !data){ return false; }
34115 var targetNode = n.node;
34116 var dropNode = data.node;
34117 // default drop rules
34118 if(!(targetNode && targetNode.isTarget && pt)){
34121 if(pt == "append" && targetNode.allowChildren === false){
34124 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34127 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34130 // reuse the object
34131 var overEvent = this.dragOverData;
34132 overEvent.tree = this.tree;
34133 overEvent.target = targetNode;
34134 overEvent.data = data;
34135 overEvent.point = pt;
34136 overEvent.source = dd;
34137 overEvent.rawEvent = e;
34138 overEvent.dropNode = dropNode;
34139 overEvent.cancel = false;
34140 var result = this.tree.fireEvent("nodedragover", overEvent);
34141 return overEvent.cancel === false && result !== false;
34144 getDropPoint : function(e, n, dd)
34148 return tn.allowChildren !== false ? "append" : false; // always append for root
34150 var dragEl = n.ddel;
34151 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34152 var y = Roo.lib.Event.getPageY(e);
34153 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34155 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34156 var noAppend = tn.allowChildren === false;
34157 if(this.appendOnly || tn.parentNode.allowChildren === false){
34158 return noAppend ? false : "append";
34160 var noBelow = false;
34161 if(!this.allowParentInsert){
34162 noBelow = tn.hasChildNodes() && tn.isExpanded();
34164 var q = (b - t) / (noAppend ? 2 : 3);
34165 if(y >= t && y < (t + q)){
34167 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34174 onNodeEnter : function(n, dd, e, data)
34176 this.cancelExpand();
34179 onNodeOver : function(n, dd, e, data)
34182 var pt = this.getDropPoint(e, n, dd);
34185 // auto node expand check
34186 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34187 this.queueExpand(node);
34188 }else if(pt != "append"){
34189 this.cancelExpand();
34192 // set the insert point style on the target node
34193 var returnCls = this.dropNotAllowed;
34194 if(this.isValidDropPoint(n, pt, dd, e, data)){
34199 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34200 cls = "x-tree-drag-insert-above";
34201 }else if(pt == "below"){
34202 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34203 cls = "x-tree-drag-insert-below";
34205 returnCls = "x-tree-drop-ok-append";
34206 cls = "x-tree-drag-append";
34208 if(this.lastInsertClass != cls){
34209 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34210 this.lastInsertClass = cls;
34217 onNodeOut : function(n, dd, e, data){
34219 this.cancelExpand();
34220 this.removeDropIndicators(n);
34223 onNodeDrop : function(n, dd, e, data){
34224 var point = this.getDropPoint(e, n, dd);
34225 var targetNode = n.node;
34226 targetNode.ui.startDrop();
34227 if(!this.isValidDropPoint(n, point, dd, e, data)){
34228 targetNode.ui.endDrop();
34231 // first try to find the drop node
34232 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34235 target: targetNode,
34240 dropNode: dropNode,
34243 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34244 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34245 targetNode.ui.endDrop();
34248 // allow target changing
34249 targetNode = dropEvent.target;
34250 if(point == "append" && !targetNode.isExpanded()){
34251 targetNode.expand(false, null, function(){
34252 this.completeDrop(dropEvent);
34253 }.createDelegate(this));
34255 this.completeDrop(dropEvent);
34260 completeDrop : function(de){
34261 var ns = de.dropNode, p = de.point, t = de.target;
34262 if(!(ns instanceof Array)){
34266 for(var i = 0, len = ns.length; i < len; i++){
34269 t.parentNode.insertBefore(n, t);
34270 }else if(p == "below"){
34271 t.parentNode.insertBefore(n, t.nextSibling);
34277 if(this.tree.hlDrop){
34281 this.tree.fireEvent("nodedrop", de);
34284 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34285 if(this.tree.hlDrop){
34286 dropNode.ui.focus();
34287 dropNode.ui.highlight();
34289 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34292 getTree : function(){
34296 removeDropIndicators : function(n){
34299 Roo.fly(el).removeClass([
34300 "x-tree-drag-insert-above",
34301 "x-tree-drag-insert-below",
34302 "x-tree-drag-append"]);
34303 this.lastInsertClass = "_noclass";
34307 beforeDragDrop : function(target, e, id){
34308 this.cancelExpand();
34312 afterRepair : function(data){
34313 if(data && Roo.enableFx){
34314 data.node.ui.highlight();
34324 * Ext JS Library 1.1.1
34325 * Copyright(c) 2006-2007, Ext JS, LLC.
34327 * Originally Released Under LGPL - original licence link has changed is not relivant.
34330 * <script type="text/javascript">
34334 if(Roo.dd.DragZone){
34335 Roo.tree.TreeDragZone = function(tree, config){
34336 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34340 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34341 ddGroup : "TreeDD",
34343 onBeforeDrag : function(data, e){
34345 return n && n.draggable && !n.disabled;
34349 onInitDrag : function(e){
34350 var data = this.dragData;
34351 this.tree.getSelectionModel().select(data.node);
34352 this.proxy.update("");
34353 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34354 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34357 getRepairXY : function(e, data){
34358 return data.node.ui.getDDRepairXY();
34361 onEndDrag : function(data, e){
34362 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34367 onValidDrop : function(dd, e, id){
34368 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34372 beforeInvalidDrop : function(e, id){
34373 // this scrolls the original position back into view
34374 var sm = this.tree.getSelectionModel();
34375 sm.clearSelections();
34376 sm.select(this.dragData.node);
34381 * Ext JS Library 1.1.1
34382 * Copyright(c) 2006-2007, Ext JS, LLC.
34384 * Originally Released Under LGPL - original licence link has changed is not relivant.
34387 * <script type="text/javascript">
34390 * @class Roo.tree.TreeEditor
34391 * @extends Roo.Editor
34392 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34393 * as the editor field.
34395 * @param {Object} config (used to be the tree panel.)
34396 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34398 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34399 * @cfg {Roo.form.TextField|Object} field The field configuration
34403 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34406 if (oldconfig) { // old style..
34407 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34410 tree = config.tree;
34411 config.field = config.field || {};
34412 config.field.xtype = 'TextField';
34413 field = Roo.factory(config.field, Roo.form);
34415 config = config || {};
34420 * @event beforenodeedit
34421 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34422 * false from the handler of this event.
34423 * @param {Editor} this
34424 * @param {Roo.tree.Node} node
34426 "beforenodeedit" : true
34430 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34434 tree.on('beforeclick', this.beforeNodeClick, this);
34435 tree.getTreeEl().on('mousedown', this.hide, this);
34436 this.on('complete', this.updateNode, this);
34437 this.on('beforestartedit', this.fitToTree, this);
34438 this.on('startedit', this.bindScroll, this, {delay:10});
34439 this.on('specialkey', this.onSpecialKey, this);
34442 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34444 * @cfg {String} alignment
34445 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34451 * @cfg {Boolean} hideEl
34452 * True to hide the bound element while the editor is displayed (defaults to false)
34456 * @cfg {String} cls
34457 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34459 cls: "x-small-editor x-tree-editor",
34461 * @cfg {Boolean} shim
34462 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34468 * @cfg {Number} maxWidth
34469 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34470 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34471 * scroll and client offsets into account prior to each edit.
34478 fitToTree : function(ed, el){
34479 var td = this.tree.getTreeEl().dom, nd = el.dom;
34480 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34481 td.scrollLeft = nd.offsetLeft;
34485 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
34486 this.setSize(w, '');
34488 return this.fireEvent('beforenodeedit', this, this.editNode);
34493 triggerEdit : function(node){
34494 this.completeEdit();
34495 this.editNode = node;
34496 this.startEdit(node.ui.textNode, node.text);
34500 bindScroll : function(){
34501 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
34505 beforeNodeClick : function(node, e){
34506 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
34507 this.lastClick = new Date();
34508 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
34510 this.triggerEdit(node);
34517 updateNode : function(ed, value){
34518 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
34519 this.editNode.setText(value);
34523 onHide : function(){
34524 Roo.tree.TreeEditor.superclass.onHide.call(this);
34526 this.editNode.ui.focus();
34531 onSpecialKey : function(field, e){
34532 var k = e.getKey();
34536 }else if(k == e.ENTER && !e.hasModifier()){
34538 this.completeEdit();
34541 });//<Script type="text/javascript">
34544 * Ext JS Library 1.1.1
34545 * Copyright(c) 2006-2007, Ext JS, LLC.
34547 * Originally Released Under LGPL - original licence link has changed is not relivant.
34550 * <script type="text/javascript">
34554 * Not documented??? - probably should be...
34557 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
34558 //focus: Roo.emptyFn, // prevent odd scrolling behavior
34560 renderElements : function(n, a, targetNode, bulkRender){
34561 //consel.log("renderElements?");
34562 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34564 var t = n.getOwnerTree();
34565 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
34567 var cols = t.columns;
34568 var bw = t.borderWidth;
34570 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34571 var cb = typeof a.checked == "boolean";
34572 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34573 var colcls = 'x-t-' + tid + '-c0';
34575 '<li class="x-tree-node">',
34578 '<div class="x-tree-node-el ', a.cls,'">',
34580 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
34583 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
34584 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
34585 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
34586 (a.icon ? ' x-tree-node-inline-icon' : ''),
34587 (a.iconCls ? ' '+a.iconCls : ''),
34588 '" unselectable="on" />',
34589 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
34590 (a.checked ? 'checked="checked" />' : ' />')) : ''),
34592 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34593 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
34594 '<span unselectable="on" qtip="' + tx + '">',
34598 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
34599 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
34601 for(var i = 1, len = cols.length; i < len; i++){
34603 colcls = 'x-t-' + tid + '-c' +i;
34604 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
34605 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
34606 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
34612 '<div class="x-clear"></div></div>',
34613 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34616 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34617 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34618 n.nextSibling.ui.getEl(), buf.join(""));
34620 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34622 var el = this.wrap.firstChild;
34624 this.elNode = el.firstChild;
34625 this.ranchor = el.childNodes[1];
34626 this.ctNode = this.wrap.childNodes[1];
34627 var cs = el.firstChild.childNodes;
34628 this.indentNode = cs[0];
34629 this.ecNode = cs[1];
34630 this.iconNode = cs[2];
34633 this.checkbox = cs[3];
34636 this.anchor = cs[index];
34638 this.textNode = cs[index].firstChild;
34640 //el.on("click", this.onClick, this);
34641 //el.on("dblclick", this.onDblClick, this);
34644 // console.log(this);
34646 initEvents : function(){
34647 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
34650 var a = this.ranchor;
34652 var el = Roo.get(a);
34654 if(Roo.isOpera){ // opera render bug ignores the CSS
34655 el.setStyle("text-decoration", "none");
34658 el.on("click", this.onClick, this);
34659 el.on("dblclick", this.onDblClick, this);
34660 el.on("contextmenu", this.onContextMenu, this);
34664 /*onSelectedChange : function(state){
34667 this.addClass("x-tree-selected");
34670 this.removeClass("x-tree-selected");
34673 addClass : function(cls){
34675 Roo.fly(this.elRow).addClass(cls);
34681 removeClass : function(cls){
34683 Roo.fly(this.elRow).removeClass(cls);
34689 });//<Script type="text/javascript">
34693 * Ext JS Library 1.1.1
34694 * Copyright(c) 2006-2007, Ext JS, LLC.
34696 * Originally Released Under LGPL - original licence link has changed is not relivant.
34699 * <script type="text/javascript">
34704 * @class Roo.tree.ColumnTree
34705 * @extends Roo.data.TreePanel
34706 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
34707 * @cfg {int} borderWidth compined right/left border allowance
34709 * @param {String/HTMLElement/Element} el The container element
34710 * @param {Object} config
34712 Roo.tree.ColumnTree = function(el, config)
34714 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
34718 * Fire this event on a container when it resizes
34719 * @param {int} w Width
34720 * @param {int} h Height
34724 this.on('resize', this.onResize, this);
34727 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
34731 borderWidth: Roo.isBorderBox ? 0 : 2,
34734 render : function(){
34735 // add the header.....
34737 Roo.tree.ColumnTree.superclass.render.apply(this);
34739 this.el.addClass('x-column-tree');
34741 this.headers = this.el.createChild(
34742 {cls:'x-tree-headers'},this.innerCt.dom);
34744 var cols = this.columns, c;
34745 var totalWidth = 0;
34747 var len = cols.length;
34748 for(var i = 0; i < len; i++){
34750 totalWidth += c.width;
34751 this.headEls.push(this.headers.createChild({
34752 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
34754 cls:'x-tree-hd-text',
34757 style:'width:'+(c.width-this.borderWidth)+'px;'
34760 this.headers.createChild({cls:'x-clear'});
34761 // prevent floats from wrapping when clipped
34762 this.headers.setWidth(totalWidth);
34763 //this.innerCt.setWidth(totalWidth);
34764 this.innerCt.setStyle({ overflow: 'auto' });
34765 this.onResize(this.width, this.height);
34769 onResize : function(w,h)
34774 this.innerCt.setWidth(this.width);
34775 this.innerCt.setHeight(this.height-20);
34778 var cols = this.columns, c;
34779 var totalWidth = 0;
34781 var len = cols.length;
34782 for(var i = 0; i < len; i++){
34784 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
34785 // it's the expander..
34786 expEl = this.headEls[i];
34789 totalWidth += c.width;
34793 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
34795 this.headers.setWidth(w-20);
34804 * Ext JS Library 1.1.1
34805 * Copyright(c) 2006-2007, Ext JS, LLC.
34807 * Originally Released Under LGPL - original licence link has changed is not relivant.
34810 * <script type="text/javascript">
34814 * @class Roo.menu.Menu
34815 * @extends Roo.util.Observable
34816 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
34817 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
34819 * Creates a new Menu
34820 * @param {Object} config Configuration options
34822 Roo.menu.Menu = function(config){
34823 Roo.apply(this, config);
34824 this.id = this.id || Roo.id();
34827 * @event beforeshow
34828 * Fires before this menu is displayed
34829 * @param {Roo.menu.Menu} this
34833 * @event beforehide
34834 * Fires before this menu is hidden
34835 * @param {Roo.menu.Menu} this
34840 * Fires after this menu is displayed
34841 * @param {Roo.menu.Menu} this
34846 * Fires after this menu is hidden
34847 * @param {Roo.menu.Menu} this
34852 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
34853 * @param {Roo.menu.Menu} this
34854 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34855 * @param {Roo.EventObject} e
34860 * Fires when the mouse is hovering over this menu
34861 * @param {Roo.menu.Menu} this
34862 * @param {Roo.EventObject} e
34863 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34868 * Fires when the mouse exits this menu
34869 * @param {Roo.menu.Menu} this
34870 * @param {Roo.EventObject} e
34871 * @param {Roo.menu.Item} menuItem The menu item that was clicked
34876 * Fires when a menu item contained in this menu is clicked
34877 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
34878 * @param {Roo.EventObject} e
34882 if (this.registerMenu) {
34883 Roo.menu.MenuMgr.register(this);
34886 var mis = this.items;
34887 this.items = new Roo.util.MixedCollection();
34889 this.add.apply(this, mis);
34893 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
34895 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
34899 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
34900 * for bottom-right shadow (defaults to "sides")
34904 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
34905 * this menu (defaults to "tl-tr?")
34907 subMenuAlign : "tl-tr?",
34909 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
34910 * relative to its element of origin (defaults to "tl-bl?")
34912 defaultAlign : "tl-bl?",
34914 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
34916 allowOtherMenus : false,
34918 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
34920 registerMenu : true,
34925 render : function(){
34929 var el = this.el = new Roo.Layer({
34931 shadow:this.shadow,
34933 parentEl: this.parentEl || document.body,
34937 this.keyNav = new Roo.menu.MenuNav(this);
34940 el.addClass("x-menu-plain");
34943 el.addClass(this.cls);
34945 // generic focus element
34946 this.focusEl = el.createChild({
34947 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
34949 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
34950 ul.on("click", this.onClick, this);
34951 ul.on("mouseover", this.onMouseOver, this);
34952 ul.on("mouseout", this.onMouseOut, this);
34953 this.items.each(function(item){
34958 var li = document.createElement("li");
34959 li.className = "x-menu-list-item";
34960 ul.dom.appendChild(li);
34961 item.render(li, this);
34968 autoWidth : function(){
34969 var el = this.el, ul = this.ul;
34973 var w = this.width;
34976 }else if(Roo.isIE){
34977 el.setWidth(this.minWidth);
34978 var t = el.dom.offsetWidth; // force recalc
34979 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
34984 delayAutoWidth : function(){
34987 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
34989 this.awTask.delay(20);
34994 findTargetItem : function(e){
34995 var t = e.getTarget(".x-menu-list-item", this.ul, true);
34996 if(t && t.menuItemId){
34997 return this.items.get(t.menuItemId);
35002 onClick : function(e){
35004 if(t = this.findTargetItem(e)){
35006 this.fireEvent("click", this, t, e);
35011 setActiveItem : function(item, autoExpand){
35012 if(item != this.activeItem){
35013 if(this.activeItem){
35014 this.activeItem.deactivate();
35016 this.activeItem = item;
35017 item.activate(autoExpand);
35018 }else if(autoExpand){
35024 tryActivate : function(start, step){
35025 var items = this.items;
35026 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35027 var item = items.get(i);
35028 if(!item.disabled && item.canActivate){
35029 this.setActiveItem(item, false);
35037 onMouseOver : function(e){
35039 if(t = this.findTargetItem(e)){
35040 if(t.canActivate && !t.disabled){
35041 this.setActiveItem(t, true);
35044 this.fireEvent("mouseover", this, e, t);
35048 onMouseOut : function(e){
35050 if(t = this.findTargetItem(e)){
35051 if(t == this.activeItem && t.shouldDeactivate(e)){
35052 this.activeItem.deactivate();
35053 delete this.activeItem;
35056 this.fireEvent("mouseout", this, e, t);
35060 * Read-only. Returns true if the menu is currently displayed, else false.
35063 isVisible : function(){
35064 return this.el && !this.hidden;
35068 * Displays this menu relative to another element
35069 * @param {String/HTMLElement/Roo.Element} element The element to align to
35070 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35071 * the element (defaults to this.defaultAlign)
35072 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35074 show : function(el, pos, parentMenu){
35075 this.parentMenu = parentMenu;
35079 this.fireEvent("beforeshow", this);
35080 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35084 * Displays this menu at a specific xy position
35085 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35086 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35088 showAt : function(xy, parentMenu, /* private: */_e){
35089 this.parentMenu = parentMenu;
35094 this.fireEvent("beforeshow", this);
35095 xy = this.el.adjustForConstraints(xy);
35099 this.hidden = false;
35101 this.fireEvent("show", this);
35104 focus : function(){
35106 this.doFocus.defer(50, this);
35110 doFocus : function(){
35112 this.focusEl.focus();
35117 * Hides this menu and optionally all parent menus
35118 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35120 hide : function(deep){
35121 if(this.el && this.isVisible()){
35122 this.fireEvent("beforehide", this);
35123 if(this.activeItem){
35124 this.activeItem.deactivate();
35125 this.activeItem = null;
35128 this.hidden = true;
35129 this.fireEvent("hide", this);
35131 if(deep === true && this.parentMenu){
35132 this.parentMenu.hide(true);
35137 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35138 * Any of the following are valid:
35140 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35141 * <li>An HTMLElement object which will be converted to a menu item</li>
35142 * <li>A menu item config object that will be created as a new menu item</li>
35143 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35144 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35149 var menu = new Roo.menu.Menu();
35151 // Create a menu item to add by reference
35152 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35154 // Add a bunch of items at once using different methods.
35155 // Only the last item added will be returned.
35156 var item = menu.add(
35157 menuItem, // add existing item by ref
35158 'Dynamic Item', // new TextItem
35159 '-', // new separator
35160 { text: 'Config Item' } // new item by config
35163 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35164 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35167 var a = arguments, l = a.length, item;
35168 for(var i = 0; i < l; i++){
35170 if ((typeof(el) == "object") && el.xtype && el.xns) {
35171 el = Roo.factory(el, Roo.menu);
35174 if(el.render){ // some kind of Item
35175 item = this.addItem(el);
35176 }else if(typeof el == "string"){ // string
35177 if(el == "separator" || el == "-"){
35178 item = this.addSeparator();
35180 item = this.addText(el);
35182 }else if(el.tagName || el.el){ // element
35183 item = this.addElement(el);
35184 }else if(typeof el == "object"){ // must be menu item config?
35185 item = this.addMenuItem(el);
35192 * Returns this menu's underlying {@link Roo.Element} object
35193 * @return {Roo.Element} The element
35195 getEl : function(){
35203 * Adds a separator bar to the menu
35204 * @return {Roo.menu.Item} The menu item that was added
35206 addSeparator : function(){
35207 return this.addItem(new Roo.menu.Separator());
35211 * Adds an {@link Roo.Element} object to the menu
35212 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35213 * @return {Roo.menu.Item} The menu item that was added
35215 addElement : function(el){
35216 return this.addItem(new Roo.menu.BaseItem(el));
35220 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35221 * @param {Roo.menu.Item} item The menu item to add
35222 * @return {Roo.menu.Item} The menu item that was added
35224 addItem : function(item){
35225 this.items.add(item);
35227 var li = document.createElement("li");
35228 li.className = "x-menu-list-item";
35229 this.ul.dom.appendChild(li);
35230 item.render(li, this);
35231 this.delayAutoWidth();
35237 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35238 * @param {Object} config A MenuItem config object
35239 * @return {Roo.menu.Item} The menu item that was added
35241 addMenuItem : function(config){
35242 if(!(config instanceof Roo.menu.Item)){
35243 if(typeof config.checked == "boolean"){ // must be check menu item config?
35244 config = new Roo.menu.CheckItem(config);
35246 config = new Roo.menu.Item(config);
35249 return this.addItem(config);
35253 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35254 * @param {String} text The text to display in the menu item
35255 * @return {Roo.menu.Item} The menu item that was added
35257 addText : function(text){
35258 return this.addItem(new Roo.menu.TextItem({ text : text }));
35262 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35263 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35264 * @param {Roo.menu.Item} item The menu item to add
35265 * @return {Roo.menu.Item} The menu item that was added
35267 insert : function(index, item){
35268 this.items.insert(index, item);
35270 var li = document.createElement("li");
35271 li.className = "x-menu-list-item";
35272 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35273 item.render(li, this);
35274 this.delayAutoWidth();
35280 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35281 * @param {Roo.menu.Item} item The menu item to remove
35283 remove : function(item){
35284 this.items.removeKey(item.id);
35289 * Removes and destroys all items in the menu
35291 removeAll : function(){
35293 while(f = this.items.first()){
35299 // MenuNav is a private utility class used internally by the Menu
35300 Roo.menu.MenuNav = function(menu){
35301 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35302 this.scope = this.menu = menu;
35305 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35306 doRelay : function(e, h){
35307 var k = e.getKey();
35308 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35309 this.menu.tryActivate(0, 1);
35312 return h.call(this.scope || this, e, this.menu);
35315 up : function(e, m){
35316 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35317 m.tryActivate(m.items.length-1, -1);
35321 down : function(e, m){
35322 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35323 m.tryActivate(0, 1);
35327 right : function(e, m){
35329 m.activeItem.expandMenu(true);
35333 left : function(e, m){
35335 if(m.parentMenu && m.parentMenu.activeItem){
35336 m.parentMenu.activeItem.activate();
35340 enter : function(e, m){
35342 e.stopPropagation();
35343 m.activeItem.onClick(e);
35344 m.fireEvent("click", this, m.activeItem);
35350 * Ext JS Library 1.1.1
35351 * Copyright(c) 2006-2007, Ext JS, LLC.
35353 * Originally Released Under LGPL - original licence link has changed is not relivant.
35356 * <script type="text/javascript">
35360 * @class Roo.menu.MenuMgr
35361 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35364 Roo.menu.MenuMgr = function(){
35365 var menus, active, groups = {}, attached = false, lastShow = new Date();
35367 // private - called when first menu is created
35370 active = new Roo.util.MixedCollection();
35371 Roo.get(document).addKeyListener(27, function(){
35372 if(active.length > 0){
35379 function hideAll(){
35380 if(active && active.length > 0){
35381 var c = active.clone();
35382 c.each(function(m){
35389 function onHide(m){
35391 if(active.length < 1){
35392 Roo.get(document).un("mousedown", onMouseDown);
35398 function onShow(m){
35399 var last = active.last();
35400 lastShow = new Date();
35403 Roo.get(document).on("mousedown", onMouseDown);
35407 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35408 m.parentMenu.activeChild = m;
35409 }else if(last && last.isVisible()){
35410 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35415 function onBeforeHide(m){
35417 m.activeChild.hide();
35419 if(m.autoHideTimer){
35420 clearTimeout(m.autoHideTimer);
35421 delete m.autoHideTimer;
35426 function onBeforeShow(m){
35427 var pm = m.parentMenu;
35428 if(!pm && !m.allowOtherMenus){
35430 }else if(pm && pm.activeChild && active != m){
35431 pm.activeChild.hide();
35436 function onMouseDown(e){
35437 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35443 function onBeforeCheck(mi, state){
35445 var g = groups[mi.group];
35446 for(var i = 0, l = g.length; i < l; i++){
35448 g[i].setChecked(false);
35457 * Hides all menus that are currently visible
35459 hideAll : function(){
35464 register : function(menu){
35468 menus[menu.id] = menu;
35469 menu.on("beforehide", onBeforeHide);
35470 menu.on("hide", onHide);
35471 menu.on("beforeshow", onBeforeShow);
35472 menu.on("show", onShow);
35473 var g = menu.group;
35474 if(g && menu.events["checkchange"]){
35478 groups[g].push(menu);
35479 menu.on("checkchange", onCheck);
35484 * Returns a {@link Roo.menu.Menu} object
35485 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
35486 * be used to generate and return a new Menu instance.
35488 get : function(menu){
35489 if(typeof menu == "string"){ // menu id
35490 return menus[menu];
35491 }else if(menu.events){ // menu instance
35493 }else if(typeof menu.length == 'number'){ // array of menu items?
35494 return new Roo.menu.Menu({items:menu});
35495 }else{ // otherwise, must be a config
35496 return new Roo.menu.Menu(menu);
35501 unregister : function(menu){
35502 delete menus[menu.id];
35503 menu.un("beforehide", onBeforeHide);
35504 menu.un("hide", onHide);
35505 menu.un("beforeshow", onBeforeShow);
35506 menu.un("show", onShow);
35507 var g = menu.group;
35508 if(g && menu.events["checkchange"]){
35509 groups[g].remove(menu);
35510 menu.un("checkchange", onCheck);
35515 registerCheckable : function(menuItem){
35516 var g = menuItem.group;
35521 groups[g].push(menuItem);
35522 menuItem.on("beforecheckchange", onBeforeCheck);
35527 unregisterCheckable : function(menuItem){
35528 var g = menuItem.group;
35530 groups[g].remove(menuItem);
35531 menuItem.un("beforecheckchange", onBeforeCheck);
35537 * Ext JS Library 1.1.1
35538 * Copyright(c) 2006-2007, Ext JS, LLC.
35540 * Originally Released Under LGPL - original licence link has changed is not relivant.
35543 * <script type="text/javascript">
35548 * @class Roo.menu.BaseItem
35549 * @extends Roo.Component
35550 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
35551 * management and base configuration options shared by all menu components.
35553 * Creates a new BaseItem
35554 * @param {Object} config Configuration options
35556 Roo.menu.BaseItem = function(config){
35557 Roo.menu.BaseItem.superclass.constructor.call(this, config);
35562 * Fires when this item is clicked
35563 * @param {Roo.menu.BaseItem} this
35564 * @param {Roo.EventObject} e
35569 * Fires when this item is activated
35570 * @param {Roo.menu.BaseItem} this
35574 * @event deactivate
35575 * Fires when this item is deactivated
35576 * @param {Roo.menu.BaseItem} this
35582 this.on("click", this.handler, this.scope, true);
35586 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
35588 * @cfg {Function} handler
35589 * A function that will handle the click event of this menu item (defaults to undefined)
35592 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
35594 canActivate : false,
35597 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
35602 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
35604 activeClass : "x-menu-item-active",
35606 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
35608 hideOnClick : true,
35610 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
35615 ctype: "Roo.menu.BaseItem",
35618 actionMode : "container",
35621 render : function(container, parentMenu){
35622 this.parentMenu = parentMenu;
35623 Roo.menu.BaseItem.superclass.render.call(this, container);
35624 this.container.menuItemId = this.id;
35628 onRender : function(container, position){
35629 this.el = Roo.get(this.el);
35630 container.dom.appendChild(this.el.dom);
35634 onClick : function(e){
35635 if(!this.disabled && this.fireEvent("click", this, e) !== false
35636 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
35637 this.handleClick(e);
35644 activate : function(){
35648 var li = this.container;
35649 li.addClass(this.activeClass);
35650 this.region = li.getRegion().adjust(2, 2, -2, -2);
35651 this.fireEvent("activate", this);
35656 deactivate : function(){
35657 this.container.removeClass(this.activeClass);
35658 this.fireEvent("deactivate", this);
35662 shouldDeactivate : function(e){
35663 return !this.region || !this.region.contains(e.getPoint());
35667 handleClick : function(e){
35668 if(this.hideOnClick){
35669 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
35674 expandMenu : function(autoActivate){
35679 hideMenu : function(){
35684 * Ext JS Library 1.1.1
35685 * Copyright(c) 2006-2007, Ext JS, LLC.
35687 * Originally Released Under LGPL - original licence link has changed is not relivant.
35690 * <script type="text/javascript">
35694 * @class Roo.menu.Adapter
35695 * @extends Roo.menu.BaseItem
35696 * 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.
35697 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
35699 * Creates a new Adapter
35700 * @param {Object} config Configuration options
35702 Roo.menu.Adapter = function(component, config){
35703 Roo.menu.Adapter.superclass.constructor.call(this, config);
35704 this.component = component;
35706 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
35708 canActivate : true,
35711 onRender : function(container, position){
35712 this.component.render(container);
35713 this.el = this.component.getEl();
35717 activate : function(){
35721 this.component.focus();
35722 this.fireEvent("activate", this);
35727 deactivate : function(){
35728 this.fireEvent("deactivate", this);
35732 disable : function(){
35733 this.component.disable();
35734 Roo.menu.Adapter.superclass.disable.call(this);
35738 enable : function(){
35739 this.component.enable();
35740 Roo.menu.Adapter.superclass.enable.call(this);
35744 * Ext JS Library 1.1.1
35745 * Copyright(c) 2006-2007, Ext JS, LLC.
35747 * Originally Released Under LGPL - original licence link has changed is not relivant.
35750 * <script type="text/javascript">
35754 * @class Roo.menu.TextItem
35755 * @extends Roo.menu.BaseItem
35756 * Adds a static text string to a menu, usually used as either a heading or group separator.
35757 * Note: old style constructor with text is still supported.
35760 * Creates a new TextItem
35761 * @param {Object} cfg Configuration
35763 Roo.menu.TextItem = function(cfg){
35764 if (typeof(cfg) == 'string') {
35767 Roo.apply(this,cfg);
35770 Roo.menu.TextItem.superclass.constructor.call(this);
35773 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
35775 * @cfg {Boolean} text Text to show on item.
35780 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35782 hideOnClick : false,
35784 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
35786 itemCls : "x-menu-text",
35789 onRender : function(){
35790 var s = document.createElement("span");
35791 s.className = this.itemCls;
35792 s.innerHTML = this.text;
35794 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
35798 * Ext JS Library 1.1.1
35799 * Copyright(c) 2006-2007, Ext JS, LLC.
35801 * Originally Released Under LGPL - original licence link has changed is not relivant.
35804 * <script type="text/javascript">
35808 * @class Roo.menu.Separator
35809 * @extends Roo.menu.BaseItem
35810 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
35811 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
35813 * @param {Object} config Configuration options
35815 Roo.menu.Separator = function(config){
35816 Roo.menu.Separator.superclass.constructor.call(this, config);
35819 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
35821 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
35823 itemCls : "x-menu-sep",
35825 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
35827 hideOnClick : false,
35830 onRender : function(li){
35831 var s = document.createElement("span");
35832 s.className = this.itemCls;
35833 s.innerHTML = " ";
35835 li.addClass("x-menu-sep-li");
35836 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
35840 * Ext JS Library 1.1.1
35841 * Copyright(c) 2006-2007, Ext JS, LLC.
35843 * Originally Released Under LGPL - original licence link has changed is not relivant.
35846 * <script type="text/javascript">
35849 * @class Roo.menu.Item
35850 * @extends Roo.menu.BaseItem
35851 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
35852 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
35853 * activation and click handling.
35855 * Creates a new Item
35856 * @param {Object} config Configuration options
35858 Roo.menu.Item = function(config){
35859 Roo.menu.Item.superclass.constructor.call(this, config);
35861 this.menu = Roo.menu.MenuMgr.get(this.menu);
35864 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
35867 * @cfg {String} text
35868 * The text to show on the menu item.
35872 * @cfg {String} HTML to render in menu
35873 * The text to show on the menu item (HTML version).
35877 * @cfg {String} icon
35878 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
35882 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
35884 itemCls : "x-menu-item",
35886 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
35888 canActivate : true,
35890 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
35893 // doc'd in BaseItem
35897 ctype: "Roo.menu.Item",
35900 onRender : function(container, position){
35901 var el = document.createElement("a");
35902 el.hideFocus = true;
35903 el.unselectable = "on";
35904 el.href = this.href || "#";
35905 if(this.hrefTarget){
35906 el.target = this.hrefTarget;
35908 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
35910 var html = this.html.length ? this.html : String.format('{0}',this.text);
35912 el.innerHTML = String.format(
35913 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
35914 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
35916 Roo.menu.Item.superclass.onRender.call(this, container, position);
35920 * Sets the text to display in this menu item
35921 * @param {String} text The text to display
35922 * @param {Boolean} isHTML true to indicate text is pure html.
35924 setText : function(text, isHTML){
35932 var html = this.html.length ? this.html : String.format('{0}',this.text);
35934 this.el.update(String.format(
35935 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
35936 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
35937 this.parentMenu.autoWidth();
35942 handleClick : function(e){
35943 if(!this.href){ // if no link defined, stop the event automatically
35946 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
35950 activate : function(autoExpand){
35951 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
35961 shouldDeactivate : function(e){
35962 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
35963 if(this.menu && this.menu.isVisible()){
35964 return !this.menu.getEl().getRegion().contains(e.getPoint());
35972 deactivate : function(){
35973 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
35978 expandMenu : function(autoActivate){
35979 if(!this.disabled && this.menu){
35980 clearTimeout(this.hideTimer);
35981 delete this.hideTimer;
35982 if(!this.menu.isVisible() && !this.showTimer){
35983 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
35984 }else if (this.menu.isVisible() && autoActivate){
35985 this.menu.tryActivate(0, 1);
35991 deferExpand : function(autoActivate){
35992 delete this.showTimer;
35993 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
35995 this.menu.tryActivate(0, 1);
36000 hideMenu : function(){
36001 clearTimeout(this.showTimer);
36002 delete this.showTimer;
36003 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36004 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36009 deferHide : function(){
36010 delete this.hideTimer;
36015 * Ext JS Library 1.1.1
36016 * Copyright(c) 2006-2007, Ext JS, LLC.
36018 * Originally Released Under LGPL - original licence link has changed is not relivant.
36021 * <script type="text/javascript">
36025 * @class Roo.menu.CheckItem
36026 * @extends Roo.menu.Item
36027 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36029 * Creates a new CheckItem
36030 * @param {Object} config Configuration options
36032 Roo.menu.CheckItem = function(config){
36033 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36036 * @event beforecheckchange
36037 * Fires before the checked value is set, providing an opportunity to cancel if needed
36038 * @param {Roo.menu.CheckItem} this
36039 * @param {Boolean} checked The new checked value that will be set
36041 "beforecheckchange" : true,
36043 * @event checkchange
36044 * Fires after the checked value has been set
36045 * @param {Roo.menu.CheckItem} this
36046 * @param {Boolean} checked The checked value that was set
36048 "checkchange" : true
36050 if(this.checkHandler){
36051 this.on('checkchange', this.checkHandler, this.scope);
36054 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36056 * @cfg {String} group
36057 * All check items with the same group name will automatically be grouped into a single-select
36058 * radio button group (defaults to '')
36061 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36063 itemCls : "x-menu-item x-menu-check-item",
36065 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36067 groupClass : "x-menu-group-item",
36070 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36071 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36072 * initialized with checked = true will be rendered as checked.
36077 ctype: "Roo.menu.CheckItem",
36080 onRender : function(c){
36081 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36083 this.el.addClass(this.groupClass);
36085 Roo.menu.MenuMgr.registerCheckable(this);
36087 this.checked = false;
36088 this.setChecked(true, true);
36093 destroy : function(){
36095 Roo.menu.MenuMgr.unregisterCheckable(this);
36097 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36101 * Set the checked state of this item
36102 * @param {Boolean} checked The new checked value
36103 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36105 setChecked : function(state, suppressEvent){
36106 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36107 if(this.container){
36108 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36110 this.checked = state;
36111 if(suppressEvent !== true){
36112 this.fireEvent("checkchange", this, state);
36118 handleClick : function(e){
36119 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36120 this.setChecked(!this.checked);
36122 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36126 * Ext JS Library 1.1.1
36127 * Copyright(c) 2006-2007, Ext JS, LLC.
36129 * Originally Released Under LGPL - original licence link has changed is not relivant.
36132 * <script type="text/javascript">
36136 * @class Roo.menu.DateItem
36137 * @extends Roo.menu.Adapter
36138 * A menu item that wraps the {@link Roo.DatPicker} component.
36140 * Creates a new DateItem
36141 * @param {Object} config Configuration options
36143 Roo.menu.DateItem = function(config){
36144 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36145 /** The Roo.DatePicker object @type Roo.DatePicker */
36146 this.picker = this.component;
36147 this.addEvents({select: true});
36149 this.picker.on("render", function(picker){
36150 picker.getEl().swallowEvent("click");
36151 picker.container.addClass("x-menu-date-item");
36154 this.picker.on("select", this.onSelect, this);
36157 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36159 onSelect : function(picker, date){
36160 this.fireEvent("select", this, date, picker);
36161 Roo.menu.DateItem.superclass.handleClick.call(this);
36165 * Ext JS Library 1.1.1
36166 * Copyright(c) 2006-2007, Ext JS, LLC.
36168 * Originally Released Under LGPL - original licence link has changed is not relivant.
36171 * <script type="text/javascript">
36175 * @class Roo.menu.ColorItem
36176 * @extends Roo.menu.Adapter
36177 * A menu item that wraps the {@link Roo.ColorPalette} component.
36179 * Creates a new ColorItem
36180 * @param {Object} config Configuration options
36182 Roo.menu.ColorItem = function(config){
36183 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36184 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36185 this.palette = this.component;
36186 this.relayEvents(this.palette, ["select"]);
36187 if(this.selectHandler){
36188 this.on('select', this.selectHandler, this.scope);
36191 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36193 * Ext JS Library 1.1.1
36194 * Copyright(c) 2006-2007, Ext JS, LLC.
36196 * Originally Released Under LGPL - original licence link has changed is not relivant.
36199 * <script type="text/javascript">
36204 * @class Roo.menu.DateMenu
36205 * @extends Roo.menu.Menu
36206 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36208 * Creates a new DateMenu
36209 * @param {Object} config Configuration options
36211 Roo.menu.DateMenu = function(config){
36212 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36214 var di = new Roo.menu.DateItem(config);
36217 * The {@link Roo.DatePicker} instance for this DateMenu
36220 this.picker = di.picker;
36223 * @param {DatePicker} picker
36224 * @param {Date} date
36226 this.relayEvents(di, ["select"]);
36227 this.on('beforeshow', function(){
36229 this.picker.hideMonthPicker(false);
36233 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36237 * Ext JS Library 1.1.1
36238 * Copyright(c) 2006-2007, Ext JS, LLC.
36240 * Originally Released Under LGPL - original licence link has changed is not relivant.
36243 * <script type="text/javascript">
36248 * @class Roo.menu.ColorMenu
36249 * @extends Roo.menu.Menu
36250 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36252 * Creates a new ColorMenu
36253 * @param {Object} config Configuration options
36255 Roo.menu.ColorMenu = function(config){
36256 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36258 var ci = new Roo.menu.ColorItem(config);
36261 * The {@link Roo.ColorPalette} instance for this ColorMenu
36262 * @type ColorPalette
36264 this.palette = ci.palette;
36267 * @param {ColorPalette} palette
36268 * @param {String} color
36270 this.relayEvents(ci, ["select"]);
36272 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36274 * Ext JS Library 1.1.1
36275 * Copyright(c) 2006-2007, Ext JS, LLC.
36277 * Originally Released Under LGPL - original licence link has changed is not relivant.
36280 * <script type="text/javascript">
36284 * @class Roo.form.Field
36285 * @extends Roo.BoxComponent
36286 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36288 * Creates a new Field
36289 * @param {Object} config Configuration options
36291 Roo.form.Field = function(config){
36292 Roo.form.Field.superclass.constructor.call(this, config);
36295 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36297 * @cfg {String} fieldLabel Label to use when rendering a form.
36300 * @cfg {String} qtip Mouse over tip
36304 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36306 invalidClass : "x-form-invalid",
36308 * @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")
36310 invalidText : "The value in this field is invalid",
36312 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36314 focusClass : "x-form-focus",
36316 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36317 automatic validation (defaults to "keyup").
36319 validationEvent : "keyup",
36321 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36323 validateOnBlur : true,
36325 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36327 validationDelay : 250,
36329 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36330 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36332 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36334 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36336 fieldClass : "x-form-field",
36338 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36341 ----------- ----------------------------------------------------------------------
36342 qtip Display a quick tip when the user hovers over the field
36343 title Display a default browser title attribute popup
36344 under Add a block div beneath the field containing the error text
36345 side Add an error icon to the right of the field with a popup on hover
36346 [element id] Add the error text directly to the innerHTML of the specified element
36349 msgTarget : 'qtip',
36351 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36356 * @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.
36361 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36366 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36368 inputType : undefined,
36371 * @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).
36373 tabIndex : undefined,
36376 isFormField : true,
36381 * @property {Roo.Element} fieldEl
36382 * Element Containing the rendered Field (with label etc.)
36385 * @cfg {Mixed} value A value to initialize this field with.
36390 * @cfg {String} name The field's HTML name attribute.
36393 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36397 initComponent : function(){
36398 Roo.form.Field.superclass.initComponent.call(this);
36402 * Fires when this field receives input focus.
36403 * @param {Roo.form.Field} this
36408 * Fires when this field loses input focus.
36409 * @param {Roo.form.Field} this
36413 * @event specialkey
36414 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36415 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36416 * @param {Roo.form.Field} this
36417 * @param {Roo.EventObject} e The event object
36422 * Fires just before the field blurs if the field value has changed.
36423 * @param {Roo.form.Field} this
36424 * @param {Mixed} newValue The new value
36425 * @param {Mixed} oldValue The original value
36430 * Fires after the field has been marked as invalid.
36431 * @param {Roo.form.Field} this
36432 * @param {String} msg The validation message
36437 * Fires after the field has been validated with no errors.
36438 * @param {Roo.form.Field} this
36443 * Fires after the key up
36444 * @param {Roo.form.Field} this
36445 * @param {Roo.EventObject} e The event Object
36452 * Returns the name attribute of the field if available
36453 * @return {String} name The field name
36455 getName: function(){
36456 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36460 onRender : function(ct, position){
36461 Roo.form.Field.superclass.onRender.call(this, ct, position);
36463 var cfg = this.getAutoCreate();
36465 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
36467 if (!cfg.name.length) {
36470 if(this.inputType){
36471 cfg.type = this.inputType;
36473 this.el = ct.createChild(cfg, position);
36475 var type = this.el.dom.type;
36477 if(type == 'password'){
36480 this.el.addClass('x-form-'+type);
36483 this.el.dom.readOnly = true;
36485 if(this.tabIndex !== undefined){
36486 this.el.dom.setAttribute('tabIndex', this.tabIndex);
36489 this.el.addClass([this.fieldClass, this.cls]);
36494 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
36495 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
36496 * @return {Roo.form.Field} this
36498 applyTo : function(target){
36499 this.allowDomMove = false;
36500 this.el = Roo.get(target);
36501 this.render(this.el.dom.parentNode);
36506 initValue : function(){
36507 if(this.value !== undefined){
36508 this.setValue(this.value);
36509 }else if(this.el.dom.value.length > 0){
36510 this.setValue(this.el.dom.value);
36515 * Returns true if this field has been changed since it was originally loaded and is not disabled.
36517 isDirty : function() {
36518 if(this.disabled) {
36521 return String(this.getValue()) !== String(this.originalValue);
36525 afterRender : function(){
36526 Roo.form.Field.superclass.afterRender.call(this);
36531 fireKey : function(e){
36532 //Roo.log('field ' + e.getKey());
36533 if(e.isNavKeyPress()){
36534 this.fireEvent("specialkey", this, e);
36539 * Resets the current field value to the originally loaded value and clears any validation messages
36541 reset : function(){
36542 this.setValue(this.originalValue);
36543 this.clearInvalid();
36547 initEvents : function(){
36548 // safari killled keypress - so keydown is now used..
36549 this.el.on("keydown" , this.fireKey, this);
36550 this.el.on("focus", this.onFocus, this);
36551 this.el.on("blur", this.onBlur, this);
36552 this.el.relayEvent('keyup', this);
36554 // reference to original value for reset
36555 this.originalValue = this.getValue();
36559 onFocus : function(){
36560 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36561 this.el.addClass(this.focusClass);
36563 if(!this.hasFocus){
36564 this.hasFocus = true;
36565 this.startValue = this.getValue();
36566 this.fireEvent("focus", this);
36570 beforeBlur : Roo.emptyFn,
36573 onBlur : function(){
36575 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
36576 this.el.removeClass(this.focusClass);
36578 this.hasFocus = false;
36579 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
36582 var v = this.getValue();
36583 if(String(v) !== String(this.startValue)){
36584 this.fireEvent('change', this, v, this.startValue);
36586 this.fireEvent("blur", this);
36590 * Returns whether or not the field value is currently valid
36591 * @param {Boolean} preventMark True to disable marking the field invalid
36592 * @return {Boolean} True if the value is valid, else false
36594 isValid : function(preventMark){
36598 var restore = this.preventMark;
36599 this.preventMark = preventMark === true;
36600 var v = this.validateValue(this.processValue(this.getRawValue()));
36601 this.preventMark = restore;
36606 * Validates the field value
36607 * @return {Boolean} True if the value is valid, else false
36609 validate : function(){
36610 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
36611 this.clearInvalid();
36617 processValue : function(value){
36622 // Subclasses should provide the validation implementation by overriding this
36623 validateValue : function(value){
36628 * Mark this field as invalid
36629 * @param {String} msg The validation message
36631 markInvalid : function(msg){
36632 if(!this.rendered || this.preventMark){ // not rendered
36635 this.el.addClass(this.invalidClass);
36636 msg = msg || this.invalidText;
36637 switch(this.msgTarget){
36639 this.el.dom.qtip = msg;
36640 this.el.dom.qclass = 'x-form-invalid-tip';
36641 if(Roo.QuickTips){ // fix for floating editors interacting with DND
36642 Roo.QuickTips.enable();
36646 this.el.dom.title = msg;
36650 var elp = this.el.findParent('.x-form-element', 5, true);
36651 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
36652 this.errorEl.setWidth(elp.getWidth(true)-20);
36654 this.errorEl.update(msg);
36655 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
36658 if(!this.errorIcon){
36659 var elp = this.el.findParent('.x-form-element', 5, true);
36660 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
36662 this.alignErrorIcon();
36663 this.errorIcon.dom.qtip = msg;
36664 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
36665 this.errorIcon.show();
36666 this.on('resize', this.alignErrorIcon, this);
36669 var t = Roo.getDom(this.msgTarget);
36671 t.style.display = this.msgDisplay;
36674 this.fireEvent('invalid', this, msg);
36678 alignErrorIcon : function(){
36679 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
36683 * Clear any invalid styles/messages for this field
36685 clearInvalid : function(){
36686 if(!this.rendered || this.preventMark){ // not rendered
36689 this.el.removeClass(this.invalidClass);
36690 switch(this.msgTarget){
36692 this.el.dom.qtip = '';
36695 this.el.dom.title = '';
36699 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
36703 if(this.errorIcon){
36704 this.errorIcon.dom.qtip = '';
36705 this.errorIcon.hide();
36706 this.un('resize', this.alignErrorIcon, this);
36710 var t = Roo.getDom(this.msgTarget);
36712 t.style.display = 'none';
36715 this.fireEvent('valid', this);
36719 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
36720 * @return {Mixed} value The field value
36722 getRawValue : function(){
36723 var v = this.el.getValue();
36729 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
36730 * @return {Mixed} value The field value
36732 getValue : function(){
36733 var v = this.el.getValue();
36739 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
36740 * @param {Mixed} value The value to set
36742 setRawValue : function(v){
36743 return this.el.dom.value = (v === null || v === undefined ? '' : v);
36747 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
36748 * @param {Mixed} value The value to set
36750 setValue : function(v){
36753 this.el.dom.value = (v === null || v === undefined ? '' : v);
36758 adjustSize : function(w, h){
36759 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
36760 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
36764 adjustWidth : function(tag, w){
36765 tag = tag.toLowerCase();
36766 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
36767 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
36768 if(tag == 'input'){
36771 if(tag == 'textarea'){
36774 }else if(Roo.isOpera){
36775 if(tag == 'input'){
36778 if(tag == 'textarea'){
36788 // anything other than normal should be considered experimental
36789 Roo.form.Field.msgFx = {
36791 show: function(msgEl, f){
36792 msgEl.setDisplayed('block');
36795 hide : function(msgEl, f){
36796 msgEl.setDisplayed(false).update('');
36801 show: function(msgEl, f){
36802 msgEl.slideIn('t', {stopFx:true});
36805 hide : function(msgEl, f){
36806 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
36811 show: function(msgEl, f){
36812 msgEl.fixDisplay();
36813 msgEl.alignTo(f.el, 'tl-tr');
36814 msgEl.slideIn('l', {stopFx:true});
36817 hide : function(msgEl, f){
36818 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
36823 * Ext JS Library 1.1.1
36824 * Copyright(c) 2006-2007, Ext JS, LLC.
36826 * Originally Released Under LGPL - original licence link has changed is not relivant.
36829 * <script type="text/javascript">
36834 * @class Roo.form.TextField
36835 * @extends Roo.form.Field
36836 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
36837 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
36839 * Creates a new TextField
36840 * @param {Object} config Configuration options
36842 Roo.form.TextField = function(config){
36843 Roo.form.TextField.superclass.constructor.call(this, config);
36847 * Fires when the autosize function is triggered. The field may or may not have actually changed size
36848 * according to the default logic, but this event provides a hook for the developer to apply additional
36849 * logic at runtime to resize the field if needed.
36850 * @param {Roo.form.Field} this This text field
36851 * @param {Number} width The new field width
36857 Roo.extend(Roo.form.TextField, Roo.form.Field, {
36859 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
36863 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
36867 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
36871 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
36875 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
36879 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
36881 disableKeyFilter : false,
36883 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
36887 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
36891 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
36893 maxLength : Number.MAX_VALUE,
36895 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
36897 minLengthText : "The minimum length for this field is {0}",
36899 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
36901 maxLengthText : "The maximum length for this field is {0}",
36903 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
36905 selectOnFocus : false,
36907 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
36909 blankText : "This field is required",
36911 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
36912 * If available, this function will be called only after the basic validators all return true, and will be passed the
36913 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
36917 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
36918 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
36919 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
36923 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
36927 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
36933 initEvents : function()
36935 if (this.emptyText) {
36936 this.el.attr('placeholder', this.emptyText);
36939 Roo.form.TextField.superclass.initEvents.call(this);
36940 if(this.validationEvent == 'keyup'){
36941 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
36942 this.el.on('keyup', this.filterValidation, this);
36944 else if(this.validationEvent !== false){
36945 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
36948 if(this.selectOnFocus){
36949 this.on("focus", this.preFocus, this);
36952 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
36953 this.el.on("keypress", this.filterKeys, this);
36956 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
36957 this.el.on("click", this.autoSize, this);
36959 if(this.el.is('input[type=password]') && Roo.isSafari){
36960 this.el.on('keydown', this.SafariOnKeyDown, this);
36964 processValue : function(value){
36965 if(this.stripCharsRe){
36966 var newValue = value.replace(this.stripCharsRe, '');
36967 if(newValue !== value){
36968 this.setRawValue(newValue);
36975 filterValidation : function(e){
36976 if(!e.isNavKeyPress()){
36977 this.validationTask.delay(this.validationDelay);
36982 onKeyUp : function(e){
36983 if(!e.isNavKeyPress()){
36989 * Resets the current field value to the originally-loaded value and clears any validation messages.
36992 reset : function(){
36993 Roo.form.TextField.superclass.reset.call(this);
36999 preFocus : function(){
37001 if(this.selectOnFocus){
37002 this.el.dom.select();
37008 filterKeys : function(e){
37009 var k = e.getKey();
37010 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37013 var c = e.getCharCode(), cc = String.fromCharCode(c);
37014 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37017 if(!this.maskRe.test(cc)){
37022 setValue : function(v){
37024 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37030 * Validates a value according to the field's validation rules and marks the field as invalid
37031 * if the validation fails
37032 * @param {Mixed} value The value to validate
37033 * @return {Boolean} True if the value is valid, else false
37035 validateValue : function(value){
37036 if(value.length < 1) { // if it's blank
37037 if(this.allowBlank){
37038 this.clearInvalid();
37041 this.markInvalid(this.blankText);
37045 if(value.length < this.minLength){
37046 this.markInvalid(String.format(this.minLengthText, this.minLength));
37049 if(value.length > this.maxLength){
37050 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37054 var vt = Roo.form.VTypes;
37055 if(!vt[this.vtype](value, this)){
37056 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37060 if(typeof this.validator == "function"){
37061 var msg = this.validator(value);
37063 this.markInvalid(msg);
37067 if(this.regex && !this.regex.test(value)){
37068 this.markInvalid(this.regexText);
37075 * Selects text in this field
37076 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37077 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37079 selectText : function(start, end){
37080 var v = this.getRawValue();
37082 start = start === undefined ? 0 : start;
37083 end = end === undefined ? v.length : end;
37084 var d = this.el.dom;
37085 if(d.setSelectionRange){
37086 d.setSelectionRange(start, end);
37087 }else if(d.createTextRange){
37088 var range = d.createTextRange();
37089 range.moveStart("character", start);
37090 range.moveEnd("character", v.length-end);
37097 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37098 * This only takes effect if grow = true, and fires the autosize event.
37100 autoSize : function(){
37101 if(!this.grow || !this.rendered){
37105 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37108 var v = el.dom.value;
37109 var d = document.createElement('div');
37110 d.appendChild(document.createTextNode(v));
37114 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37115 this.el.setWidth(w);
37116 this.fireEvent("autosize", this, w);
37120 SafariOnKeyDown : function(event)
37122 // this is a workaround for a password hang bug on chrome/ webkit.
37124 var isSelectAll = false;
37126 if(this.el.dom.selectionEnd > 0){
37127 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37129 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37130 event.preventDefault();
37135 if(isSelectAll){ // backspace and delete key
37137 event.preventDefault();
37138 // this is very hacky as keydown always get's upper case.
37140 var cc = String.fromCharCode(event.getCharCode());
37141 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37149 * Ext JS Library 1.1.1
37150 * Copyright(c) 2006-2007, Ext JS, LLC.
37152 * Originally Released Under LGPL - original licence link has changed is not relivant.
37155 * <script type="text/javascript">
37159 * @class Roo.form.Hidden
37160 * @extends Roo.form.TextField
37161 * Simple Hidden element used on forms
37163 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37166 * Creates a new Hidden form element.
37167 * @param {Object} config Configuration options
37172 // easy hidden field...
37173 Roo.form.Hidden = function(config){
37174 Roo.form.Hidden.superclass.constructor.call(this, config);
37177 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37179 inputType: 'hidden',
37182 labelSeparator: '',
37184 itemCls : 'x-form-item-display-none'
37192 * Ext JS Library 1.1.1
37193 * Copyright(c) 2006-2007, Ext JS, LLC.
37195 * Originally Released Under LGPL - original licence link has changed is not relivant.
37198 * <script type="text/javascript">
37202 * @class Roo.form.TriggerField
37203 * @extends Roo.form.TextField
37204 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37205 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37206 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37207 * for which you can provide a custom implementation. For example:
37209 var trigger = new Roo.form.TriggerField();
37210 trigger.onTriggerClick = myTriggerFn;
37211 trigger.applyTo('my-field');
37214 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37215 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37216 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37217 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37219 * Create a new TriggerField.
37220 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37221 * to the base TextField)
37223 Roo.form.TriggerField = function(config){
37224 this.mimicing = false;
37225 Roo.form.TriggerField.superclass.constructor.call(this, config);
37228 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37230 * @cfg {String} triggerClass A CSS class to apply to the trigger
37233 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37234 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37236 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37238 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37242 /** @cfg {Boolean} grow @hide */
37243 /** @cfg {Number} growMin @hide */
37244 /** @cfg {Number} growMax @hide */
37250 autoSize: Roo.emptyFn,
37254 deferHeight : true,
37257 actionMode : 'wrap',
37259 onResize : function(w, h){
37260 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37261 if(typeof w == 'number'){
37262 var x = w - this.trigger.getWidth();
37263 this.el.setWidth(this.adjustWidth('input', x));
37264 this.trigger.setStyle('left', x+'px');
37269 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37272 getResizeEl : function(){
37277 getPositionEl : function(){
37282 alignErrorIcon : function(){
37283 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37287 onRender : function(ct, position){
37288 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37289 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37290 this.trigger = this.wrap.createChild(this.triggerConfig ||
37291 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37292 if(this.hideTrigger){
37293 this.trigger.setDisplayed(false);
37295 this.initTrigger();
37297 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37302 initTrigger : function(){
37303 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37304 this.trigger.addClassOnOver('x-form-trigger-over');
37305 this.trigger.addClassOnClick('x-form-trigger-click');
37309 onDestroy : function(){
37311 this.trigger.removeAllListeners();
37312 this.trigger.remove();
37315 this.wrap.remove();
37317 Roo.form.TriggerField.superclass.onDestroy.call(this);
37321 onFocus : function(){
37322 Roo.form.TriggerField.superclass.onFocus.call(this);
37323 if(!this.mimicing){
37324 this.wrap.addClass('x-trigger-wrap-focus');
37325 this.mimicing = true;
37326 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37327 if(this.monitorTab){
37328 this.el.on("keydown", this.checkTab, this);
37334 checkTab : function(e){
37335 if(e.getKey() == e.TAB){
37336 this.triggerBlur();
37341 onBlur : function(){
37346 mimicBlur : function(e, t){
37347 if(!this.wrap.contains(t) && this.validateBlur()){
37348 this.triggerBlur();
37353 triggerBlur : function(){
37354 this.mimicing = false;
37355 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37356 if(this.monitorTab){
37357 this.el.un("keydown", this.checkTab, this);
37359 this.wrap.removeClass('x-trigger-wrap-focus');
37360 Roo.form.TriggerField.superclass.onBlur.call(this);
37364 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37365 validateBlur : function(e, t){
37370 onDisable : function(){
37371 Roo.form.TriggerField.superclass.onDisable.call(this);
37373 this.wrap.addClass('x-item-disabled');
37378 onEnable : function(){
37379 Roo.form.TriggerField.superclass.onEnable.call(this);
37381 this.wrap.removeClass('x-item-disabled');
37386 onShow : function(){
37387 var ae = this.getActionEl();
37390 ae.dom.style.display = '';
37391 ae.dom.style.visibility = 'visible';
37397 onHide : function(){
37398 var ae = this.getActionEl();
37399 ae.dom.style.display = 'none';
37403 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37404 * by an implementing function.
37406 * @param {EventObject} e
37408 onTriggerClick : Roo.emptyFn
37411 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37412 // to be extended by an implementing class. For an example of implementing this class, see the custom
37413 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37414 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37415 initComponent : function(){
37416 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37418 this.triggerConfig = {
37419 tag:'span', cls:'x-form-twin-triggers', cn:[
37420 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37421 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37425 getTrigger : function(index){
37426 return this.triggers[index];
37429 initTrigger : function(){
37430 var ts = this.trigger.select('.x-form-trigger', true);
37431 this.wrap.setStyle('overflow', 'hidden');
37432 var triggerField = this;
37433 ts.each(function(t, all, index){
37434 t.hide = function(){
37435 var w = triggerField.wrap.getWidth();
37436 this.dom.style.display = 'none';
37437 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37439 t.show = function(){
37440 var w = triggerField.wrap.getWidth();
37441 this.dom.style.display = '';
37442 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37444 var triggerIndex = 'Trigger'+(index+1);
37446 if(this['hide'+triggerIndex]){
37447 t.dom.style.display = 'none';
37449 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37450 t.addClassOnOver('x-form-trigger-over');
37451 t.addClassOnClick('x-form-trigger-click');
37453 this.triggers = ts.elements;
37456 onTrigger1Click : Roo.emptyFn,
37457 onTrigger2Click : Roo.emptyFn
37460 * Ext JS Library 1.1.1
37461 * Copyright(c) 2006-2007, Ext JS, LLC.
37463 * Originally Released Under LGPL - original licence link has changed is not relivant.
37466 * <script type="text/javascript">
37470 * @class Roo.form.TextArea
37471 * @extends Roo.form.TextField
37472 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
37473 * support for auto-sizing.
37475 * Creates a new TextArea
37476 * @param {Object} config Configuration options
37478 Roo.form.TextArea = function(config){
37479 Roo.form.TextArea.superclass.constructor.call(this, config);
37480 // these are provided exchanges for backwards compat
37481 // minHeight/maxHeight were replaced by growMin/growMax to be
37482 // compatible with TextField growing config values
37483 if(this.minHeight !== undefined){
37484 this.growMin = this.minHeight;
37486 if(this.maxHeight !== undefined){
37487 this.growMax = this.maxHeight;
37491 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
37493 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
37497 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
37501 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
37502 * in the field (equivalent to setting overflow: hidden, defaults to false)
37504 preventScrollbars: false,
37506 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37507 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
37511 onRender : function(ct, position){
37513 this.defaultAutoCreate = {
37515 style:"width:300px;height:60px;",
37516 autocomplete: "off"
37519 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
37521 this.textSizeEl = Roo.DomHelper.append(document.body, {
37522 tag: "pre", cls: "x-form-grow-sizer"
37524 if(this.preventScrollbars){
37525 this.el.setStyle("overflow", "hidden");
37527 this.el.setHeight(this.growMin);
37531 onDestroy : function(){
37532 if(this.textSizeEl){
37533 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
37535 Roo.form.TextArea.superclass.onDestroy.call(this);
37539 onKeyUp : function(e){
37540 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
37546 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
37547 * This only takes effect if grow = true, and fires the autosize event if the height changes.
37549 autoSize : function(){
37550 if(!this.grow || !this.textSizeEl){
37554 var v = el.dom.value;
37555 var ts = this.textSizeEl;
37558 ts.appendChild(document.createTextNode(v));
37561 Roo.fly(ts).setWidth(this.el.getWidth());
37563 v = "  ";
37566 v = v.replace(/\n/g, '<p> </p>');
37568 v += " \n ";
37571 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
37572 if(h != this.lastHeight){
37573 this.lastHeight = h;
37574 this.el.setHeight(h);
37575 this.fireEvent("autosize", this, h);
37580 * Ext JS Library 1.1.1
37581 * Copyright(c) 2006-2007, Ext JS, LLC.
37583 * Originally Released Under LGPL - original licence link has changed is not relivant.
37586 * <script type="text/javascript">
37591 * @class Roo.form.NumberField
37592 * @extends Roo.form.TextField
37593 * Numeric text field that provides automatic keystroke filtering and numeric validation.
37595 * Creates a new NumberField
37596 * @param {Object} config Configuration options
37598 Roo.form.NumberField = function(config){
37599 Roo.form.NumberField.superclass.constructor.call(this, config);
37602 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
37604 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
37606 fieldClass: "x-form-field x-form-num-field",
37608 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
37610 allowDecimals : true,
37612 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
37614 decimalSeparator : ".",
37616 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
37618 decimalPrecision : 2,
37620 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
37622 allowNegative : true,
37624 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
37626 minValue : Number.NEGATIVE_INFINITY,
37628 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
37630 maxValue : Number.MAX_VALUE,
37632 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
37634 minText : "The minimum value for this field is {0}",
37636 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
37638 maxText : "The maximum value for this field is {0}",
37640 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
37641 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
37643 nanText : "{0} is not a valid number",
37646 initEvents : function(){
37647 Roo.form.NumberField.superclass.initEvents.call(this);
37648 var allowed = "0123456789";
37649 if(this.allowDecimals){
37650 allowed += this.decimalSeparator;
37652 if(this.allowNegative){
37655 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
37656 var keyPress = function(e){
37657 var k = e.getKey();
37658 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
37661 var c = e.getCharCode();
37662 if(allowed.indexOf(String.fromCharCode(c)) === -1){
37666 this.el.on("keypress", keyPress, this);
37670 validateValue : function(value){
37671 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
37674 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37677 var num = this.parseValue(value);
37679 this.markInvalid(String.format(this.nanText, value));
37682 if(num < this.minValue){
37683 this.markInvalid(String.format(this.minText, this.minValue));
37686 if(num > this.maxValue){
37687 this.markInvalid(String.format(this.maxText, this.maxValue));
37693 getValue : function(){
37694 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
37698 parseValue : function(value){
37699 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
37700 return isNaN(value) ? '' : value;
37704 fixPrecision : function(value){
37705 var nan = isNaN(value);
37706 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
37707 return nan ? '' : value;
37709 return parseFloat(value).toFixed(this.decimalPrecision);
37712 setValue : function(v){
37713 v = this.fixPrecision(v);
37714 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
37718 decimalPrecisionFcn : function(v){
37719 return Math.floor(v);
37722 beforeBlur : function(){
37723 var v = this.parseValue(this.getRawValue());
37730 * Ext JS Library 1.1.1
37731 * Copyright(c) 2006-2007, Ext JS, LLC.
37733 * Originally Released Under LGPL - original licence link has changed is not relivant.
37736 * <script type="text/javascript">
37740 * @class Roo.form.DateField
37741 * @extends Roo.form.TriggerField
37742 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
37744 * Create a new DateField
37745 * @param {Object} config
37747 Roo.form.DateField = function(config){
37748 Roo.form.DateField.superclass.constructor.call(this, config);
37754 * Fires when a date is selected
37755 * @param {Roo.form.DateField} combo This combo box
37756 * @param {Date} date The date selected
37763 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
37764 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
37765 this.ddMatch = null;
37766 if(this.disabledDates){
37767 var dd = this.disabledDates;
37769 for(var i = 0; i < dd.length; i++){
37771 if(i != dd.length-1) re += "|";
37773 this.ddMatch = new RegExp(re + ")");
37777 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
37779 * @cfg {String} format
37780 * The default date format string which can be overriden for localization support. The format must be
37781 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
37785 * @cfg {String} altFormats
37786 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
37787 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
37789 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
37791 * @cfg {Array} disabledDays
37792 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
37794 disabledDays : null,
37796 * @cfg {String} disabledDaysText
37797 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
37799 disabledDaysText : "Disabled",
37801 * @cfg {Array} disabledDates
37802 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
37803 * expression so they are very powerful. Some examples:
37805 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
37806 * <li>["03/08", "09/16"] would disable those days for every year</li>
37807 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
37808 * <li>["03/../2006"] would disable every day in March 2006</li>
37809 * <li>["^03"] would disable every day in every March</li>
37811 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
37812 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
37814 disabledDates : null,
37816 * @cfg {String} disabledDatesText
37817 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
37819 disabledDatesText : "Disabled",
37821 * @cfg {Date/String} minValue
37822 * The minimum allowed date. Can be either a Javascript date object or a string date in a
37823 * valid format (defaults to null).
37827 * @cfg {Date/String} maxValue
37828 * The maximum allowed date. Can be either a Javascript date object or a string date in a
37829 * valid format (defaults to null).
37833 * @cfg {String} minText
37834 * The error text to display when the date in the cell is before minValue (defaults to
37835 * 'The date in this field must be after {minValue}').
37837 minText : "The date in this field must be equal to or after {0}",
37839 * @cfg {String} maxText
37840 * The error text to display when the date in the cell is after maxValue (defaults to
37841 * 'The date in this field must be before {maxValue}').
37843 maxText : "The date in this field must be equal to or before {0}",
37845 * @cfg {String} invalidText
37846 * The error text to display when the date in the field is invalid (defaults to
37847 * '{value} is not a valid date - it must be in the format {format}').
37849 invalidText : "{0} is not a valid date - it must be in the format {1}",
37851 * @cfg {String} triggerClass
37852 * An additional CSS class used to style the trigger button. The trigger will always get the
37853 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
37854 * which displays a calendar icon).
37856 triggerClass : 'x-form-date-trigger',
37860 * @cfg {Boolean} useIso
37861 * if enabled, then the date field will use a hidden field to store the
37862 * real value as iso formated date. default (false)
37866 * @cfg {String/Object} autoCreate
37867 * A DomHelper element spec, or true for a default element spec (defaults to
37868 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
37871 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
37874 hiddenField: false,
37876 onRender : function(ct, position)
37878 Roo.form.DateField.superclass.onRender.call(this, ct, position);
37880 //this.el.dom.removeAttribute('name');
37881 Roo.log("Changing name?");
37882 this.el.dom.setAttribute('name', this.name + '____hidden___' );
37883 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
37885 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
37886 // prevent input submission
37887 this.hiddenName = this.name;
37894 validateValue : function(value)
37896 value = this.formatDate(value);
37897 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
37898 Roo.log('super failed');
37901 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
37904 var svalue = value;
37905 value = this.parseDate(value);
37907 Roo.log('parse date failed' + svalue);
37908 this.markInvalid(String.format(this.invalidText, svalue, this.format));
37911 var time = value.getTime();
37912 if(this.minValue && time < this.minValue.getTime()){
37913 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
37916 if(this.maxValue && time > this.maxValue.getTime()){
37917 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
37920 if(this.disabledDays){
37921 var day = value.getDay();
37922 for(var i = 0; i < this.disabledDays.length; i++) {
37923 if(day === this.disabledDays[i]){
37924 this.markInvalid(this.disabledDaysText);
37929 var fvalue = this.formatDate(value);
37930 if(this.ddMatch && this.ddMatch.test(fvalue)){
37931 this.markInvalid(String.format(this.disabledDatesText, fvalue));
37938 // Provides logic to override the default TriggerField.validateBlur which just returns true
37939 validateBlur : function(){
37940 return !this.menu || !this.menu.isVisible();
37943 getName: function()
37945 // returns hidden if it's set..
37946 if (!this.rendered) {return ''};
37947 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37952 * Returns the current date value of the date field.
37953 * @return {Date} The date value
37955 getValue : function(){
37957 return this.hiddenField ?
37958 this.hiddenField.value :
37959 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
37963 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
37964 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
37965 * (the default format used is "m/d/y").
37968 //All of these calls set the same date value (May 4, 2006)
37970 //Pass a date object:
37971 var dt = new Date('5/4/06');
37972 dateField.setValue(dt);
37974 //Pass a date string (default format):
37975 dateField.setValue('5/4/06');
37977 //Pass a date string (custom format):
37978 dateField.format = 'Y-m-d';
37979 dateField.setValue('2006-5-4');
37981 * @param {String/Date} date The date or valid date string
37983 setValue : function(date){
37984 if (this.hiddenField) {
37985 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
37987 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
37988 // make sure the value field is always stored as a date..
37989 this.value = this.parseDate(date);
37995 parseDate : function(value){
37996 if(!value || value instanceof Date){
37999 var v = Date.parseDate(value, this.format);
38000 if (!v && this.useIso) {
38001 v = Date.parseDate(value, 'Y-m-d');
38003 if(!v && this.altFormats){
38004 if(!this.altFormatsArray){
38005 this.altFormatsArray = this.altFormats.split("|");
38007 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38008 v = Date.parseDate(value, this.altFormatsArray[i]);
38015 formatDate : function(date, fmt){
38016 return (!date || !(date instanceof Date)) ?
38017 date : date.dateFormat(fmt || this.format);
38022 select: function(m, d){
38025 this.fireEvent('select', this, d);
38027 show : function(){ // retain focus styling
38031 this.focus.defer(10, this);
38032 var ml = this.menuListeners;
38033 this.menu.un("select", ml.select, this);
38034 this.menu.un("show", ml.show, this);
38035 this.menu.un("hide", ml.hide, this);
38040 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38041 onTriggerClick : function(){
38045 if(this.menu == null){
38046 this.menu = new Roo.menu.DateMenu();
38048 Roo.apply(this.menu.picker, {
38049 showClear: this.allowBlank,
38050 minDate : this.minValue,
38051 maxDate : this.maxValue,
38052 disabledDatesRE : this.ddMatch,
38053 disabledDatesText : this.disabledDatesText,
38054 disabledDays : this.disabledDays,
38055 disabledDaysText : this.disabledDaysText,
38056 format : this.useIso ? 'Y-m-d' : this.format,
38057 minText : String.format(this.minText, this.formatDate(this.minValue)),
38058 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38060 this.menu.on(Roo.apply({}, this.menuListeners, {
38063 this.menu.picker.setValue(this.getValue() || new Date());
38064 this.menu.show(this.el, "tl-bl?");
38067 beforeBlur : function(){
38068 var v = this.parseDate(this.getRawValue());
38074 /** @cfg {Boolean} grow @hide */
38075 /** @cfg {Number} growMin @hide */
38076 /** @cfg {Number} growMax @hide */
38083 * Ext JS Library 1.1.1
38084 * Copyright(c) 2006-2007, Ext JS, LLC.
38086 * Originally Released Under LGPL - original licence link has changed is not relivant.
38089 * <script type="text/javascript">
38093 * @class Roo.form.MonthField
38094 * @extends Roo.form.TriggerField
38095 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38097 * Create a new MonthField
38098 * @param {Object} config
38100 Roo.form.MonthField = function(config){
38102 Roo.form.MonthField.superclass.constructor.call(this, config);
38108 * Fires when a date is selected
38109 * @param {Roo.form.MonthFieeld} combo This combo box
38110 * @param {Date} date The date selected
38117 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38118 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38119 this.ddMatch = null;
38120 if(this.disabledDates){
38121 var dd = this.disabledDates;
38123 for(var i = 0; i < dd.length; i++){
38125 if(i != dd.length-1) re += "|";
38127 this.ddMatch = new RegExp(re + ")");
38131 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38133 * @cfg {String} format
38134 * The default date format string which can be overriden for localization support. The format must be
38135 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38139 * @cfg {String} altFormats
38140 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38141 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38143 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38145 * @cfg {Array} disabledDays
38146 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38148 disabledDays : [0,1,2,3,4,5,6],
38150 * @cfg {String} disabledDaysText
38151 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38153 disabledDaysText : "Disabled",
38155 * @cfg {Array} disabledDates
38156 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38157 * expression so they are very powerful. Some examples:
38159 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38160 * <li>["03/08", "09/16"] would disable those days for every year</li>
38161 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38162 * <li>["03/../2006"] would disable every day in March 2006</li>
38163 * <li>["^03"] would disable every day in every March</li>
38165 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38166 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38168 disabledDates : null,
38170 * @cfg {String} disabledDatesText
38171 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38173 disabledDatesText : "Disabled",
38175 * @cfg {Date/String} minValue
38176 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38177 * valid format (defaults to null).
38181 * @cfg {Date/String} maxValue
38182 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38183 * valid format (defaults to null).
38187 * @cfg {String} minText
38188 * The error text to display when the date in the cell is before minValue (defaults to
38189 * 'The date in this field must be after {minValue}').
38191 minText : "The date in this field must be equal to or after {0}",
38193 * @cfg {String} maxTextf
38194 * The error text to display when the date in the cell is after maxValue (defaults to
38195 * 'The date in this field must be before {maxValue}').
38197 maxText : "The date in this field must be equal to or before {0}",
38199 * @cfg {String} invalidText
38200 * The error text to display when the date in the field is invalid (defaults to
38201 * '{value} is not a valid date - it must be in the format {format}').
38203 invalidText : "{0} is not a valid date - it must be in the format {1}",
38205 * @cfg {String} triggerClass
38206 * An additional CSS class used to style the trigger button. The trigger will always get the
38207 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38208 * which displays a calendar icon).
38210 triggerClass : 'x-form-date-trigger',
38214 * @cfg {Boolean} useIso
38215 * if enabled, then the date field will use a hidden field to store the
38216 * real value as iso formated date. default (true)
38220 * @cfg {String/Object} autoCreate
38221 * A DomHelper element spec, or true for a default element spec (defaults to
38222 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38225 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38228 hiddenField: false,
38230 hideMonthPicker : false,
38232 onRender : function(ct, position)
38234 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38236 this.el.dom.removeAttribute('name');
38237 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38239 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38240 // prevent input submission
38241 this.hiddenName = this.name;
38248 validateValue : function(value)
38250 value = this.formatDate(value);
38251 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38254 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38257 var svalue = value;
38258 value = this.parseDate(value);
38260 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38263 var time = value.getTime();
38264 if(this.minValue && time < this.minValue.getTime()){
38265 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38268 if(this.maxValue && time > this.maxValue.getTime()){
38269 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38272 /*if(this.disabledDays){
38273 var day = value.getDay();
38274 for(var i = 0; i < this.disabledDays.length; i++) {
38275 if(day === this.disabledDays[i]){
38276 this.markInvalid(this.disabledDaysText);
38282 var fvalue = this.formatDate(value);
38283 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38284 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38292 // Provides logic to override the default TriggerField.validateBlur which just returns true
38293 validateBlur : function(){
38294 return !this.menu || !this.menu.isVisible();
38298 * Returns the current date value of the date field.
38299 * @return {Date} The date value
38301 getValue : function(){
38305 return this.hiddenField ?
38306 this.hiddenField.value :
38307 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38311 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38312 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38313 * (the default format used is "m/d/y").
38316 //All of these calls set the same date value (May 4, 2006)
38318 //Pass a date object:
38319 var dt = new Date('5/4/06');
38320 monthField.setValue(dt);
38322 //Pass a date string (default format):
38323 monthField.setValue('5/4/06');
38325 //Pass a date string (custom format):
38326 monthField.format = 'Y-m-d';
38327 monthField.setValue('2006-5-4');
38329 * @param {String/Date} date The date or valid date string
38331 setValue : function(date){
38332 Roo.log('month setValue' + date);
38333 // can only be first of month..
38335 var val = this.parseDate(date);
38337 if (this.hiddenField) {
38338 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38340 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38341 this.value = this.parseDate(date);
38345 parseDate : function(value){
38346 if(!value || value instanceof Date){
38347 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38350 var v = Date.parseDate(value, this.format);
38351 if (!v && this.useIso) {
38352 v = Date.parseDate(value, 'Y-m-d');
38356 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38360 if(!v && this.altFormats){
38361 if(!this.altFormatsArray){
38362 this.altFormatsArray = this.altFormats.split("|");
38364 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38365 v = Date.parseDate(value, this.altFormatsArray[i]);
38372 formatDate : function(date, fmt){
38373 return (!date || !(date instanceof Date)) ?
38374 date : date.dateFormat(fmt || this.format);
38379 select: function(m, d){
38381 this.fireEvent('select', this, d);
38383 show : function(){ // retain focus styling
38387 this.focus.defer(10, this);
38388 var ml = this.menuListeners;
38389 this.menu.un("select", ml.select, this);
38390 this.menu.un("show", ml.show, this);
38391 this.menu.un("hide", ml.hide, this);
38395 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38396 onTriggerClick : function(){
38400 if(this.menu == null){
38401 this.menu = new Roo.menu.DateMenu();
38405 Roo.apply(this.menu.picker, {
38407 showClear: this.allowBlank,
38408 minDate : this.minValue,
38409 maxDate : this.maxValue,
38410 disabledDatesRE : this.ddMatch,
38411 disabledDatesText : this.disabledDatesText,
38413 format : this.useIso ? 'Y-m-d' : this.format,
38414 minText : String.format(this.minText, this.formatDate(this.minValue)),
38415 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38418 this.menu.on(Roo.apply({}, this.menuListeners, {
38426 // hide month picker get's called when we called by 'before hide';
38428 var ignorehide = true;
38429 p.hideMonthPicker = function(disableAnim){
38433 if(this.monthPicker){
38434 Roo.log("hideMonthPicker called");
38435 if(disableAnim === true){
38436 this.monthPicker.hide();
38438 this.monthPicker.slideOut('t', {duration:.2});
38439 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38440 p.fireEvent("select", this, this.value);
38446 Roo.log('picker set value');
38447 Roo.log(this.getValue());
38448 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
38449 m.show(this.el, 'tl-bl?');
38450 ignorehide = false;
38451 // this will trigger hideMonthPicker..
38454 // hidden the day picker
38455 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
38461 p.showMonthPicker.defer(100, p);
38467 beforeBlur : function(){
38468 var v = this.parseDate(this.getRawValue());
38474 /** @cfg {Boolean} grow @hide */
38475 /** @cfg {Number} growMin @hide */
38476 /** @cfg {Number} growMax @hide */
38483 * Ext JS Library 1.1.1
38484 * Copyright(c) 2006-2007, Ext JS, LLC.
38486 * Originally Released Under LGPL - original licence link has changed is not relivant.
38489 * <script type="text/javascript">
38494 * @class Roo.form.ComboBox
38495 * @extends Roo.form.TriggerField
38496 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
38498 * Create a new ComboBox.
38499 * @param {Object} config Configuration options
38501 Roo.form.ComboBox = function(config){
38502 Roo.form.ComboBox.superclass.constructor.call(this, config);
38506 * Fires when the dropdown list is expanded
38507 * @param {Roo.form.ComboBox} combo This combo box
38512 * Fires when the dropdown list is collapsed
38513 * @param {Roo.form.ComboBox} combo This combo box
38517 * @event beforeselect
38518 * Fires before a list item is selected. Return false to cancel the selection.
38519 * @param {Roo.form.ComboBox} combo This combo box
38520 * @param {Roo.data.Record} record The data record returned from the underlying store
38521 * @param {Number} index The index of the selected item in the dropdown list
38523 'beforeselect' : true,
38526 * Fires when a list item is selected
38527 * @param {Roo.form.ComboBox} combo This combo box
38528 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
38529 * @param {Number} index The index of the selected item in the dropdown list
38533 * @event beforequery
38534 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
38535 * The event object passed has these properties:
38536 * @param {Roo.form.ComboBox} combo This combo box
38537 * @param {String} query The query
38538 * @param {Boolean} forceAll true to force "all" query
38539 * @param {Boolean} cancel true to cancel the query
38540 * @param {Object} e The query event object
38542 'beforequery': true,
38545 * Fires when the 'add' icon is pressed (add a listener to enable add button)
38546 * @param {Roo.form.ComboBox} combo This combo box
38551 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
38552 * @param {Roo.form.ComboBox} combo This combo box
38553 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
38559 if(this.transform){
38560 this.allowDomMove = false;
38561 var s = Roo.getDom(this.transform);
38562 if(!this.hiddenName){
38563 this.hiddenName = s.name;
38566 this.mode = 'local';
38567 var d = [], opts = s.options;
38568 for(var i = 0, len = opts.length;i < len; i++){
38570 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
38572 this.value = value;
38574 d.push([value, o.text]);
38576 this.store = new Roo.data.SimpleStore({
38578 fields: ['value', 'text'],
38581 this.valueField = 'value';
38582 this.displayField = 'text';
38584 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
38585 if(!this.lazyRender){
38586 this.target = true;
38587 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
38588 s.parentNode.removeChild(s); // remove it
38589 this.render(this.el.parentNode);
38591 s.parentNode.removeChild(s); // remove it
38596 this.store = Roo.factory(this.store, Roo.data);
38599 this.selectedIndex = -1;
38600 if(this.mode == 'local'){
38601 if(config.queryDelay === undefined){
38602 this.queryDelay = 10;
38604 if(config.minChars === undefined){
38610 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
38612 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
38615 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
38616 * rendering into an Roo.Editor, defaults to false)
38619 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
38620 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
38623 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
38626 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
38627 * the dropdown list (defaults to undefined, with no header element)
38631 * @cfg {String/Roo.Template} tpl The template to use to render the output
38635 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
38637 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
38639 listWidth: undefined,
38641 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
38642 * mode = 'remote' or 'text' if mode = 'local')
38644 displayField: undefined,
38646 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
38647 * mode = 'remote' or 'value' if mode = 'local').
38648 * Note: use of a valueField requires the user make a selection
38649 * in order for a value to be mapped.
38651 valueField: undefined,
38655 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
38656 * field's data value (defaults to the underlying DOM element's name)
38658 hiddenName: undefined,
38660 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
38664 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
38666 selectedClass: 'x-combo-selected',
38668 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
38669 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
38670 * which displays a downward arrow icon).
38672 triggerClass : 'x-form-arrow-trigger',
38674 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
38678 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
38679 * anchor positions (defaults to 'tl-bl')
38681 listAlign: 'tl-bl?',
38683 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
38687 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
38688 * query specified by the allQuery config option (defaults to 'query')
38690 triggerAction: 'query',
38692 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
38693 * (defaults to 4, does not apply if editable = false)
38697 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
38698 * delay (typeAheadDelay) if it matches a known value (defaults to false)
38702 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
38703 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
38707 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
38708 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
38712 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
38713 * when editable = true (defaults to false)
38715 selectOnFocus:false,
38717 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
38719 queryParam: 'query',
38721 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
38722 * when mode = 'remote' (defaults to 'Loading...')
38724 loadingText: 'Loading...',
38726 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
38730 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
38734 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
38735 * traditional select (defaults to true)
38739 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
38743 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
38747 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
38748 * listWidth has a higher value)
38752 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
38753 * allow the user to set arbitrary text into the field (defaults to false)
38755 forceSelection:false,
38757 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
38758 * if typeAhead = true (defaults to 250)
38760 typeAheadDelay : 250,
38762 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
38763 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
38765 valueNotFoundText : undefined,
38767 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
38769 blockFocus : false,
38772 * @cfg {Boolean} disableClear Disable showing of clear button.
38774 disableClear : false,
38776 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
38778 alwaysQuery : false,
38784 // element that contains real text value.. (when hidden is used..)
38787 onRender : function(ct, position){
38788 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
38789 if(this.hiddenName){
38790 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
38792 this.hiddenField.value =
38793 this.hiddenValue !== undefined ? this.hiddenValue :
38794 this.value !== undefined ? this.value : '';
38796 // prevent input submission
38797 this.el.dom.removeAttribute('name');
38802 this.el.dom.setAttribute('autocomplete', 'off');
38805 var cls = 'x-combo-list';
38807 this.list = new Roo.Layer({
38808 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
38811 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
38812 this.list.setWidth(lw);
38813 this.list.swallowEvent('mousewheel');
38814 this.assetHeight = 0;
38817 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
38818 this.assetHeight += this.header.getHeight();
38821 this.innerList = this.list.createChild({cls:cls+'-inner'});
38822 this.innerList.on('mouseover', this.onViewOver, this);
38823 this.innerList.on('mousemove', this.onViewMove, this);
38824 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
38826 if(this.allowBlank && !this.pageSize && !this.disableClear){
38827 this.footer = this.list.createChild({cls:cls+'-ft'});
38828 this.pageTb = new Roo.Toolbar(this.footer);
38832 this.footer = this.list.createChild({cls:cls+'-ft'});
38833 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
38834 {pageSize: this.pageSize});
38838 if (this.pageTb && this.allowBlank && !this.disableClear) {
38840 this.pageTb.add(new Roo.Toolbar.Fill(), {
38841 cls: 'x-btn-icon x-btn-clear',
38843 handler: function()
38846 _this.clearValue();
38847 _this.onSelect(false, -1);
38852 this.assetHeight += this.footer.getHeight();
38857 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
38860 this.view = new Roo.View(this.innerList, this.tpl, {
38861 singleSelect:true, store: this.store, selectedClass: this.selectedClass
38864 this.view.on('click', this.onViewClick, this);
38866 this.store.on('beforeload', this.onBeforeLoad, this);
38867 this.store.on('load', this.onLoad, this);
38868 this.store.on('loadexception', this.onLoadException, this);
38870 if(this.resizable){
38871 this.resizer = new Roo.Resizable(this.list, {
38872 pinned:true, handles:'se'
38874 this.resizer.on('resize', function(r, w, h){
38875 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
38876 this.listWidth = w;
38877 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
38878 this.restrictHeight();
38880 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
38882 if(!this.editable){
38883 this.editable = true;
38884 this.setEditable(false);
38888 if (typeof(this.events.add.listeners) != 'undefined') {
38890 this.addicon = this.wrap.createChild(
38891 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
38893 this.addicon.on('click', function(e) {
38894 this.fireEvent('add', this);
38897 if (typeof(this.events.edit.listeners) != 'undefined') {
38899 this.editicon = this.wrap.createChild(
38900 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
38901 if (this.addicon) {
38902 this.editicon.setStyle('margin-left', '40px');
38904 this.editicon.on('click', function(e) {
38906 // we fire even if inothing is selected..
38907 this.fireEvent('edit', this, this.lastData );
38917 initEvents : function(){
38918 Roo.form.ComboBox.superclass.initEvents.call(this);
38920 this.keyNav = new Roo.KeyNav(this.el, {
38921 "up" : function(e){
38922 this.inKeyMode = true;
38926 "down" : function(e){
38927 if(!this.isExpanded()){
38928 this.onTriggerClick();
38930 this.inKeyMode = true;
38935 "enter" : function(e){
38936 this.onViewClick();
38940 "esc" : function(e){
38944 "tab" : function(e){
38945 this.onViewClick(false);
38946 this.fireEvent("specialkey", this, e);
38952 doRelay : function(foo, bar, hname){
38953 if(hname == 'down' || this.scope.isExpanded()){
38954 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
38961 this.queryDelay = Math.max(this.queryDelay || 10,
38962 this.mode == 'local' ? 10 : 250);
38963 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
38964 if(this.typeAhead){
38965 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
38967 if(this.editable !== false){
38968 this.el.on("keyup", this.onKeyUp, this);
38970 if(this.forceSelection){
38971 this.on('blur', this.doForce, this);
38975 onDestroy : function(){
38977 this.view.setStore(null);
38978 this.view.el.removeAllListeners();
38979 this.view.el.remove();
38980 this.view.purgeListeners();
38983 this.list.destroy();
38986 this.store.un('beforeload', this.onBeforeLoad, this);
38987 this.store.un('load', this.onLoad, this);
38988 this.store.un('loadexception', this.onLoadException, this);
38990 Roo.form.ComboBox.superclass.onDestroy.call(this);
38994 fireKey : function(e){
38995 if(e.isNavKeyPress() && !this.list.isVisible()){
38996 this.fireEvent("specialkey", this, e);
39001 onResize: function(w, h){
39002 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39004 if(typeof w != 'number'){
39005 // we do not handle it!?!?
39008 var tw = this.trigger.getWidth();
39009 tw += this.addicon ? this.addicon.getWidth() : 0;
39010 tw += this.editicon ? this.editicon.getWidth() : 0;
39012 this.el.setWidth( this.adjustWidth('input', x));
39014 this.trigger.setStyle('left', x+'px');
39016 if(this.list && this.listWidth === undefined){
39017 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39018 this.list.setWidth(lw);
39019 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39027 * Allow or prevent the user from directly editing the field text. If false is passed,
39028 * the user will only be able to select from the items defined in the dropdown list. This method
39029 * is the runtime equivalent of setting the 'editable' config option at config time.
39030 * @param {Boolean} value True to allow the user to directly edit the field text
39032 setEditable : function(value){
39033 if(value == this.editable){
39036 this.editable = value;
39038 this.el.dom.setAttribute('readOnly', true);
39039 this.el.on('mousedown', this.onTriggerClick, this);
39040 this.el.addClass('x-combo-noedit');
39042 this.el.dom.setAttribute('readOnly', false);
39043 this.el.un('mousedown', this.onTriggerClick, this);
39044 this.el.removeClass('x-combo-noedit');
39049 onBeforeLoad : function(){
39050 if(!this.hasFocus){
39053 this.innerList.update(this.loadingText ?
39054 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39055 this.restrictHeight();
39056 this.selectedIndex = -1;
39060 onLoad : function(){
39061 if(!this.hasFocus){
39064 if(this.store.getCount() > 0){
39066 this.restrictHeight();
39067 if(this.lastQuery == this.allQuery){
39069 this.el.dom.select();
39071 if(!this.selectByValue(this.value, true)){
39072 this.select(0, true);
39076 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39077 this.taTask.delay(this.typeAheadDelay);
39081 this.onEmptyResults();
39086 onLoadException : function()
39089 Roo.log(this.store.reader.jsonData);
39090 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39091 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39097 onTypeAhead : function(){
39098 if(this.store.getCount() > 0){
39099 var r = this.store.getAt(0);
39100 var newValue = r.data[this.displayField];
39101 var len = newValue.length;
39102 var selStart = this.getRawValue().length;
39103 if(selStart != len){
39104 this.setRawValue(newValue);
39105 this.selectText(selStart, newValue.length);
39111 onSelect : function(record, index){
39112 if(this.fireEvent('beforeselect', this, record, index) !== false){
39113 this.setFromData(index > -1 ? record.data : false);
39115 this.fireEvent('select', this, record, index);
39120 * Returns the currently selected field value or empty string if no value is set.
39121 * @return {String} value The selected value
39123 getValue : function(){
39124 if(this.valueField){
39125 return typeof this.value != 'undefined' ? this.value : '';
39127 return Roo.form.ComboBox.superclass.getValue.call(this);
39132 * Clears any text/value currently set in the field
39134 clearValue : function(){
39135 if(this.hiddenField){
39136 this.hiddenField.value = '';
39139 this.setRawValue('');
39140 this.lastSelectionText = '';
39145 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39146 * will be displayed in the field. If the value does not match the data value of an existing item,
39147 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39148 * Otherwise the field will be blank (although the value will still be set).
39149 * @param {String} value The value to match
39151 setValue : function(v){
39153 if(this.valueField){
39154 var r = this.findRecord(this.valueField, v);
39156 text = r.data[this.displayField];
39157 }else if(this.valueNotFoundText !== undefined){
39158 text = this.valueNotFoundText;
39161 this.lastSelectionText = text;
39162 if(this.hiddenField){
39163 this.hiddenField.value = v;
39165 Roo.form.ComboBox.superclass.setValue.call(this, text);
39169 * @property {Object} the last set data for the element
39174 * Sets the value of the field based on a object which is related to the record format for the store.
39175 * @param {Object} value the value to set as. or false on reset?
39177 setFromData : function(o){
39178 var dv = ''; // display value
39179 var vv = ''; // value value..
39181 if (this.displayField) {
39182 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39184 // this is an error condition!!!
39185 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39188 if(this.valueField){
39189 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39191 if(this.hiddenField){
39192 this.hiddenField.value = vv;
39194 this.lastSelectionText = dv;
39195 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39199 // no hidden field.. - we store the value in 'value', but still display
39200 // display field!!!!
39201 this.lastSelectionText = dv;
39202 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39208 reset : function(){
39209 // overridden so that last data is reset..
39210 this.setValue(this.originalValue);
39211 this.clearInvalid();
39212 this.lastData = false;
39214 this.view.clearSelections();
39218 findRecord : function(prop, value){
39220 if(this.store.getCount() > 0){
39221 this.store.each(function(r){
39222 if(r.data[prop] == value){
39232 getName: function()
39234 // returns hidden if it's set..
39235 if (!this.rendered) {return ''};
39236 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39240 onViewMove : function(e, t){
39241 this.inKeyMode = false;
39245 onViewOver : function(e, t){
39246 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39249 var item = this.view.findItemFromChild(t);
39251 var index = this.view.indexOf(item);
39252 this.select(index, false);
39257 onViewClick : function(doFocus)
39259 var index = this.view.getSelectedIndexes()[0];
39260 var r = this.store.getAt(index);
39262 this.onSelect(r, index);
39264 if(doFocus !== false && !this.blockFocus){
39270 restrictHeight : function(){
39271 this.innerList.dom.style.height = '';
39272 var inner = this.innerList.dom;
39273 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39274 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39275 this.list.beginUpdate();
39276 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39277 this.list.alignTo(this.el, this.listAlign);
39278 this.list.endUpdate();
39282 onEmptyResults : function(){
39287 * Returns true if the dropdown list is expanded, else false.
39289 isExpanded : function(){
39290 return this.list.isVisible();
39294 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39295 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39296 * @param {String} value The data value of the item to select
39297 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39298 * selected item if it is not currently in view (defaults to true)
39299 * @return {Boolean} True if the value matched an item in the list, else false
39301 selectByValue : function(v, scrollIntoView){
39302 if(v !== undefined && v !== null){
39303 var r = this.findRecord(this.valueField || this.displayField, v);
39305 this.select(this.store.indexOf(r), scrollIntoView);
39313 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39314 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39315 * @param {Number} index The zero-based index of the list item to select
39316 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39317 * selected item if it is not currently in view (defaults to true)
39319 select : function(index, scrollIntoView){
39320 this.selectedIndex = index;
39321 this.view.select(index);
39322 if(scrollIntoView !== false){
39323 var el = this.view.getNode(index);
39325 this.innerList.scrollChildIntoView(el, false);
39331 selectNext : function(){
39332 var ct = this.store.getCount();
39334 if(this.selectedIndex == -1){
39336 }else if(this.selectedIndex < ct-1){
39337 this.select(this.selectedIndex+1);
39343 selectPrev : function(){
39344 var ct = this.store.getCount();
39346 if(this.selectedIndex == -1){
39348 }else if(this.selectedIndex != 0){
39349 this.select(this.selectedIndex-1);
39355 onKeyUp : function(e){
39356 if(this.editable !== false && !e.isSpecialKey()){
39357 this.lastKey = e.getKey();
39358 this.dqTask.delay(this.queryDelay);
39363 validateBlur : function(){
39364 return !this.list || !this.list.isVisible();
39368 initQuery : function(){
39369 this.doQuery(this.getRawValue());
39373 doForce : function(){
39374 if(this.el.dom.value.length > 0){
39375 this.el.dom.value =
39376 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39382 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39383 * query allowing the query action to be canceled if needed.
39384 * @param {String} query The SQL query to execute
39385 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39386 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39387 * saved in the current store (defaults to false)
39389 doQuery : function(q, forceAll){
39390 if(q === undefined || q === null){
39395 forceAll: forceAll,
39399 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39403 forceAll = qe.forceAll;
39404 if(forceAll === true || (q.length >= this.minChars)){
39405 if(this.lastQuery != q || this.alwaysQuery){
39406 this.lastQuery = q;
39407 if(this.mode == 'local'){
39408 this.selectedIndex = -1;
39410 this.store.clearFilter();
39412 this.store.filter(this.displayField, q);
39416 this.store.baseParams[this.queryParam] = q;
39418 params: this.getParams(q)
39423 this.selectedIndex = -1;
39430 getParams : function(q){
39432 //p[this.queryParam] = q;
39435 p.limit = this.pageSize;
39441 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39443 collapse : function(){
39444 if(!this.isExpanded()){
39448 Roo.get(document).un('mousedown', this.collapseIf, this);
39449 Roo.get(document).un('mousewheel', this.collapseIf, this);
39450 if (!this.editable) {
39451 Roo.get(document).un('keydown', this.listKeyPress, this);
39453 this.fireEvent('collapse', this);
39457 collapseIf : function(e){
39458 if(!e.within(this.wrap) && !e.within(this.list)){
39464 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
39466 expand : function(){
39467 if(this.isExpanded() || !this.hasFocus){
39470 this.list.alignTo(this.el, this.listAlign);
39472 Roo.get(document).on('mousedown', this.collapseIf, this);
39473 Roo.get(document).on('mousewheel', this.collapseIf, this);
39474 if (!this.editable) {
39475 Roo.get(document).on('keydown', this.listKeyPress, this);
39478 this.fireEvent('expand', this);
39482 // Implements the default empty TriggerField.onTriggerClick function
39483 onTriggerClick : function(){
39487 if(this.isExpanded()){
39489 if (!this.blockFocus) {
39494 this.hasFocus = true;
39495 if(this.triggerAction == 'all') {
39496 this.doQuery(this.allQuery, true);
39498 this.doQuery(this.getRawValue());
39500 if (!this.blockFocus) {
39505 listKeyPress : function(e)
39507 //Roo.log('listkeypress');
39508 // scroll to first matching element based on key pres..
39509 if (e.isSpecialKey()) {
39512 var k = String.fromCharCode(e.getKey()).toUpperCase();
39515 var csel = this.view.getSelectedNodes();
39516 var cselitem = false;
39518 var ix = this.view.indexOf(csel[0]);
39519 cselitem = this.store.getAt(ix);
39520 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
39526 this.store.each(function(v) {
39528 // start at existing selection.
39529 if (cselitem.id == v.id) {
39535 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
39536 match = this.store.indexOf(v);
39541 if (match === false) {
39542 return true; // no more action?
39545 this.view.select(match);
39546 var sn = Roo.get(this.view.getSelectedNodes()[0])
39547 sn.scrollIntoView(sn.dom.parentNode, false);
39551 * @cfg {Boolean} grow
39555 * @cfg {Number} growMin
39559 * @cfg {Number} growMax
39567 * Copyright(c) 2010-2012, Roo J Solutions Limited
39574 * @class Roo.form.ComboBoxArray
39575 * @extends Roo.form.TextField
39576 * A facebook style adder... for lists of email / people / countries etc...
39577 * pick multiple items from a combo box, and shows each one.
39579 * Fred [x] Brian [x] [Pick another |v]
39582 * For this to work: it needs various extra information
39583 * - normal combo problay has
39585 * + displayField, valueField
39587 * For our purpose...
39590 * If we change from 'extends' to wrapping...
39597 * Create a new ComboBoxArray.
39598 * @param {Object} config Configuration options
39602 Roo.form.ComboBoxArray = function(config)
39605 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
39607 this.items = new Roo.util.MixedCollection(false);
39609 // construct the child combo...
39619 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
39622 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
39627 // behavies liek a hiddne field
39628 inputType: 'hidden',
39630 * @cfg {Number} width The width of the box that displays the selected element
39637 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
39641 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
39643 hiddenName : false,
39646 // private the array of items that are displayed..
39648 // private - the hidden field el.
39650 // private - the filed el..
39653 //validateValue : function() { return true; }, // all values are ok!
39654 //onAddClick: function() { },
39656 onRender : function(ct, position)
39659 // create the standard hidden element
39660 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
39663 // give fake names to child combo;
39664 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
39665 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
39667 this.combo = Roo.factory(this.combo, Roo.form);
39668 this.combo.onRender(ct, position);
39669 if (typeof(this.combo.width) != 'undefined') {
39670 this.combo.onResize(this.combo.width,0);
39673 this.combo.initEvents();
39675 // assigned so form know we need to do this..
39676 this.store = this.combo.store;
39677 this.valueField = this.combo.valueField;
39678 this.displayField = this.combo.displayField ;
39681 this.combo.wrap.addClass('x-cbarray-grp');
39683 var cbwrap = this.combo.wrap.createChild(
39684 {tag: 'div', cls: 'x-cbarray-cb'},
39689 this.hiddenEl = this.combo.wrap.createChild({
39690 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
39692 this.el = this.combo.wrap.createChild({
39693 tag: 'input', type:'hidden' , name: this.name, value : ''
39695 // this.el.dom.removeAttribute("name");
39698 this.outerWrap = this.combo.wrap;
39699 this.wrap = cbwrap;
39701 this.outerWrap.setWidth(this.width);
39702 this.outerWrap.dom.removeChild(this.el.dom);
39704 this.wrap.dom.appendChild(this.el.dom);
39705 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
39706 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
39708 this.combo.trigger.setStyle('position','relative');
39709 this.combo.trigger.setStyle('left', '0px');
39710 this.combo.trigger.setStyle('top', '2px');
39712 this.combo.el.setStyle('vertical-align', 'text-bottom');
39714 //this.trigger.setStyle('vertical-align', 'top');
39716 // this should use the code from combo really... on('add' ....)
39720 this.adder = this.outerWrap.createChild(
39721 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
39723 this.adder.on('click', function(e) {
39724 _t.fireEvent('adderclick', this, e);
39728 //this.adder.on('click', this.onAddClick, _t);
39731 this.combo.on('select', function(cb, rec, ix) {
39732 this.addItem(rec.data);
39735 cb.el.dom.value = '';
39736 //cb.lastData = rec.data;
39745 getName: function()
39747 // returns hidden if it's set..
39748 if (!this.rendered) {return ''};
39749 return this.hiddenName ? this.hiddenName : this.name;
39754 onResize: function(w, h){
39757 // not sure if this is needed..
39758 //this.combo.onResize(w,h);
39760 if(typeof w != 'number'){
39761 // we do not handle it!?!?
39764 var tw = this.combo.trigger.getWidth();
39765 tw += this.addicon ? this.addicon.getWidth() : 0;
39766 tw += this.editicon ? this.editicon.getWidth() : 0;
39768 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
39770 this.combo.trigger.setStyle('left', '0px');
39772 if(this.list && this.listWidth === undefined){
39773 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
39774 this.list.setWidth(lw);
39775 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39782 addItem: function(rec)
39784 var valueField = this.combo.valueField;
39785 var displayField = this.combo.displayField;
39786 if (this.items.indexOfKey(rec[valueField]) > -1) {
39787 //console.log("GOT " + rec.data.id);
39791 var x = new Roo.form.ComboBoxArray.Item({
39792 //id : rec[this.idField],
39794 displayField : displayField ,
39795 tipField : displayField ,
39799 this.items.add(rec[valueField],x);
39800 // add it before the element..
39801 this.updateHiddenEl();
39802 x.render(this.outerWrap, this.wrap.dom);
39803 // add the image handler..
39806 updateHiddenEl : function()
39809 if (!this.hiddenEl) {
39813 var idField = this.combo.valueField;
39815 this.items.each(function(f) {
39816 ar.push(f.data[idField]);
39819 this.hiddenEl.dom.value = ar.join(',');
39825 //Roo.form.ComboBoxArray.superclass.reset.call(this);
39826 this.items.each(function(f) {
39829 this.el.dom.value = '';
39830 if (this.hiddenEl) {
39831 this.hiddenEl.dom.value = '';
39835 getValue: function()
39837 return this.hiddenEl ? this.hiddenEl.dom.value : '';
39839 setValue: function(v) // not a valid action - must use addItems..
39846 if (this.store.isLocal && (typeof(v) == 'string')) {
39847 // then we can use the store to find the values..
39848 // comma seperated at present.. this needs to allow JSON based encoding..
39849 this.hiddenEl.value = v;
39851 Roo.each(v.split(','), function(k) {
39852 Roo.log("CHECK " + this.valueField + ',' + k);
39853 var li = this.store.query(this.valueField, k);
39858 add[this.valueField] = k;
39859 add[this.displayField] = li.item(0).data[this.displayField];
39865 if (typeof(v) == 'object') {
39866 // then let's assume it's an array of objects..
39867 Roo.each(v, function(l) {
39875 setFromData: function(v)
39877 // this recieves an object, if setValues is called.
39879 this.el.dom.value = v[this.displayField];
39880 this.hiddenEl.dom.value = v[this.valueField];
39881 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
39884 var kv = v[this.valueField];
39885 var dv = v[this.displayField];
39886 kv = typeof(kv) != 'string' ? '' : kv;
39887 dv = typeof(dv) != 'string' ? '' : dv;
39890 var keys = kv.split(',');
39891 var display = dv.split(',');
39892 for (var i = 0 ; i < keys.length; i++) {
39895 add[this.valueField] = keys[i];
39896 add[this.displayField] = display[i];
39904 validateValue : function(value){
39905 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
39914 * @class Roo.form.ComboBoxArray.Item
39915 * @extends Roo.BoxComponent
39916 * A selected item in the list
39917 * Fred [x] Brian [x] [Pick another |v]
39920 * Create a new item.
39921 * @param {Object} config Configuration options
39924 Roo.form.ComboBoxArray.Item = function(config) {
39925 config.id = Roo.id();
39926 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
39929 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
39932 displayField : false,
39936 defaultAutoCreate : {
39938 cls: 'x-cbarray-item',
39945 src : Roo.BLANK_IMAGE_URL ,
39953 onRender : function(ct, position)
39955 Roo.form.Field.superclass.onRender.call(this, ct, position);
39958 var cfg = this.getAutoCreate();
39959 this.el = ct.createChild(cfg, position);
39962 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
39964 this.el.child('div').dom.innerHTML = this.cb.renderer ?
39965 this.cb.renderer(this.data) :
39966 String.format('{0}',this.data[this.displayField]);
39969 this.el.child('div').dom.setAttribute('qtip',
39970 String.format('{0}',this.data[this.tipField])
39973 this.el.child('img').on('click', this.remove, this);
39977 remove : function()
39980 this.cb.items.remove(this);
39981 this.el.child('img').un('click', this.remove, this);
39983 this.cb.updateHiddenEl();
39989 * Ext JS Library 1.1.1
39990 * Copyright(c) 2006-2007, Ext JS, LLC.
39992 * Originally Released Under LGPL - original licence link has changed is not relivant.
39995 * <script type="text/javascript">
39998 * @class Roo.form.Checkbox
39999 * @extends Roo.form.Field
40000 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40002 * Creates a new Checkbox
40003 * @param {Object} config Configuration options
40005 Roo.form.Checkbox = function(config){
40006 Roo.form.Checkbox.superclass.constructor.call(this, config);
40010 * Fires when the checkbox is checked or unchecked.
40011 * @param {Roo.form.Checkbox} this This checkbox
40012 * @param {Boolean} checked The new checked value
40018 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40020 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40022 focusClass : undefined,
40024 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40026 fieldClass: "x-form-field",
40028 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40032 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40033 * {tag: "input", type: "checkbox", autocomplete: "off"})
40035 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40037 * @cfg {String} boxLabel The text that appears beside the checkbox
40041 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40045 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40047 valueOff: '0', // value when not checked..
40049 actionMode : 'viewEl',
40052 itemCls : 'x-menu-check-item x-form-item',
40053 groupClass : 'x-menu-group-item',
40054 inputType : 'hidden',
40057 inSetChecked: false, // check that we are not calling self...
40059 inputElement: false, // real input element?
40060 basedOn: false, // ????
40062 isFormField: true, // not sure where this is needed!!!!
40064 onResize : function(){
40065 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40066 if(!this.boxLabel){
40067 this.el.alignTo(this.wrap, 'c-c');
40071 initEvents : function(){
40072 Roo.form.Checkbox.superclass.initEvents.call(this);
40073 this.el.on("click", this.onClick, this);
40074 this.el.on("change", this.onClick, this);
40078 getResizeEl : function(){
40082 getPositionEl : function(){
40087 onRender : function(ct, position){
40088 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40090 if(this.inputValue !== undefined){
40091 this.el.dom.value = this.inputValue;
40094 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40095 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40096 var viewEl = this.wrap.createChild({
40097 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40098 this.viewEl = viewEl;
40099 this.wrap.on('click', this.onClick, this);
40101 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40102 this.el.on('propertychange', this.setFromHidden, this); //ie
40107 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40108 // viewEl.on('click', this.onClick, this);
40110 //if(this.checked){
40111 this.setChecked(this.checked);
40113 //this.checked = this.el.dom;
40119 initValue : Roo.emptyFn,
40122 * Returns the checked state of the checkbox.
40123 * @return {Boolean} True if checked, else false
40125 getValue : function(){
40127 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40129 return this.valueOff;
40134 onClick : function(){
40135 this.setChecked(!this.checked);
40137 //if(this.el.dom.checked != this.checked){
40138 // this.setValue(this.el.dom.checked);
40143 * Sets the checked state of the checkbox.
40144 * On is always based on a string comparison between inputValue and the param.
40145 * @param {Boolean/String} value - the value to set
40146 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40148 setValue : function(v,suppressEvent){
40151 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40152 //if(this.el && this.el.dom){
40153 // this.el.dom.checked = this.checked;
40154 // this.el.dom.defaultChecked = this.checked;
40156 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40157 //this.fireEvent("check", this, this.checked);
40160 setChecked : function(state,suppressEvent)
40162 if (this.inSetChecked) {
40163 this.checked = state;
40169 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40171 this.checked = state;
40172 if(suppressEvent !== true){
40173 this.fireEvent('check', this, state);
40175 this.inSetChecked = true;
40176 this.el.dom.value = state ? this.inputValue : this.valueOff;
40177 this.inSetChecked = false;
40180 // handle setting of hidden value by some other method!!?!?
40181 setFromHidden: function()
40186 //console.log("SET FROM HIDDEN");
40187 //alert('setFrom hidden');
40188 this.setValue(this.el.dom.value);
40191 onDestroy : function()
40194 Roo.get(this.viewEl).remove();
40197 Roo.form.Checkbox.superclass.onDestroy.call(this);
40202 * Ext JS Library 1.1.1
40203 * Copyright(c) 2006-2007, Ext JS, LLC.
40205 * Originally Released Under LGPL - original licence link has changed is not relivant.
40208 * <script type="text/javascript">
40212 * @class Roo.form.Radio
40213 * @extends Roo.form.Checkbox
40214 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40215 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40217 * Creates a new Radio
40218 * @param {Object} config Configuration options
40220 Roo.form.Radio = function(){
40221 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40223 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40224 inputType: 'radio',
40227 * If this radio is part of a group, it will return the selected value
40230 getGroupValue : function(){
40231 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40235 onRender : function(ct, position){
40236 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40238 if(this.inputValue !== undefined){
40239 this.el.dom.value = this.inputValue;
40242 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40243 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40244 //var viewEl = this.wrap.createChild({
40245 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40246 //this.viewEl = viewEl;
40247 //this.wrap.on('click', this.onClick, this);
40249 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40250 //this.el.on('propertychange', this.setFromHidden, this); //ie
40255 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40256 // viewEl.on('click', this.onClick, this);
40259 this.el.dom.checked = 'checked' ;
40265 });//<script type="text/javascript">
40268 * Ext JS Library 1.1.1
40269 * Copyright(c) 2006-2007, Ext JS, LLC.
40270 * licensing@extjs.com
40272 * http://www.extjs.com/license
40278 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
40279 * - IE ? - no idea how much works there.
40287 * @class Ext.form.HtmlEditor
40288 * @extends Ext.form.Field
40289 * Provides a lightweight HTML Editor component.
40291 * This has been tested on Fireforx / Chrome.. IE may not be so great..
40293 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
40294 * supported by this editor.</b><br/><br/>
40295 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
40296 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40298 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
40300 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
40304 * @cfg {String} createLinkText The default text for the create link prompt
40306 createLinkText : 'Please enter the URL for the link:',
40308 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
40310 defaultLinkValue : 'http:/'+'/',
40313 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40318 * @cfg {Number} height (in pixels)
40322 * @cfg {Number} width (in pixels)
40327 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40330 stylesheets: false,
40335 // private properties
40336 validationEvent : false,
40338 initialized : false,
40340 sourceEditMode : false,
40341 onFocus : Roo.emptyFn,
40343 hideMode:'offsets',
40345 defaultAutoCreate : { // modified by initCompnoent..
40347 style:"width:500px;height:300px;",
40348 autocomplete: "off"
40352 initComponent : function(){
40355 * @event initialize
40356 * Fires when the editor is fully initialized (including the iframe)
40357 * @param {HtmlEditor} this
40362 * Fires when the editor is first receives the focus. Any insertion must wait
40363 * until after this event.
40364 * @param {HtmlEditor} this
40368 * @event beforesync
40369 * Fires before the textarea is updated with content from the editor iframe. Return false
40370 * to cancel the sync.
40371 * @param {HtmlEditor} this
40372 * @param {String} html
40376 * @event beforepush
40377 * Fires before the iframe editor is updated with content from the textarea. Return false
40378 * to cancel the push.
40379 * @param {HtmlEditor} this
40380 * @param {String} html
40385 * Fires when the textarea is updated with content from the editor iframe.
40386 * @param {HtmlEditor} this
40387 * @param {String} html
40392 * Fires when the iframe editor is updated with content from the textarea.
40393 * @param {HtmlEditor} this
40394 * @param {String} html
40398 * @event editmodechange
40399 * Fires when the editor switches edit modes
40400 * @param {HtmlEditor} this
40401 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
40403 editmodechange: true,
40405 * @event editorevent
40406 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40407 * @param {HtmlEditor} this
40411 this.defaultAutoCreate = {
40413 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
40414 autocomplete: "off"
40419 * Protected method that will not generally be called directly. It
40420 * is called when the editor creates its toolbar. Override this method if you need to
40421 * add custom toolbar buttons.
40422 * @param {HtmlEditor} editor
40424 createToolbar : function(editor){
40425 if (!editor.toolbars || !editor.toolbars.length) {
40426 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
40429 for (var i =0 ; i < editor.toolbars.length;i++) {
40430 editor.toolbars[i] = Roo.factory(
40431 typeof(editor.toolbars[i]) == 'string' ?
40432 { xtype: editor.toolbars[i]} : editor.toolbars[i],
40433 Roo.form.HtmlEditor);
40434 editor.toolbars[i].init(editor);
40441 * Protected method that will not generally be called directly. It
40442 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40443 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40445 getDocMarkup : function(){
40448 if (this.stylesheets === false) {
40450 Roo.get(document.head).select('style').each(function(node) {
40451 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40454 Roo.get(document.head).select('link').each(function(node) {
40455 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40458 } else if (!this.stylesheets.length) {
40460 st = '<style type="text/css">' +
40461 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40464 Roo.each(this.stylesheets, function(s) {
40465 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
40470 st += '<style type="text/css">' +
40471 'IMG { cursor: pointer } ' +
40475 return '<html><head>' + st +
40476 //<style type="text/css">' +
40477 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40479 ' </head><body class="roo-htmleditor-body"></body></html>';
40483 onRender : function(ct, position)
40486 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
40487 this.el.dom.style.border = '0 none';
40488 this.el.dom.setAttribute('tabIndex', -1);
40489 this.el.addClass('x-hidden');
40490 if(Roo.isIE){ // fix IE 1px bogus margin
40491 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
40493 this.wrap = this.el.wrap({
40494 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
40497 if (this.resizable) {
40498 this.resizeEl = new Roo.Resizable(this.wrap, {
40502 minHeight : this.height,
40503 height: this.height,
40504 handles : this.resizable,
40507 resize : function(r, w, h) {
40508 _t.onResize(w,h); // -something
40515 this.frameId = Roo.id();
40517 this.createToolbar(this);
40521 var iframe = this.wrap.createChild({
40524 name: this.frameId,
40525 frameBorder : 'no',
40526 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
40530 // console.log(iframe);
40531 //this.wrap.dom.appendChild(iframe);
40533 this.iframe = iframe.dom;
40535 this.assignDocWin();
40537 this.doc.designMode = 'on';
40540 this.doc.write(this.getDocMarkup());
40544 var task = { // must defer to wait for browser to be ready
40546 //console.log("run task?" + this.doc.readyState);
40547 this.assignDocWin();
40548 if(this.doc.body || this.doc.readyState == 'complete'){
40550 this.doc.designMode="on";
40554 Roo.TaskMgr.stop(task);
40555 this.initEditor.defer(10, this);
40562 Roo.TaskMgr.start(task);
40565 this.setSize(this.wrap.getSize());
40567 if (this.resizeEl) {
40568 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
40569 // should trigger onReize..
40574 onResize : function(w, h)
40576 //Roo.log('resize: ' +w + ',' + h );
40577 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
40578 if(this.el && this.iframe){
40579 if(typeof w == 'number'){
40580 var aw = w - this.wrap.getFrameWidth('lr');
40581 this.el.setWidth(this.adjustWidth('textarea', aw));
40582 this.iframe.style.width = aw + 'px';
40584 if(typeof h == 'number'){
40586 for (var i =0; i < this.toolbars.length;i++) {
40587 // fixme - ask toolbars for heights?
40588 tbh += this.toolbars[i].tb.el.getHeight();
40589 if (this.toolbars[i].footer) {
40590 tbh += this.toolbars[i].footer.el.getHeight();
40597 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
40598 ah -= 5; // knock a few pixes off for look..
40599 this.el.setHeight(this.adjustWidth('textarea', ah));
40600 this.iframe.style.height = ah + 'px';
40602 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
40609 * Toggles the editor between standard and source edit mode.
40610 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
40612 toggleSourceEdit : function(sourceEditMode){
40614 this.sourceEditMode = sourceEditMode === true;
40616 if(this.sourceEditMode){
40618 // Roo.log(this.syncValue());
40620 this.iframe.className = 'x-hidden';
40621 this.el.removeClass('x-hidden');
40622 this.el.dom.removeAttribute('tabIndex');
40626 // Roo.log(this.pushValue());
40628 this.iframe.className = '';
40629 this.el.addClass('x-hidden');
40630 this.el.dom.setAttribute('tabIndex', -1);
40633 this.setSize(this.wrap.getSize());
40634 this.fireEvent('editmodechange', this, this.sourceEditMode);
40637 // private used internally
40638 createLink : function(){
40639 var url = prompt(this.createLinkText, this.defaultLinkValue);
40640 if(url && url != 'http:/'+'/'){
40641 this.relayCmd('createlink', url);
40645 // private (for BoxComponent)
40646 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40648 // private (for BoxComponent)
40649 getResizeEl : function(){
40653 // private (for BoxComponent)
40654 getPositionEl : function(){
40659 initEvents : function(){
40660 this.originalValue = this.getValue();
40664 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40667 markInvalid : Roo.emptyFn,
40669 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
40672 clearInvalid : Roo.emptyFn,
40674 setValue : function(v){
40675 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
40680 * Protected method that will not generally be called directly. If you need/want
40681 * custom HTML cleanup, this is the method you should override.
40682 * @param {String} html The HTML to be cleaned
40683 * return {String} The cleaned HTML
40685 cleanHtml : function(html){
40686 html = String(html);
40687 if(html.length > 5){
40688 if(Roo.isSafari){ // strip safari nonsense
40689 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
40692 if(html == ' '){
40699 * Protected method that will not generally be called directly. Syncs the contents
40700 * of the editor iframe with the textarea.
40702 syncValue : function(){
40703 if(this.initialized){
40704 var bd = (this.doc.body || this.doc.documentElement);
40705 //this.cleanUpPaste(); -- this is done else where and causes havoc..
40706 var html = bd.innerHTML;
40708 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
40709 var m = bs.match(/text-align:(.*?);/i);
40711 html = '<div style="'+m[0]+'">' + html + '</div>';
40714 html = this.cleanHtml(html);
40715 // fix up the special chars.. normaly like back quotes in word...
40716 // however we do not want to do this with chinese..
40717 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
40718 var cc = b.charCodeAt();
40720 (cc >= 0x4E00 && cc < 0xA000 ) ||
40721 (cc >= 0x3400 && cc < 0x4E00 ) ||
40722 (cc >= 0xf900 && cc < 0xfb00 )
40728 if(this.fireEvent('beforesync', this, html) !== false){
40729 this.el.dom.value = html;
40730 this.fireEvent('sync', this, html);
40736 * Protected method that will not generally be called directly. Pushes the value of the textarea
40737 * into the iframe editor.
40739 pushValue : function(){
40740 if(this.initialized){
40741 var v = this.el.dom.value;
40747 if(this.fireEvent('beforepush', this, v) !== false){
40748 var d = (this.doc.body || this.doc.documentElement);
40750 this.cleanUpPaste();
40751 this.el.dom.value = d.innerHTML;
40752 this.fireEvent('push', this, v);
40758 deferFocus : function(){
40759 this.focus.defer(10, this);
40763 focus : function(){
40764 if(this.win && !this.sourceEditMode){
40771 assignDocWin: function()
40773 var iframe = this.iframe;
40776 this.doc = iframe.contentWindow.document;
40777 this.win = iframe.contentWindow;
40779 if (!Roo.get(this.frameId)) {
40782 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
40783 this.win = Roo.get(this.frameId).dom.contentWindow;
40788 initEditor : function(){
40789 //console.log("INIT EDITOR");
40790 this.assignDocWin();
40794 this.doc.designMode="on";
40796 this.doc.write(this.getDocMarkup());
40799 var dbody = (this.doc.body || this.doc.documentElement);
40800 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
40801 // this copies styles from the containing element into thsi one..
40802 // not sure why we need all of this..
40803 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
40804 ss['background-attachment'] = 'fixed'; // w3c
40805 dbody.bgProperties = 'fixed'; // ie
40806 Roo.DomHelper.applyStyles(dbody, ss);
40807 Roo.EventManager.on(this.doc, {
40808 //'mousedown': this.onEditorEvent,
40809 'mouseup': this.onEditorEvent,
40810 'dblclick': this.onEditorEvent,
40811 'click': this.onEditorEvent,
40812 'keyup': this.onEditorEvent,
40817 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
40819 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
40820 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
40822 this.initialized = true;
40824 this.fireEvent('initialize', this);
40829 onDestroy : function(){
40835 for (var i =0; i < this.toolbars.length;i++) {
40836 // fixme - ask toolbars for heights?
40837 this.toolbars[i].onDestroy();
40840 this.wrap.dom.innerHTML = '';
40841 this.wrap.remove();
40846 onFirstFocus : function(){
40848 this.assignDocWin();
40851 this.activated = true;
40852 for (var i =0; i < this.toolbars.length;i++) {
40853 this.toolbars[i].onFirstFocus();
40856 if(Roo.isGecko){ // prevent silly gecko errors
40858 var s = this.win.getSelection();
40859 if(!s.focusNode || s.focusNode.nodeType != 3){
40860 var r = s.getRangeAt(0);
40861 r.selectNodeContents((this.doc.body || this.doc.documentElement));
40866 this.execCmd('useCSS', true);
40867 this.execCmd('styleWithCSS', false);
40870 this.fireEvent('activate', this);
40874 adjustFont: function(btn){
40875 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
40876 //if(Roo.isSafari){ // safari
40879 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
40880 if(Roo.isSafari){ // safari
40881 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
40882 v = (v < 10) ? 10 : v;
40883 v = (v > 48) ? 48 : v;
40884 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
40889 v = Math.max(1, v+adjust);
40891 this.execCmd('FontSize', v );
40894 onEditorEvent : function(e){
40895 this.fireEvent('editorevent', this, e);
40896 // this.updateToolbar();
40897 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
40900 insertTag : function(tg)
40902 // could be a bit smarter... -> wrap the current selected tRoo..
40903 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
40905 range = this.createRange(this.getSelection());
40906 var wrappingNode = this.doc.createElement(tg.toLowerCase());
40907 wrappingNode.appendChild(range.extractContents());
40908 range.insertNode(wrappingNode);
40915 this.execCmd("formatblock", tg);
40919 insertText : function(txt)
40923 var range = this.createRange();
40924 range.deleteContents();
40925 //alert(Sender.getAttribute('label'));
40927 range.insertNode(this.doc.createTextNode(txt));
40931 relayBtnCmd : function(btn){
40932 this.relayCmd(btn.cmd);
40936 * Executes a Midas editor command on the editor document and performs necessary focus and
40937 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
40938 * @param {String} cmd The Midas command
40939 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40941 relayCmd : function(cmd, value){
40943 this.execCmd(cmd, value);
40944 this.fireEvent('editorevent', this);
40945 //this.updateToolbar();
40950 * Executes a Midas editor command directly on the editor document.
40951 * For visual commands, you should use {@link #relayCmd} instead.
40952 * <b>This should only be called after the editor is initialized.</b>
40953 * @param {String} cmd The Midas command
40954 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
40956 execCmd : function(cmd, value){
40957 this.doc.execCommand(cmd, false, value === undefined ? null : value);
40964 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
40966 * @param {String} text | dom node..
40968 insertAtCursor : function(text)
40973 if(!this.activated){
40979 var r = this.doc.selection.createRange();
40990 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
40994 // from jquery ui (MIT licenced)
40996 var win = this.win;
40998 if (win.getSelection && win.getSelection().getRangeAt) {
40999 range = win.getSelection().getRangeAt(0);
41000 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41001 range.insertNode(node);
41002 } else if (win.document.selection && win.document.selection.createRange) {
41003 // no firefox support
41004 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41005 win.document.selection.createRange().pasteHTML(txt);
41007 // no firefox support
41008 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41009 this.execCmd('InsertHTML', txt);
41018 mozKeyPress : function(e){
41020 var c = e.getCharCode(), cmd;
41023 c = String.fromCharCode(c).toLowerCase();
41037 this.cleanUpPaste.defer(100, this);
41045 e.preventDefault();
41053 fixKeys : function(){ // load time branching for fastest keydown performance
41055 return function(e){
41056 var k = e.getKey(), r;
41059 r = this.doc.selection.createRange();
41062 r.pasteHTML('    ');
41069 r = this.doc.selection.createRange();
41071 var target = r.parentElement();
41072 if(!target || target.tagName.toLowerCase() != 'li'){
41074 r.pasteHTML('<br />');
41080 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41081 this.cleanUpPaste.defer(100, this);
41087 }else if(Roo.isOpera){
41088 return function(e){
41089 var k = e.getKey();
41093 this.execCmd('InsertHTML','    ');
41096 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41097 this.cleanUpPaste.defer(100, this);
41102 }else if(Roo.isSafari){
41103 return function(e){
41104 var k = e.getKey();
41108 this.execCmd('InsertText','\t');
41112 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41113 this.cleanUpPaste.defer(100, this);
41121 getAllAncestors: function()
41123 var p = this.getSelectedNode();
41126 a.push(p); // push blank onto stack..
41127 p = this.getParentElement();
41131 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41135 a.push(this.doc.body);
41139 lastSelNode : false,
41142 getSelection : function()
41144 this.assignDocWin();
41145 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41148 getSelectedNode: function()
41150 // this may only work on Gecko!!!
41152 // should we cache this!!!!
41157 var range = this.createRange(this.getSelection()).cloneRange();
41160 var parent = range.parentElement();
41162 var testRange = range.duplicate();
41163 testRange.moveToElementText(parent);
41164 if (testRange.inRange(range)) {
41167 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41170 parent = parent.parentElement;
41175 // is ancestor a text element.
41176 var ac = range.commonAncestorContainer;
41177 if (ac.nodeType == 3) {
41178 ac = ac.parentNode;
41181 var ar = ac.childNodes;
41184 var other_nodes = [];
41185 var has_other_nodes = false;
41186 for (var i=0;i<ar.length;i++) {
41187 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41190 // fullly contained node.
41192 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41197 // probably selected..
41198 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41199 other_nodes.push(ar[i]);
41203 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41208 has_other_nodes = true;
41210 if (!nodes.length && other_nodes.length) {
41211 nodes= other_nodes;
41213 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41219 createRange: function(sel)
41221 // this has strange effects when using with
41222 // top toolbar - not sure if it's a great idea.
41223 //this.editor.contentWindow.focus();
41224 if (typeof sel != "undefined") {
41226 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41228 return this.doc.createRange();
41231 return this.doc.createRange();
41234 getParentElement: function()
41237 this.assignDocWin();
41238 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41240 var range = this.createRange(sel);
41243 var p = range.commonAncestorContainer;
41244 while (p.nodeType == 3) { // text node
41255 * Range intersection.. the hard stuff...
41259 * [ -- selected range --- ]
41263 * if end is before start or hits it. fail.
41264 * if start is after end or hits it fail.
41266 * if either hits (but other is outside. - then it's not
41272 // @see http://www.thismuchiknow.co.uk/?p=64.
41273 rangeIntersectsNode : function(range, node)
41275 var nodeRange = node.ownerDocument.createRange();
41277 nodeRange.selectNode(node);
41279 nodeRange.selectNodeContents(node);
41282 var rangeStartRange = range.cloneRange();
41283 rangeStartRange.collapse(true);
41285 var rangeEndRange = range.cloneRange();
41286 rangeEndRange.collapse(false);
41288 var nodeStartRange = nodeRange.cloneRange();
41289 nodeStartRange.collapse(true);
41291 var nodeEndRange = nodeRange.cloneRange();
41292 nodeEndRange.collapse(false);
41294 return rangeStartRange.compareBoundaryPoints(
41295 Range.START_TO_START, nodeEndRange) == -1 &&
41296 rangeEndRange.compareBoundaryPoints(
41297 Range.START_TO_START, nodeStartRange) == 1;
41301 rangeCompareNode : function(range, node)
41303 var nodeRange = node.ownerDocument.createRange();
41305 nodeRange.selectNode(node);
41307 nodeRange.selectNodeContents(node);
41311 range.collapse(true);
41313 nodeRange.collapse(true);
41315 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41316 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41318 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41320 var nodeIsBefore = ss == 1;
41321 var nodeIsAfter = ee == -1;
41323 if (nodeIsBefore && nodeIsAfter)
41325 if (!nodeIsBefore && nodeIsAfter)
41326 return 1; //right trailed.
41328 if (nodeIsBefore && !nodeIsAfter)
41329 return 2; // left trailed.
41334 // private? - in a new class?
41335 cleanUpPaste : function()
41337 // cleans up the whole document..
41338 Roo.log('cleanuppaste');
41339 this.cleanUpChildren(this.doc.body);
41340 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41341 if (clean != this.doc.body.innerHTML) {
41342 this.doc.body.innerHTML = clean;
41347 cleanWordChars : function(input) {// change the chars to hex code
41348 var he = Roo.form.HtmlEditor;
41350 var output = input;
41351 Roo.each(he.swapCodes, function(sw) {
41352 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41354 output = output.replace(swapper, sw[1]);
41361 cleanUpChildren : function (n)
41363 if (!n.childNodes.length) {
41366 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41367 this.cleanUpChild(n.childNodes[i]);
41374 cleanUpChild : function (node)
41377 //console.log(node);
41378 if (node.nodeName == "#text") {
41379 // clean up silly Windows -- stuff?
41382 if (node.nodeName == "#comment") {
41383 node.parentNode.removeChild(node);
41384 // clean up silly Windows -- stuff?
41388 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
41390 node.parentNode.removeChild(node);
41395 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
41397 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41398 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41400 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41401 // remove_keep_children = true;
41404 if (remove_keep_children) {
41405 this.cleanUpChildren(node);
41406 // inserts everything just before this node...
41407 while (node.childNodes.length) {
41408 var cn = node.childNodes[0];
41409 node.removeChild(cn);
41410 node.parentNode.insertBefore(cn, node);
41412 node.parentNode.removeChild(node);
41416 if (!node.attributes || !node.attributes.length) {
41417 this.cleanUpChildren(node);
41421 function cleanAttr(n,v)
41424 if (v.match(/^\./) || v.match(/^\//)) {
41427 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41430 if (v.match(/^#/)) {
41433 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41434 node.removeAttribute(n);
41438 function cleanStyle(n,v)
41440 if (v.match(/expression/)) { //XSS?? should we even bother..
41441 node.removeAttribute(n);
41444 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
41445 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
41448 var parts = v.split(/;/);
41451 Roo.each(parts, function(p) {
41452 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41456 var l = p.split(':').shift().replace(/\s+/g,'');
41457 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41460 if ( cblack.indexOf(l) > -1) {
41461 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41462 //node.removeAttribute(n);
41466 // only allow 'c whitelisted system attributes'
41467 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41468 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41469 //node.removeAttribute(n);
41479 if (clean.length) {
41480 node.setAttribute(n, clean.join(';'));
41482 node.removeAttribute(n);
41488 for (var i = node.attributes.length-1; i > -1 ; i--) {
41489 var a = node.attributes[i];
41492 if (a.name.toLowerCase().substr(0,2)=='on') {
41493 node.removeAttribute(a.name);
41496 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
41497 node.removeAttribute(a.name);
41500 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
41501 cleanAttr(a.name,a.value); // fixme..
41504 if (a.name == 'style') {
41505 cleanStyle(a.name,a.value);
41508 /// clean up MS crap..
41509 // tecnically this should be a list of valid class'es..
41512 if (a.name == 'class') {
41513 if (a.value.match(/^Mso/)) {
41514 node.className = '';
41517 if (a.value.match(/body/)) {
41518 node.className = '';
41529 this.cleanUpChildren(node);
41535 // hide stuff that is not compatible
41549 * @event specialkey
41553 * @cfg {String} fieldClass @hide
41556 * @cfg {String} focusClass @hide
41559 * @cfg {String} autoCreate @hide
41562 * @cfg {String} inputType @hide
41565 * @cfg {String} invalidClass @hide
41568 * @cfg {String} invalidText @hide
41571 * @cfg {String} msgFx @hide
41574 * @cfg {String} validateOnBlur @hide
41578 Roo.form.HtmlEditor.white = [
41579 'area', 'br', 'img', 'input', 'hr', 'wbr',
41581 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
41582 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
41583 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
41584 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
41585 'table', 'ul', 'xmp',
41587 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
41590 'dir', 'menu', 'ol', 'ul', 'dl',
41596 Roo.form.HtmlEditor.black = [
41597 // 'embed', 'object', // enable - backend responsiblity to clean thiese
41599 'base', 'basefont', 'bgsound', 'blink', 'body',
41600 'frame', 'frameset', 'head', 'html', 'ilayer',
41601 'iframe', 'layer', 'link', 'meta', 'object',
41602 'script', 'style' ,'title', 'xml' // clean later..
41604 Roo.form.HtmlEditor.clean = [
41605 'script', 'style', 'title', 'xml'
41607 Roo.form.HtmlEditor.remove = [
41612 Roo.form.HtmlEditor.ablack = [
41616 Roo.form.HtmlEditor.aclean = [
41617 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
41621 Roo.form.HtmlEditor.pwhite= [
41622 'http', 'https', 'mailto'
41625 // white listed style attributes.
41626 Roo.form.HtmlEditor.cwhite= [
41627 // 'text-align', /// default is to allow most things..
41633 // black listed style attributes.
41634 Roo.form.HtmlEditor.cblack= [
41635 // 'font-size' -- this can be set by the project
41639 Roo.form.HtmlEditor.swapCodes =[
41650 // <script type="text/javascript">
41653 * Ext JS Library 1.1.1
41654 * Copyright(c) 2006-2007, Ext JS, LLC.
41660 * @class Roo.form.HtmlEditorToolbar1
41665 new Roo.form.HtmlEditor({
41668 new Roo.form.HtmlEditorToolbar1({
41669 disable : { fonts: 1 , format: 1, ..., ... , ...],
41675 * @cfg {Object} disable List of elements to disable..
41676 * @cfg {Array} btns List of additional buttons.
41680 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
41683 Roo.form.HtmlEditor.ToolbarStandard = function(config)
41686 Roo.apply(this, config);
41688 // default disabled, based on 'good practice'..
41689 this.disable = this.disable || {};
41690 Roo.applyIf(this.disable, {
41693 specialElements : true
41697 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
41698 // dont call parent... till later.
41701 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
41709 * @cfg {Object} disable List of toolbar elements to disable
41714 * @cfg {Array} fontFamilies An array of available font families
41732 // "á" , ?? a acute?
41737 "°" // , // degrees
41739 // "é" , // e ecute
41740 // "ú" , // u ecute?
41743 specialElements : [
41745 text: "Insert Table",
41748 ihtml : '<table><tr><td>Cell</td></tr></table>'
41752 text: "Insert Image",
41755 ihtml : '<img src="about:blank"/>'
41764 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
41765 "input:submit", "input:button", "select", "textarea", "label" ],
41768 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
41770 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
41774 * @cfg {String} defaultFont default font to use.
41776 defaultFont: 'tahoma',
41778 fontSelect : false,
41781 formatCombo : false,
41783 init : function(editor)
41785 this.editor = editor;
41788 var fid = editor.frameId;
41790 function btn(id, toggle, handler){
41791 var xid = fid + '-'+ id ;
41795 cls : 'x-btn-icon x-edit-'+id,
41796 enableToggle:toggle !== false,
41797 scope: editor, // was editor...
41798 handler:handler||editor.relayBtnCmd,
41799 clickEvent:'mousedown',
41800 tooltip: etb.buttonTips[id] || undefined, ///tips ???
41807 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
41809 // stop form submits
41810 tb.el.on('click', function(e){
41811 e.preventDefault(); // what does this do?
41814 if(!this.disable.font) { // && !Roo.isSafari){
41815 /* why no safari for fonts
41816 editor.fontSelect = tb.el.createChild({
41819 cls:'x-font-select',
41820 html: this.createFontOptions()
41823 editor.fontSelect.on('change', function(){
41824 var font = editor.fontSelect.dom.value;
41825 editor.relayCmd('fontname', font);
41826 editor.deferFocus();
41830 editor.fontSelect.dom,
41836 if(!this.disable.formats){
41837 this.formatCombo = new Roo.form.ComboBox({
41838 store: new Roo.data.SimpleStore({
41841 data : this.formats // from states.js
41845 //autoCreate : {tag: "div", size: "20"},
41846 displayField:'tag',
41850 triggerAction: 'all',
41851 emptyText:'Add tag',
41852 selectOnFocus:true,
41855 'select': function(c, r, i) {
41856 editor.insertTag(r.get('tag'));
41862 tb.addField(this.formatCombo);
41866 if(!this.disable.format){
41873 if(!this.disable.fontSize){
41878 btn('increasefontsize', false, editor.adjustFont),
41879 btn('decreasefontsize', false, editor.adjustFont)
41884 if(!this.disable.colors){
41887 id:editor.frameId +'-forecolor',
41888 cls:'x-btn-icon x-edit-forecolor',
41889 clickEvent:'mousedown',
41890 tooltip: this.buttonTips['forecolor'] || undefined,
41892 menu : new Roo.menu.ColorMenu({
41893 allowReselect: true,
41894 focus: Roo.emptyFn,
41897 selectHandler: function(cp, color){
41898 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
41899 editor.deferFocus();
41902 clickEvent:'mousedown'
41905 id:editor.frameId +'backcolor',
41906 cls:'x-btn-icon x-edit-backcolor',
41907 clickEvent:'mousedown',
41908 tooltip: this.buttonTips['backcolor'] || undefined,
41910 menu : new Roo.menu.ColorMenu({
41911 focus: Roo.emptyFn,
41914 allowReselect: true,
41915 selectHandler: function(cp, color){
41917 editor.execCmd('useCSS', false);
41918 editor.execCmd('hilitecolor', color);
41919 editor.execCmd('useCSS', true);
41920 editor.deferFocus();
41922 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
41923 Roo.isSafari || Roo.isIE ? '#'+color : color);
41924 editor.deferFocus();
41928 clickEvent:'mousedown'
41933 // now add all the items...
41936 if(!this.disable.alignments){
41939 btn('justifyleft'),
41940 btn('justifycenter'),
41941 btn('justifyright')
41945 //if(!Roo.isSafari){
41946 if(!this.disable.links){
41949 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
41953 if(!this.disable.lists){
41956 btn('insertorderedlist'),
41957 btn('insertunorderedlist')
41960 if(!this.disable.sourceEdit){
41963 btn('sourceedit', true, function(btn){
41964 this.toggleSourceEdit(btn.pressed);
41971 // special menu.. - needs to be tidied up..
41972 if (!this.disable.special) {
41975 cls: 'x-edit-none',
41981 for (var i =0; i < this.specialChars.length; i++) {
41982 smenu.menu.items.push({
41984 html: this.specialChars[i],
41985 handler: function(a,b) {
41986 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
41987 //editor.insertAtCursor(a.html);
42000 if (!this.disable.specialElements) {
42003 cls: 'x-edit-none',
42008 for (var i =0; i < this.specialElements.length; i++) {
42009 semenu.menu.items.push(
42011 handler: function(a,b) {
42012 editor.insertAtCursor(this.ihtml);
42014 }, this.specialElements[i])
42026 for(var i =0; i< this.btns.length;i++) {
42027 var b = Roo.factory(this.btns[i],Roo.form);
42028 b.cls = 'x-edit-none';
42037 // disable everything...
42039 this.tb.items.each(function(item){
42040 if(item.id != editor.frameId+ '-sourceedit'){
42044 this.rendered = true;
42046 // the all the btns;
42047 editor.on('editorevent', this.updateToolbar, this);
42048 // other toolbars need to implement this..
42049 //editor.on('editmodechange', this.updateToolbar, this);
42055 * Protected method that will not generally be called directly. It triggers
42056 * a toolbar update by reading the markup state of the current selection in the editor.
42058 updateToolbar: function(){
42060 if(!this.editor.activated){
42061 this.editor.onFirstFocus();
42065 var btns = this.tb.items.map,
42066 doc = this.editor.doc,
42067 frameId = this.editor.frameId;
42069 if(!this.disable.font && !Roo.isSafari){
42071 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
42072 if(name != this.fontSelect.dom.value){
42073 this.fontSelect.dom.value = name;
42077 if(!this.disable.format){
42078 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
42079 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
42080 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
42082 if(!this.disable.alignments){
42083 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
42084 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
42085 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
42087 if(!Roo.isSafari && !this.disable.lists){
42088 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
42089 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
42092 var ans = this.editor.getAllAncestors();
42093 if (this.formatCombo) {
42096 var store = this.formatCombo.store;
42097 this.formatCombo.setValue("");
42098 for (var i =0; i < ans.length;i++) {
42099 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
42101 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
42109 // hides menus... - so this cant be on a menu...
42110 Roo.menu.MenuMgr.hideAll();
42112 //this.editorsyncValue();
42116 createFontOptions : function(){
42117 var buf = [], fs = this.fontFamilies, ff, lc;
42121 for(var i = 0, len = fs.length; i< len; i++){
42123 lc = ff.toLowerCase();
42125 '<option value="',lc,'" style="font-family:',ff,';"',
42126 (this.defaultFont == lc ? ' selected="true">' : '>'),
42131 return buf.join('');
42134 toggleSourceEdit : function(sourceEditMode){
42135 if(sourceEditMode === undefined){
42136 sourceEditMode = !this.sourceEditMode;
42138 this.sourceEditMode = sourceEditMode === true;
42139 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
42140 // just toggle the button?
42141 if(btn.pressed !== this.editor.sourceEditMode){
42142 btn.toggle(this.editor.sourceEditMode);
42146 if(this.sourceEditMode){
42147 this.tb.items.each(function(item){
42148 if(item.cmd != 'sourceedit'){
42154 if(this.initialized){
42155 this.tb.items.each(function(item){
42161 // tell the editor that it's been pressed..
42162 this.editor.toggleSourceEdit(sourceEditMode);
42166 * Object collection of toolbar tooltips for the buttons in the editor. The key
42167 * is the command id associated with that button and the value is a valid QuickTips object.
42172 title: 'Bold (Ctrl+B)',
42173 text: 'Make the selected text bold.',
42174 cls: 'x-html-editor-tip'
42177 title: 'Italic (Ctrl+I)',
42178 text: 'Make the selected text italic.',
42179 cls: 'x-html-editor-tip'
42187 title: 'Bold (Ctrl+B)',
42188 text: 'Make the selected text bold.',
42189 cls: 'x-html-editor-tip'
42192 title: 'Italic (Ctrl+I)',
42193 text: 'Make the selected text italic.',
42194 cls: 'x-html-editor-tip'
42197 title: 'Underline (Ctrl+U)',
42198 text: 'Underline the selected text.',
42199 cls: 'x-html-editor-tip'
42201 increasefontsize : {
42202 title: 'Grow Text',
42203 text: 'Increase the font size.',
42204 cls: 'x-html-editor-tip'
42206 decreasefontsize : {
42207 title: 'Shrink Text',
42208 text: 'Decrease the font size.',
42209 cls: 'x-html-editor-tip'
42212 title: 'Text Highlight Color',
42213 text: 'Change the background color of the selected text.',
42214 cls: 'x-html-editor-tip'
42217 title: 'Font Color',
42218 text: 'Change the color of the selected text.',
42219 cls: 'x-html-editor-tip'
42222 title: 'Align Text Left',
42223 text: 'Align text to the left.',
42224 cls: 'x-html-editor-tip'
42227 title: 'Center Text',
42228 text: 'Center text in the editor.',
42229 cls: 'x-html-editor-tip'
42232 title: 'Align Text Right',
42233 text: 'Align text to the right.',
42234 cls: 'x-html-editor-tip'
42236 insertunorderedlist : {
42237 title: 'Bullet List',
42238 text: 'Start a bulleted list.',
42239 cls: 'x-html-editor-tip'
42241 insertorderedlist : {
42242 title: 'Numbered List',
42243 text: 'Start a numbered list.',
42244 cls: 'x-html-editor-tip'
42247 title: 'Hyperlink',
42248 text: 'Make the selected text a hyperlink.',
42249 cls: 'x-html-editor-tip'
42252 title: 'Source Edit',
42253 text: 'Switch to source editing mode.',
42254 cls: 'x-html-editor-tip'
42258 onDestroy : function(){
42261 this.tb.items.each(function(item){
42263 item.menu.removeAll();
42265 item.menu.el.destroy();
42273 onFirstFocus: function() {
42274 this.tb.items.each(function(item){
42283 // <script type="text/javascript">
42286 * Ext JS Library 1.1.1
42287 * Copyright(c) 2006-2007, Ext JS, LLC.
42294 * @class Roo.form.HtmlEditor.ToolbarContext
42299 new Roo.form.HtmlEditor({
42302 { xtype: 'ToolbarStandard', styles : {} }
42303 { xtype: 'ToolbarContext', disable : {} }
42309 * @config : {Object} disable List of elements to disable.. (not done yet.)
42310 * @config : {Object} styles Map of styles available.
42314 Roo.form.HtmlEditor.ToolbarContext = function(config)
42317 Roo.apply(this, config);
42318 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42319 // dont call parent... till later.
42320 this.styles = this.styles || {};
42325 Roo.form.HtmlEditor.ToolbarContext.types = {
42337 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
42399 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
42404 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
42414 style : 'fontFamily',
42415 displayField: 'display',
42416 optname : 'font-family',
42465 // should we really allow this??
42466 // should this just be
42477 style : 'fontFamily',
42478 displayField: 'display',
42479 optname : 'font-family',
42486 style : 'fontFamily',
42487 displayField: 'display',
42488 optname : 'font-family',
42495 style : 'fontFamily',
42496 displayField: 'display',
42497 optname : 'font-family',
42508 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
42509 Roo.form.HtmlEditor.ToolbarContext.stores = false;
42511 Roo.form.HtmlEditor.ToolbarContext.options = {
42513 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
42514 [ 'Courier New', 'Courier New'],
42515 [ 'Tahoma', 'Tahoma'],
42516 [ 'Times New Roman,serif', 'Times'],
42517 [ 'Verdana','Verdana' ]
42521 // fixme - these need to be configurable..
42524 Roo.form.HtmlEditor.ToolbarContext.types
42527 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
42535 * @cfg {Object} disable List of toolbar elements to disable
42540 * @cfg {Object} styles List of styles
42541 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
42543 * These must be defined in the page, so they get rendered correctly..
42554 init : function(editor)
42556 this.editor = editor;
42559 var fid = editor.frameId;
42561 function btn(id, toggle, handler){
42562 var xid = fid + '-'+ id ;
42566 cls : 'x-btn-icon x-edit-'+id,
42567 enableToggle:toggle !== false,
42568 scope: editor, // was editor...
42569 handler:handler||editor.relayBtnCmd,
42570 clickEvent:'mousedown',
42571 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42575 // create a new element.
42576 var wdiv = editor.wrap.createChild({
42578 }, editor.wrap.dom.firstChild.nextSibling, true);
42580 // can we do this more than once??
42582 // stop form submits
42585 // disable everything...
42586 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42587 this.toolbars = {};
42589 for (var i in ty) {
42591 this.toolbars[i] = this.buildToolbar(ty[i],i);
42593 this.tb = this.toolbars.BODY;
42595 this.buildFooter();
42596 this.footer.show();
42597 editor.on('hide', function( ) { this.footer.hide() }, this);
42598 editor.on('show', function( ) { this.footer.show() }, this);
42601 this.rendered = true;
42603 // the all the btns;
42604 editor.on('editorevent', this.updateToolbar, this);
42605 // other toolbars need to implement this..
42606 //editor.on('editmodechange', this.updateToolbar, this);
42612 * Protected method that will not generally be called directly. It triggers
42613 * a toolbar update by reading the markup state of the current selection in the editor.
42615 updateToolbar: function(editor,ev,sel){
42618 // capture mouse up - this is handy for selecting images..
42619 // perhaps should go somewhere else...
42620 if(!this.editor.activated){
42621 this.editor.onFirstFocus();
42625 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
42626 // selectNode - might want to handle IE?
42628 (ev.type == 'mouseup' || ev.type == 'click' ) &&
42629 ev.target && ev.target.tagName == 'IMG') {
42630 // they have click on an image...
42631 // let's see if we can change the selection...
42634 var nodeRange = sel.ownerDocument.createRange();
42636 nodeRange.selectNode(sel);
42638 nodeRange.selectNodeContents(sel);
42640 //nodeRange.collapse(true);
42641 var s = editor.win.getSelection();
42642 s.removeAllRanges();
42643 s.addRange(nodeRange);
42647 var updateFooter = sel ? false : true;
42650 var ans = this.editor.getAllAncestors();
42653 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
42656 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
42657 sel = sel ? sel : this.editor.doc.body;
42658 sel = sel.tagName.length ? sel : this.editor.doc.body;
42661 // pick a menu that exists..
42662 var tn = sel.tagName.toUpperCase();
42663 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
42665 tn = sel.tagName.toUpperCase();
42667 var lastSel = this.tb.selectedNode
42669 this.tb.selectedNode = sel;
42671 // if current menu does not match..
42672 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
42675 ///console.log("show: " + tn);
42676 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
42679 this.tb.items.first().el.innerHTML = tn + ': ';
42682 // update attributes
42683 if (this.tb.fields) {
42684 this.tb.fields.each(function(e) {
42686 e.setValue(sel.style[e.stylename]);
42689 e.setValue(sel.getAttribute(e.attrname));
42693 var hasStyles = false;
42694 for(var i in this.styles) {
42701 var st = this.tb.fields.item(0);
42703 st.store.removeAll();
42706 var cn = sel.className.split(/\s+/);
42709 if (this.styles['*']) {
42711 Roo.each(this.styles['*'], function(v) {
42712 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42715 if (this.styles[tn]) {
42716 Roo.each(this.styles[tn], function(v) {
42717 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
42721 st.store.loadData(avs);
42725 // flag our selected Node.
42726 this.tb.selectedNode = sel;
42729 Roo.menu.MenuMgr.hideAll();
42733 if (!updateFooter) {
42734 //this.footDisp.dom.innerHTML = '';
42737 // update the footer
42741 this.footerEls = ans.reverse();
42742 Roo.each(this.footerEls, function(a,i) {
42743 if (!a) { return; }
42744 html += html.length ? ' > ' : '';
42746 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
42751 var sz = this.footDisp.up('td').getSize();
42752 this.footDisp.dom.style.width = (sz.width -10) + 'px';
42753 this.footDisp.dom.style.marginLeft = '5px';
42755 this.footDisp.dom.style.overflow = 'hidden';
42757 this.footDisp.dom.innerHTML = html;
42759 //this.editorsyncValue();
42766 onDestroy : function(){
42769 this.tb.items.each(function(item){
42771 item.menu.removeAll();
42773 item.menu.el.destroy();
42781 onFirstFocus: function() {
42782 // need to do this for all the toolbars..
42783 this.tb.items.each(function(item){
42787 buildToolbar: function(tlist, nm)
42789 var editor = this.editor;
42790 // create a new element.
42791 var wdiv = editor.wrap.createChild({
42793 }, editor.wrap.dom.firstChild.nextSibling, true);
42796 var tb = new Roo.Toolbar(wdiv);
42799 tb.add(nm+ ": ");
42802 for(var i in this.styles) {
42807 if (styles && styles.length) {
42809 // this needs a multi-select checkbox...
42810 tb.addField( new Roo.form.ComboBox({
42811 store: new Roo.data.SimpleStore({
42813 fields: ['val', 'selected'],
42816 name : '-roo-edit-className',
42817 attrname : 'className',
42818 displayField: 'val',
42822 triggerAction: 'all',
42823 emptyText:'Select Style',
42824 selectOnFocus:true,
42827 'select': function(c, r, i) {
42828 // initial support only for on class per el..
42829 tb.selectedNode.className = r ? r.get('val') : '';
42830 editor.syncValue();
42837 var tbc = Roo.form.HtmlEditor.ToolbarContext;
42838 var tbops = tbc.options;
42840 for (var i in tlist) {
42842 var item = tlist[i];
42843 tb.add(item.title + ": ");
42846 //optname == used so you can configure the options available..
42847 var opts = item.opts ? item.opts : false;
42848 if (item.optname) {
42849 opts = tbops[item.optname];
42854 // opts == pulldown..
42855 tb.addField( new Roo.form.ComboBox({
42856 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
42858 fields: ['val', 'display'],
42861 name : '-roo-edit-' + i,
42863 stylename : item.style ? item.style : false,
42864 displayField: item.displayField ? item.displayField : 'val',
42865 valueField : 'val',
42867 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
42869 triggerAction: 'all',
42870 emptyText:'Select',
42871 selectOnFocus:true,
42872 width: item.width ? item.width : 130,
42874 'select': function(c, r, i) {
42876 tb.selectedNode.style[c.stylename] = r.get('val');
42879 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
42888 tb.addField( new Roo.form.TextField({
42891 //allowBlank:false,
42896 tb.addField( new Roo.form.TextField({
42897 name: '-roo-edit-' + i,
42904 'change' : function(f, nv, ov) {
42905 tb.selectedNode.setAttribute(f.attrname, nv);
42914 text: 'Remove Tag',
42917 click : function ()
42920 // undo does not work.
42922 var sn = tb.selectedNode;
42924 var pn = sn.parentNode;
42926 var stn = sn.childNodes[0];
42927 var en = sn.childNodes[sn.childNodes.length - 1 ];
42928 while (sn.childNodes.length) {
42929 var node = sn.childNodes[0];
42930 sn.removeChild(node);
42932 pn.insertBefore(node, sn);
42935 pn.removeChild(sn);
42936 var range = editor.createRange();
42938 range.setStart(stn,0);
42939 range.setEnd(en,0); //????
42940 //range.selectNode(sel);
42943 var selection = editor.getSelection();
42944 selection.removeAllRanges();
42945 selection.addRange(range);
42949 //_this.updateToolbar(null, null, pn);
42950 _this.updateToolbar(null, null, null);
42951 _this.footDisp.dom.innerHTML = '';
42961 tb.el.on('click', function(e){
42962 e.preventDefault(); // what does this do?
42964 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
42967 // dont need to disable them... as they will get hidden
42972 buildFooter : function()
42975 var fel = this.editor.wrap.createChild();
42976 this.footer = new Roo.Toolbar(fel);
42977 // toolbar has scrolly on left / right?
42978 var footDisp= new Roo.Toolbar.Fill();
42984 handler : function() {
42985 _t.footDisp.scrollTo('left',0,true)
42989 this.footer.add( footDisp );
42994 handler : function() {
42996 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
43000 var fel = Roo.get(footDisp.el);
43001 fel.addClass('x-editor-context');
43002 this.footDispWrap = fel;
43003 this.footDispWrap.overflow = 'hidden';
43005 this.footDisp = fel.createChild();
43006 this.footDispWrap.on('click', this.onContextClick, this)
43010 onContextClick : function (ev,dom)
43012 ev.preventDefault();
43013 var cn = dom.className;
43015 if (!cn.match(/x-ed-loc-/)) {
43018 var n = cn.split('-').pop();
43019 var ans = this.footerEls;
43023 var range = this.editor.createRange();
43025 range.selectNodeContents(sel);
43026 //range.selectNode(sel);
43029 var selection = this.editor.getSelection();
43030 selection.removeAllRanges();
43031 selection.addRange(range);
43035 this.updateToolbar(null, null, sel);
43052 * Ext JS Library 1.1.1
43053 * Copyright(c) 2006-2007, Ext JS, LLC.
43055 * Originally Released Under LGPL - original licence link has changed is not relivant.
43058 * <script type="text/javascript">
43062 * @class Roo.form.BasicForm
43063 * @extends Roo.util.Observable
43064 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
43066 * @param {String/HTMLElement/Roo.Element} el The form element or its id
43067 * @param {Object} config Configuration options
43069 Roo.form.BasicForm = function(el, config){
43070 this.allItems = [];
43071 this.childForms = [];
43072 Roo.apply(this, config);
43074 * The Roo.form.Field items in this form.
43075 * @type MixedCollection
43079 this.items = new Roo.util.MixedCollection(false, function(o){
43080 return o.id || (o.id = Roo.id());
43084 * @event beforeaction
43085 * Fires before any action is performed. Return false to cancel the action.
43086 * @param {Form} this
43087 * @param {Action} action The action to be performed
43089 beforeaction: true,
43091 * @event actionfailed
43092 * Fires when an action fails.
43093 * @param {Form} this
43094 * @param {Action} action The action that failed
43096 actionfailed : true,
43098 * @event actioncomplete
43099 * Fires when an action is completed.
43100 * @param {Form} this
43101 * @param {Action} action The action that completed
43103 actioncomplete : true
43108 Roo.form.BasicForm.superclass.constructor.call(this);
43111 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
43113 * @cfg {String} method
43114 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
43117 * @cfg {DataReader} reader
43118 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
43119 * This is optional as there is built-in support for processing JSON.
43122 * @cfg {DataReader} errorReader
43123 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
43124 * This is completely optional as there is built-in support for processing JSON.
43127 * @cfg {String} url
43128 * The URL to use for form actions if one isn't supplied in the action options.
43131 * @cfg {Boolean} fileUpload
43132 * Set to true if this form is a file upload.
43136 * @cfg {Object} baseParams
43137 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
43142 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
43147 activeAction : null,
43150 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
43151 * or setValues() data instead of when the form was first created.
43153 trackResetOnLoad : false,
43157 * childForms - used for multi-tab forms
43160 childForms : false,
43163 * allItems - full list of fields.
43169 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
43170 * element by passing it or its id or mask the form itself by passing in true.
43173 waitMsgTarget : false,
43176 initEl : function(el){
43177 this.el = Roo.get(el);
43178 this.id = this.el.id || Roo.id();
43179 this.el.on('submit', this.onSubmit, this);
43180 this.el.addClass('x-form');
43184 onSubmit : function(e){
43189 * Returns true if client-side validation on the form is successful.
43192 isValid : function(){
43194 this.items.each(function(f){
43203 * Returns true if any fields in this form have changed since their original load.
43206 isDirty : function(){
43208 this.items.each(function(f){
43218 * Performs a predefined action (submit or load) or custom actions you define on this form.
43219 * @param {String} actionName The name of the action type
43220 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
43221 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
43222 * accept other config options):
43224 Property Type Description
43225 ---------------- --------------- ----------------------------------------------------------------------------------
43226 url String The url for the action (defaults to the form's url)
43227 method String The form method to use (defaults to the form's method, or POST if not defined)
43228 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
43229 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
43230 validate the form on the client (defaults to false)
43232 * @return {BasicForm} this
43234 doAction : function(action, options){
43235 if(typeof action == 'string'){
43236 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
43238 if(this.fireEvent('beforeaction', this, action) !== false){
43239 this.beforeAction(action);
43240 action.run.defer(100, action);
43246 * Shortcut to do a submit action.
43247 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43248 * @return {BasicForm} this
43250 submit : function(options){
43251 this.doAction('submit', options);
43256 * Shortcut to do a load action.
43257 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
43258 * @return {BasicForm} this
43260 load : function(options){
43261 this.doAction('load', options);
43266 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
43267 * @param {Record} record The record to edit
43268 * @return {BasicForm} this
43270 updateRecord : function(record){
43271 record.beginEdit();
43272 var fs = record.fields;
43273 fs.each(function(f){
43274 var field = this.findField(f.name);
43276 record.set(f.name, field.getValue());
43284 * Loads an Roo.data.Record into this form.
43285 * @param {Record} record The record to load
43286 * @return {BasicForm} this
43288 loadRecord : function(record){
43289 this.setValues(record.data);
43294 beforeAction : function(action){
43295 var o = action.options;
43298 if(this.waitMsgTarget === true){
43299 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
43300 }else if(this.waitMsgTarget){
43301 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
43302 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
43304 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
43310 afterAction : function(action, success){
43311 this.activeAction = null;
43312 var o = action.options;
43314 if(this.waitMsgTarget === true){
43316 }else if(this.waitMsgTarget){
43317 this.waitMsgTarget.unmask();
43319 Roo.MessageBox.updateProgress(1);
43320 Roo.MessageBox.hide();
43327 Roo.callback(o.success, o.scope, [this, action]);
43328 this.fireEvent('actioncomplete', this, action);
43332 // failure condition..
43333 // we have a scenario where updates need confirming.
43334 // eg. if a locking scenario exists..
43335 // we look for { errors : { needs_confirm : true }} in the response.
43337 (typeof(action.result) != 'undefined') &&
43338 (typeof(action.result.errors) != 'undefined') &&
43339 (typeof(action.result.errors.needs_confirm) != 'undefined')
43342 Roo.MessageBox.confirm(
43343 "Change requires confirmation",
43344 action.result.errorMsg,
43349 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
43359 Roo.callback(o.failure, o.scope, [this, action]);
43360 // show an error message if no failed handler is set..
43361 if (!this.hasListener('actionfailed')) {
43362 Roo.MessageBox.alert("Error",
43363 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
43364 action.result.errorMsg :
43365 "Saving Failed, please check your entries or try again"
43369 this.fireEvent('actionfailed', this, action);
43375 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
43376 * @param {String} id The value to search for
43379 findField : function(id){
43380 var field = this.items.get(id);
43382 this.items.each(function(f){
43383 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
43389 return field || null;
43393 * Add a secondary form to this one,
43394 * Used to provide tabbed forms. One form is primary, with hidden values
43395 * which mirror the elements from the other forms.
43397 * @param {Roo.form.Form} form to add.
43400 addForm : function(form)
43403 if (this.childForms.indexOf(form) > -1) {
43407 this.childForms.push(form);
43409 Roo.each(form.allItems, function (fe) {
43411 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
43412 if (this.findField(n)) { // already added..
43415 var add = new Roo.form.Hidden({
43418 add.render(this.el);
43425 * Mark fields in this form invalid in bulk.
43426 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
43427 * @return {BasicForm} this
43429 markInvalid : function(errors){
43430 if(errors instanceof Array){
43431 for(var i = 0, len = errors.length; i < len; i++){
43432 var fieldError = errors[i];
43433 var f = this.findField(fieldError.id);
43435 f.markInvalid(fieldError.msg);
43441 if(typeof errors[id] != 'function' && (field = this.findField(id))){
43442 field.markInvalid(errors[id]);
43446 Roo.each(this.childForms || [], function (f) {
43447 f.markInvalid(errors);
43454 * Set values for fields in this form in bulk.
43455 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
43456 * @return {BasicForm} this
43458 setValues : function(values){
43459 if(values instanceof Array){ // array of objects
43460 for(var i = 0, len = values.length; i < len; i++){
43462 var f = this.findField(v.id);
43464 f.setValue(v.value);
43465 if(this.trackResetOnLoad){
43466 f.originalValue = f.getValue();
43470 }else{ // object hash
43473 if(typeof values[id] != 'function' && (field = this.findField(id))){
43475 if (field.setFromData &&
43476 field.valueField &&
43477 field.displayField &&
43478 // combos' with local stores can
43479 // be queried via setValue()
43480 // to set their value..
43481 (field.store && !field.store.isLocal)
43485 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
43486 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
43487 field.setFromData(sd);
43490 field.setValue(values[id]);
43494 if(this.trackResetOnLoad){
43495 field.originalValue = field.getValue();
43501 Roo.each(this.childForms || [], function (f) {
43502 f.setValues(values);
43509 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
43510 * they are returned as an array.
43511 * @param {Boolean} asString
43514 getValues : function(asString){
43515 if (this.childForms) {
43516 // copy values from the child forms
43517 Roo.each(this.childForms, function (f) {
43518 this.setValues(f.getValues());
43524 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
43525 if(asString === true){
43528 return Roo.urlDecode(fs);
43532 * Returns the fields in this form as an object with key/value pairs.
43533 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
43536 getFieldValues : function(with_hidden)
43538 if (this.childForms) {
43539 // copy values from the child forms
43540 // should this call getFieldValues - probably not as we do not currently copy
43541 // hidden fields when we generate..
43542 Roo.each(this.childForms, function (f) {
43543 this.setValues(f.getValues());
43548 this.items.each(function(f){
43549 if (!f.getName()) {
43552 var v = f.getValue();
43553 if (f.inputType =='radio') {
43554 if (typeof(ret[f.getName()]) == 'undefined') {
43555 ret[f.getName()] = ''; // empty..
43558 if (!f.el.dom.checked) {
43562 v = f.el.dom.value;
43566 // not sure if this supported any more..
43567 if ((typeof(v) == 'object') && f.getRawValue) {
43568 v = f.getRawValue() ; // dates..
43570 // combo boxes where name != hiddenName...
43571 if (f.name != f.getName()) {
43572 ret[f.name] = f.getRawValue();
43574 ret[f.getName()] = v;
43581 * Clears all invalid messages in this form.
43582 * @return {BasicForm} this
43584 clearInvalid : function(){
43585 this.items.each(function(f){
43589 Roo.each(this.childForms || [], function (f) {
43598 * Resets this form.
43599 * @return {BasicForm} this
43601 reset : function(){
43602 this.items.each(function(f){
43606 Roo.each(this.childForms || [], function (f) {
43615 * Add Roo.form components to this form.
43616 * @param {Field} field1
43617 * @param {Field} field2 (optional)
43618 * @param {Field} etc (optional)
43619 * @return {BasicForm} this
43622 this.items.addAll(Array.prototype.slice.call(arguments, 0));
43628 * Removes a field from the items collection (does NOT remove its markup).
43629 * @param {Field} field
43630 * @return {BasicForm} this
43632 remove : function(field){
43633 this.items.remove(field);
43638 * Looks at the fields in this form, checks them for an id attribute,
43639 * and calls applyTo on the existing dom element with that id.
43640 * @return {BasicForm} this
43642 render : function(){
43643 this.items.each(function(f){
43644 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
43652 * Calls {@link Ext#apply} for all fields in this form with the passed object.
43653 * @param {Object} values
43654 * @return {BasicForm} this
43656 applyToFields : function(o){
43657 this.items.each(function(f){
43664 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
43665 * @param {Object} values
43666 * @return {BasicForm} this
43668 applyIfToFields : function(o){
43669 this.items.each(function(f){
43677 Roo.BasicForm = Roo.form.BasicForm;/*
43679 * Ext JS Library 1.1.1
43680 * Copyright(c) 2006-2007, Ext JS, LLC.
43682 * Originally Released Under LGPL - original licence link has changed is not relivant.
43685 * <script type="text/javascript">
43689 * @class Roo.form.Form
43690 * @extends Roo.form.BasicForm
43691 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
43693 * @param {Object} config Configuration options
43695 Roo.form.Form = function(config){
43697 if (config.items) {
43698 xitems = config.items;
43699 delete config.items;
43703 Roo.form.Form.superclass.constructor.call(this, null, config);
43704 this.url = this.url || this.action;
43706 this.root = new Roo.form.Layout(Roo.applyIf({
43710 this.active = this.root;
43712 * Array of all the buttons that have been added to this form via {@link addButton}
43716 this.allItems = [];
43719 * @event clientvalidation
43720 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
43721 * @param {Form} this
43722 * @param {Boolean} valid true if the form has passed client-side validation
43724 clientvalidation: true,
43727 * Fires when the form is rendered
43728 * @param {Roo.form.Form} form
43733 if (this.progressUrl) {
43734 // push a hidden field onto the list of fields..
43738 name : 'UPLOAD_IDENTIFIER'
43743 Roo.each(xitems, this.addxtype, this);
43749 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
43751 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
43754 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
43757 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
43759 buttonAlign:'center',
43762 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
43767 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
43768 * This property cascades to child containers if not set.
43773 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
43774 * fires a looping event with that state. This is required to bind buttons to the valid
43775 * state using the config value formBind:true on the button.
43777 monitorValid : false,
43780 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
43785 * @cfg {String} progressUrl - Url to return progress data
43788 progressUrl : false,
43791 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
43792 * fields are added and the column is closed. If no fields are passed the column remains open
43793 * until end() is called.
43794 * @param {Object} config The config to pass to the column
43795 * @param {Field} field1 (optional)
43796 * @param {Field} field2 (optional)
43797 * @param {Field} etc (optional)
43798 * @return Column The column container object
43800 column : function(c){
43801 var col = new Roo.form.Column(c);
43803 if(arguments.length > 1){ // duplicate code required because of Opera
43804 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43811 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
43812 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
43813 * until end() is called.
43814 * @param {Object} config The config to pass to the fieldset
43815 * @param {Field} field1 (optional)
43816 * @param {Field} field2 (optional)
43817 * @param {Field} etc (optional)
43818 * @return FieldSet The fieldset container object
43820 fieldset : function(c){
43821 var fs = new Roo.form.FieldSet(c);
43823 if(arguments.length > 1){ // duplicate code required because of Opera
43824 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43831 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
43832 * fields are added and the container is closed. If no fields are passed the container remains open
43833 * until end() is called.
43834 * @param {Object} config The config to pass to the Layout
43835 * @param {Field} field1 (optional)
43836 * @param {Field} field2 (optional)
43837 * @param {Field} etc (optional)
43838 * @return Layout The container object
43840 container : function(c){
43841 var l = new Roo.form.Layout(c);
43843 if(arguments.length > 1){ // duplicate code required because of Opera
43844 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
43851 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
43852 * @param {Object} container A Roo.form.Layout or subclass of Layout
43853 * @return {Form} this
43855 start : function(c){
43856 // cascade label info
43857 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
43858 this.active.stack.push(c);
43859 c.ownerCt = this.active;
43865 * Closes the current open container
43866 * @return {Form} this
43869 if(this.active == this.root){
43872 this.active = this.active.ownerCt;
43877 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
43878 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
43879 * as the label of the field.
43880 * @param {Field} field1
43881 * @param {Field} field2 (optional)
43882 * @param {Field} etc. (optional)
43883 * @return {Form} this
43886 this.active.stack.push.apply(this.active.stack, arguments);
43887 this.allItems.push.apply(this.allItems,arguments);
43889 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
43890 if(a[i].isFormField){
43895 Roo.form.Form.superclass.add.apply(this, r);
43905 * Find any element that has been added to a form, using it's ID or name
43906 * This can include framesets, columns etc. along with regular fields..
43907 * @param {String} id - id or name to find.
43909 * @return {Element} e - or false if nothing found.
43911 findbyId : function(id)
43917 Roo.each(this.allItems, function(f){
43918 if (f.id == id || f.name == id ){
43929 * Render this form into the passed container. This should only be called once!
43930 * @param {String/HTMLElement/Element} container The element this component should be rendered into
43931 * @return {Form} this
43933 render : function(ct)
43939 var o = this.autoCreate || {
43941 method : this.method || 'POST',
43942 id : this.id || Roo.id()
43944 this.initEl(ct.createChild(o));
43946 this.root.render(this.el);
43950 this.items.each(function(f){
43951 f.render('x-form-el-'+f.id);
43954 if(this.buttons.length > 0){
43955 // tables are required to maintain order and for correct IE layout
43956 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
43957 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
43958 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
43960 var tr = tb.getElementsByTagName('tr')[0];
43961 for(var i = 0, len = this.buttons.length; i < len; i++) {
43962 var b = this.buttons[i];
43963 var td = document.createElement('td');
43964 td.className = 'x-form-btn-td';
43965 b.render(tr.appendChild(td));
43968 if(this.monitorValid){ // initialize after render
43969 this.startMonitoring();
43971 this.fireEvent('rendered', this);
43976 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
43977 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
43978 * object or a valid Roo.DomHelper element config
43979 * @param {Function} handler The function called when the button is clicked
43980 * @param {Object} scope (optional) The scope of the handler function
43981 * @return {Roo.Button}
43983 addButton : function(config, handler, scope){
43987 minWidth: this.minButtonWidth,
43990 if(typeof config == "string"){
43993 Roo.apply(bc, config);
43995 var btn = new Roo.Button(null, bc);
43996 this.buttons.push(btn);
44001 * Adds a series of form elements (using the xtype property as the factory method.
44002 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
44003 * @param {Object} config
44006 addxtype : function()
44008 var ar = Array.prototype.slice.call(arguments, 0);
44010 for(var i = 0; i < ar.length; i++) {
44012 continue; // skip -- if this happends something invalid got sent, we
44013 // should ignore it, as basically that interface element will not show up
44014 // and that should be pretty obvious!!
44017 if (Roo.form[ar[i].xtype]) {
44019 var fe = Roo.factory(ar[i], Roo.form);
44025 fe.store.form = this;
44030 this.allItems.push(fe);
44031 if (fe.items && fe.addxtype) {
44032 fe.addxtype.apply(fe, fe.items);
44042 // console.log('adding ' + ar[i].xtype);
44044 if (ar[i].xtype == 'Button') {
44045 //console.log('adding button');
44046 //console.log(ar[i]);
44047 this.addButton(ar[i]);
44048 this.allItems.push(fe);
44052 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
44053 alert('end is not supported on xtype any more, use items');
44055 // //console.log('adding end');
44063 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
44064 * option "monitorValid"
44066 startMonitoring : function(){
44069 Roo.TaskMgr.start({
44070 run : this.bindHandler,
44071 interval : this.monitorPoll || 200,
44078 * Stops monitoring of the valid state of this form
44080 stopMonitoring : function(){
44081 this.bound = false;
44085 bindHandler : function(){
44087 return false; // stops binding
44090 this.items.each(function(f){
44091 if(!f.isValid(true)){
44096 for(var i = 0, len = this.buttons.length; i < len; i++){
44097 var btn = this.buttons[i];
44098 if(btn.formBind === true && btn.disabled === valid){
44099 btn.setDisabled(!valid);
44102 this.fireEvent('clientvalidation', this, valid);
44116 Roo.Form = Roo.form.Form;
44119 * Ext JS Library 1.1.1
44120 * Copyright(c) 2006-2007, Ext JS, LLC.
44122 * Originally Released Under LGPL - original licence link has changed is not relivant.
44125 * <script type="text/javascript">
44129 * @class Roo.form.Action
44130 * Internal Class used to handle form actions
44132 * @param {Roo.form.BasicForm} el The form element or its id
44133 * @param {Object} config Configuration options
44137 // define the action interface
44138 Roo.form.Action = function(form, options){
44140 this.options = options || {};
44143 * Client Validation Failed
44146 Roo.form.Action.CLIENT_INVALID = 'client';
44148 * Server Validation Failed
44151 Roo.form.Action.SERVER_INVALID = 'server';
44153 * Connect to Server Failed
44156 Roo.form.Action.CONNECT_FAILURE = 'connect';
44158 * Reading Data from Server Failed
44161 Roo.form.Action.LOAD_FAILURE = 'load';
44163 Roo.form.Action.prototype = {
44165 failureType : undefined,
44166 response : undefined,
44167 result : undefined,
44169 // interface method
44170 run : function(options){
44174 // interface method
44175 success : function(response){
44179 // interface method
44180 handleResponse : function(response){
44184 // default connection failure
44185 failure : function(response){
44187 this.response = response;
44188 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44189 this.form.afterAction(this, false);
44192 processResponse : function(response){
44193 this.response = response;
44194 if(!response.responseText){
44197 this.result = this.handleResponse(response);
44198 return this.result;
44201 // utility functions used internally
44202 getUrl : function(appendParams){
44203 var url = this.options.url || this.form.url || this.form.el.dom.action;
44205 var p = this.getParams();
44207 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
44213 getMethod : function(){
44214 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
44217 getParams : function(){
44218 var bp = this.form.baseParams;
44219 var p = this.options.params;
44221 if(typeof p == "object"){
44222 p = Roo.urlEncode(Roo.applyIf(p, bp));
44223 }else if(typeof p == 'string' && bp){
44224 p += '&' + Roo.urlEncode(bp);
44227 p = Roo.urlEncode(bp);
44232 createCallback : function(){
44234 success: this.success,
44235 failure: this.failure,
44237 timeout: (this.form.timeout*1000),
44238 upload: this.form.fileUpload ? this.success : undefined
44243 Roo.form.Action.Submit = function(form, options){
44244 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
44247 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
44250 haveProgress : false,
44251 uploadComplete : false,
44253 // uploadProgress indicator.
44254 uploadProgress : function()
44256 if (!this.form.progressUrl) {
44260 if (!this.haveProgress) {
44261 Roo.MessageBox.progress("Uploading", "Uploading");
44263 if (this.uploadComplete) {
44264 Roo.MessageBox.hide();
44268 this.haveProgress = true;
44270 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
44272 var c = new Roo.data.Connection();
44274 url : this.form.progressUrl,
44279 success : function(req){
44280 //console.log(data);
44284 rdata = Roo.decode(req.responseText)
44286 Roo.log("Invalid data from server..");
44290 if (!rdata || !rdata.success) {
44292 Roo.MessageBox.alert(Roo.encode(rdata));
44295 var data = rdata.data;
44297 if (this.uploadComplete) {
44298 Roo.MessageBox.hide();
44303 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
44304 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
44307 this.uploadProgress.defer(2000,this);
44310 failure: function(data) {
44311 Roo.log('progress url failed ');
44322 // run get Values on the form, so it syncs any secondary forms.
44323 this.form.getValues();
44325 var o = this.options;
44326 var method = this.getMethod();
44327 var isPost = method == 'POST';
44328 if(o.clientValidation === false || this.form.isValid()){
44330 if (this.form.progressUrl) {
44331 this.form.findField('UPLOAD_IDENTIFIER').setValue(
44332 (new Date() * 1) + '' + Math.random());
44337 Roo.Ajax.request(Roo.apply(this.createCallback(), {
44338 form:this.form.el.dom,
44339 url:this.getUrl(!isPost),
44341 params:isPost ? this.getParams() : null,
44342 isUpload: this.form.fileUpload
44345 this.uploadProgress();
44347 }else if (o.clientValidation !== false){ // client validation failed
44348 this.failureType = Roo.form.Action.CLIENT_INVALID;
44349 this.form.afterAction(this, false);
44353 success : function(response)
44355 this.uploadComplete= true;
44356 if (this.haveProgress) {
44357 Roo.MessageBox.hide();
44361 var result = this.processResponse(response);
44362 if(result === true || result.success){
44363 this.form.afterAction(this, true);
44367 this.form.markInvalid(result.errors);
44368 this.failureType = Roo.form.Action.SERVER_INVALID;
44370 this.form.afterAction(this, false);
44372 failure : function(response)
44374 this.uploadComplete= true;
44375 if (this.haveProgress) {
44376 Roo.MessageBox.hide();
44379 this.response = response;
44380 this.failureType = Roo.form.Action.CONNECT_FAILURE;
44381 this.form.afterAction(this, false);
44384 handleResponse : function(response){
44385 if(this.form.errorReader){
44386 var rs = this.form.errorReader.read(response);
44389 for(var i = 0, len = rs.records.length; i < len; i++) {
44390 var r = rs.records[i];
44391 errors[i] = r.data;
44394 if(errors.length < 1){
44398 success : rs.success,
44404 ret = Roo.decode(response.responseText);
44408 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
44418 Roo.form.Action.Load = function(form, options){
44419 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
44420 this.reader = this.form.reader;
44423 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
44428 Roo.Ajax.request(Roo.apply(
44429 this.createCallback(), {
44430 method:this.getMethod(),
44431 url:this.getUrl(false),
44432 params:this.getParams()
44436 success : function(response){
44438 var result = this.processResponse(response);
44439 if(result === true || !result.success || !result.data){
44440 this.failureType = Roo.form.Action.LOAD_FAILURE;
44441 this.form.afterAction(this, false);
44444 this.form.clearInvalid();
44445 this.form.setValues(result.data);
44446 this.form.afterAction(this, true);
44449 handleResponse : function(response){
44450 if(this.form.reader){
44451 var rs = this.form.reader.read(response);
44452 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
44454 success : rs.success,
44458 return Roo.decode(response.responseText);
44462 Roo.form.Action.ACTION_TYPES = {
44463 'load' : Roo.form.Action.Load,
44464 'submit' : Roo.form.Action.Submit
44467 * Ext JS Library 1.1.1
44468 * Copyright(c) 2006-2007, Ext JS, LLC.
44470 * Originally Released Under LGPL - original licence link has changed is not relivant.
44473 * <script type="text/javascript">
44477 * @class Roo.form.Layout
44478 * @extends Roo.Component
44479 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
44481 * @param {Object} config Configuration options
44483 Roo.form.Layout = function(config){
44485 if (config.items) {
44486 xitems = config.items;
44487 delete config.items;
44489 Roo.form.Layout.superclass.constructor.call(this, config);
44491 Roo.each(xitems, this.addxtype, this);
44495 Roo.extend(Roo.form.Layout, Roo.Component, {
44497 * @cfg {String/Object} autoCreate
44498 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
44501 * @cfg {String/Object/Function} style
44502 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
44503 * a function which returns such a specification.
44506 * @cfg {String} labelAlign
44507 * Valid values are "left," "top" and "right" (defaults to "left")
44510 * @cfg {Number} labelWidth
44511 * Fixed width in pixels of all field labels (defaults to undefined)
44514 * @cfg {Boolean} clear
44515 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
44519 * @cfg {String} labelSeparator
44520 * The separator to use after field labels (defaults to ':')
44522 labelSeparator : ':',
44524 * @cfg {Boolean} hideLabels
44525 * True to suppress the display of field labels in this layout (defaults to false)
44527 hideLabels : false,
44530 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
44535 onRender : function(ct, position){
44536 if(this.el){ // from markup
44537 this.el = Roo.get(this.el);
44538 }else { // generate
44539 var cfg = this.getAutoCreate();
44540 this.el = ct.createChild(cfg, position);
44543 this.el.applyStyles(this.style);
44545 if(this.labelAlign){
44546 this.el.addClass('x-form-label-'+this.labelAlign);
44548 if(this.hideLabels){
44549 this.labelStyle = "display:none";
44550 this.elementStyle = "padding-left:0;";
44552 if(typeof this.labelWidth == 'number'){
44553 this.labelStyle = "width:"+this.labelWidth+"px;";
44554 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
44556 if(this.labelAlign == 'top'){
44557 this.labelStyle = "width:auto;";
44558 this.elementStyle = "padding-left:0;";
44561 var stack = this.stack;
44562 var slen = stack.length;
44564 if(!this.fieldTpl){
44565 var t = new Roo.Template(
44566 '<div class="x-form-item {5}">',
44567 '<label for="{0}" style="{2}">{1}{4}</label>',
44568 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44570 '</div><div class="x-form-clear-left"></div>'
44572 t.disableFormats = true;
44574 Roo.form.Layout.prototype.fieldTpl = t;
44576 for(var i = 0; i < slen; i++) {
44577 if(stack[i].isFormField){
44578 this.renderField(stack[i]);
44580 this.renderComponent(stack[i]);
44585 this.el.createChild({cls:'x-form-clear'});
44590 renderField : function(f){
44591 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
44594 f.labelStyle||this.labelStyle||'', //2
44595 this.elementStyle||'', //3
44596 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
44597 f.itemCls||this.itemCls||'' //5
44598 ], true).getPrevSibling());
44602 renderComponent : function(c){
44603 c.render(c.isLayout ? this.el : this.el.createChild());
44606 * Adds a object form elements (using the xtype property as the factory method.)
44607 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
44608 * @param {Object} config
44610 addxtype : function(o)
44612 // create the lement.
44613 o.form = this.form;
44614 var fe = Roo.factory(o, Roo.form);
44615 this.form.allItems.push(fe);
44616 this.stack.push(fe);
44618 if (fe.isFormField) {
44619 this.form.items.add(fe);
44627 * @class Roo.form.Column
44628 * @extends Roo.form.Layout
44629 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
44631 * @param {Object} config Configuration options
44633 Roo.form.Column = function(config){
44634 Roo.form.Column.superclass.constructor.call(this, config);
44637 Roo.extend(Roo.form.Column, Roo.form.Layout, {
44639 * @cfg {Number/String} width
44640 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44643 * @cfg {String/Object} autoCreate
44644 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
44648 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
44651 onRender : function(ct, position){
44652 Roo.form.Column.superclass.onRender.call(this, ct, position);
44654 this.el.setWidth(this.width);
44661 * @class Roo.form.Row
44662 * @extends Roo.form.Layout
44663 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
44665 * @param {Object} config Configuration options
44669 Roo.form.Row = function(config){
44670 Roo.form.Row.superclass.constructor.call(this, config);
44673 Roo.extend(Roo.form.Row, Roo.form.Layout, {
44675 * @cfg {Number/String} width
44676 * The fixed width of the column in pixels or CSS value (defaults to "auto")
44679 * @cfg {Number/String} height
44680 * The fixed height of the column in pixels or CSS value (defaults to "auto")
44682 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
44686 onRender : function(ct, position){
44687 //console.log('row render');
44689 var t = new Roo.Template(
44690 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
44691 '<label for="{0}" style="{2}">{1}{4}</label>',
44692 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
44696 t.disableFormats = true;
44698 Roo.form.Layout.prototype.rowTpl = t;
44700 this.fieldTpl = this.rowTpl;
44702 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
44703 var labelWidth = 100;
44705 if ((this.labelAlign != 'top')) {
44706 if (typeof this.labelWidth == 'number') {
44707 labelWidth = this.labelWidth
44709 this.padWidth = 20 + labelWidth;
44713 Roo.form.Column.superclass.onRender.call(this, ct, position);
44715 this.el.setWidth(this.width);
44718 this.el.setHeight(this.height);
44723 renderField : function(f){
44724 f.fieldEl = this.fieldTpl.append(this.el, [
44725 f.id, f.fieldLabel,
44726 f.labelStyle||this.labelStyle||'',
44727 this.elementStyle||'',
44728 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
44729 f.itemCls||this.itemCls||'',
44730 f.width ? f.width + this.padWidth : 160 + this.padWidth
44737 * @class Roo.form.FieldSet
44738 * @extends Roo.form.Layout
44739 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
44741 * @param {Object} config Configuration options
44743 Roo.form.FieldSet = function(config){
44744 Roo.form.FieldSet.superclass.constructor.call(this, config);
44747 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
44749 * @cfg {String} legend
44750 * The text to display as the legend for the FieldSet (defaults to '')
44753 * @cfg {String/Object} autoCreate
44754 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
44758 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
44761 onRender : function(ct, position){
44762 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
44764 this.setLegend(this.legend);
44769 setLegend : function(text){
44771 this.el.child('legend').update(text);
44776 * Ext JS Library 1.1.1
44777 * Copyright(c) 2006-2007, Ext JS, LLC.
44779 * Originally Released Under LGPL - original licence link has changed is not relivant.
44782 * <script type="text/javascript">
44785 * @class Roo.form.VTypes
44786 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
44789 Roo.form.VTypes = function(){
44790 // closure these in so they are only created once.
44791 var alpha = /^[a-zA-Z_]+$/;
44792 var alphanum = /^[a-zA-Z0-9_]+$/;
44793 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
44794 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
44796 // All these messages and functions are configurable
44799 * The function used to validate email addresses
44800 * @param {String} value The email address
44802 'email' : function(v){
44803 return email.test(v);
44806 * The error text to display when the email validation function returns false
44809 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
44811 * The keystroke filter mask to be applied on email input
44814 'emailMask' : /[a-z0-9_\.\-@]/i,
44817 * The function used to validate URLs
44818 * @param {String} value The URL
44820 'url' : function(v){
44821 return url.test(v);
44824 * The error text to display when the url validation function returns false
44827 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
44830 * The function used to validate alpha values
44831 * @param {String} value The value
44833 'alpha' : function(v){
44834 return alpha.test(v);
44837 * The error text to display when the alpha validation function returns false
44840 'alphaText' : 'This field should only contain letters and _',
44842 * The keystroke filter mask to be applied on alpha input
44845 'alphaMask' : /[a-z_]/i,
44848 * The function used to validate alphanumeric values
44849 * @param {String} value The value
44851 'alphanum' : function(v){
44852 return alphanum.test(v);
44855 * The error text to display when the alphanumeric validation function returns false
44858 'alphanumText' : 'This field should only contain letters, numbers and _',
44860 * The keystroke filter mask to be applied on alphanumeric input
44863 'alphanumMask' : /[a-z0-9_]/i
44865 }();//<script type="text/javascript">
44868 * @class Roo.form.FCKeditor
44869 * @extends Roo.form.TextArea
44870 * Wrapper around the FCKEditor http://www.fckeditor.net
44872 * Creates a new FCKeditor
44873 * @param {Object} config Configuration options
44875 Roo.form.FCKeditor = function(config){
44876 Roo.form.FCKeditor.superclass.constructor.call(this, config);
44879 * @event editorinit
44880 * Fired when the editor is initialized - you can add extra handlers here..
44881 * @param {FCKeditor} this
44882 * @param {Object} the FCK object.
44889 Roo.form.FCKeditor.editors = { };
44890 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
44892 //defaultAutoCreate : {
44893 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
44897 * @cfg {Object} fck options - see fck manual for details.
44902 * @cfg {Object} fck toolbar set (Basic or Default)
44904 toolbarSet : 'Basic',
44906 * @cfg {Object} fck BasePath
44908 basePath : '/fckeditor/',
44916 onRender : function(ct, position)
44919 this.defaultAutoCreate = {
44921 style:"width:300px;height:60px;",
44922 autocomplete: "off"
44925 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
44928 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
44929 if(this.preventScrollbars){
44930 this.el.setStyle("overflow", "hidden");
44932 this.el.setHeight(this.growMin);
44935 //console.log('onrender' + this.getId() );
44936 Roo.form.FCKeditor.editors[this.getId()] = this;
44939 this.replaceTextarea() ;
44943 getEditor : function() {
44944 return this.fckEditor;
44947 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
44948 * @param {Mixed} value The value to set
44952 setValue : function(value)
44954 //console.log('setValue: ' + value);
44956 if(typeof(value) == 'undefined') { // not sure why this is happending...
44959 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44961 //if(!this.el || !this.getEditor()) {
44962 // this.value = value;
44963 //this.setValue.defer(100,this,[value]);
44967 if(!this.getEditor()) {
44971 this.getEditor().SetData(value);
44978 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
44979 * @return {Mixed} value The field value
44981 getValue : function()
44984 if (this.frame && this.frame.dom.style.display == 'none') {
44985 return Roo.form.FCKeditor.superclass.getValue.call(this);
44988 if(!this.el || !this.getEditor()) {
44990 // this.getValue.defer(100,this);
44995 var value=this.getEditor().GetData();
44996 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
44997 return Roo.form.FCKeditor.superclass.getValue.call(this);
45003 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
45004 * @return {Mixed} value The field value
45006 getRawValue : function()
45008 if (this.frame && this.frame.dom.style.display == 'none') {
45009 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45012 if(!this.el || !this.getEditor()) {
45013 //this.getRawValue.defer(100,this);
45020 var value=this.getEditor().GetData();
45021 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
45022 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45026 setSize : function(w,h) {
45030 //if (this.frame && this.frame.dom.style.display == 'none') {
45031 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45034 //if(!this.el || !this.getEditor()) {
45035 // this.setSize.defer(100,this, [w,h]);
45041 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45043 this.frame.dom.setAttribute('width', w);
45044 this.frame.dom.setAttribute('height', h);
45045 this.frame.setSize(w,h);
45049 toggleSourceEdit : function(value) {
45053 this.el.dom.style.display = value ? '' : 'none';
45054 this.frame.dom.style.display = value ? 'none' : '';
45059 focus: function(tag)
45061 if (this.frame.dom.style.display == 'none') {
45062 return Roo.form.FCKeditor.superclass.focus.call(this);
45064 if(!this.el || !this.getEditor()) {
45065 this.focus.defer(100,this, [tag]);
45072 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
45073 this.getEditor().Focus();
45075 if (!this.getEditor().Selection.GetSelection()) {
45076 this.focus.defer(100,this, [tag]);
45081 var r = this.getEditor().EditorDocument.createRange();
45082 r.setStart(tgs[0],0);
45083 r.setEnd(tgs[0],0);
45084 this.getEditor().Selection.GetSelection().removeAllRanges();
45085 this.getEditor().Selection.GetSelection().addRange(r);
45086 this.getEditor().Focus();
45093 replaceTextarea : function()
45095 if ( document.getElementById( this.getId() + '___Frame' ) )
45097 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
45099 // We must check the elements firstly using the Id and then the name.
45100 var oTextarea = document.getElementById( this.getId() );
45102 var colElementsByName = document.getElementsByName( this.getId() ) ;
45104 oTextarea.style.display = 'none' ;
45106 if ( oTextarea.tabIndex ) {
45107 this.TabIndex = oTextarea.tabIndex ;
45110 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
45111 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
45112 this.frame = Roo.get(this.getId() + '___Frame')
45115 _getConfigHtml : function()
45119 for ( var o in this.fckconfig ) {
45120 sConfig += sConfig.length > 0 ? '&' : '';
45121 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
45124 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
45128 _getIFrameHtml : function()
45130 var sFile = 'fckeditor.html' ;
45131 /* no idea what this is about..
45134 if ( (/fcksource=true/i).test( window.top.location.search ) )
45135 sFile = 'fckeditor.original.html' ;
45140 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
45141 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
45144 var html = '<iframe id="' + this.getId() +
45145 '___Frame" src="' + sLink +
45146 '" width="' + this.width +
45147 '" height="' + this.height + '"' +
45148 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
45149 ' frameborder="0" scrolling="no"></iframe>' ;
45154 _insertHtmlBefore : function( html, element )
45156 if ( element.insertAdjacentHTML ) {
45158 element.insertAdjacentHTML( 'beforeBegin', html ) ;
45160 var oRange = document.createRange() ;
45161 oRange.setStartBefore( element ) ;
45162 var oFragment = oRange.createContextualFragment( html );
45163 element.parentNode.insertBefore( oFragment, element ) ;
45176 //Roo.reg('fckeditor', Roo.form.FCKeditor);
45178 function FCKeditor_OnComplete(editorInstance){
45179 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
45180 f.fckEditor = editorInstance;
45181 //console.log("loaded");
45182 f.fireEvent('editorinit', f, editorInstance);
45202 //<script type="text/javascript">
45204 * @class Roo.form.GridField
45205 * @extends Roo.form.Field
45206 * Embed a grid (or editable grid into a form)
45209 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
45211 * xgrid.store = Roo.data.Store
45212 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
45213 * xgrid.store.reader = Roo.data.JsonReader
45217 * Creates a new GridField
45218 * @param {Object} config Configuration options
45220 Roo.form.GridField = function(config){
45221 Roo.form.GridField.superclass.constructor.call(this, config);
45225 Roo.extend(Roo.form.GridField, Roo.form.Field, {
45227 * @cfg {Number} width - used to restrict width of grid..
45231 * @cfg {Number} height - used to restrict height of grid..
45235 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
45241 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45242 * {tag: "input", type: "checkbox", autocomplete: "off"})
45244 // defaultAutoCreate : { tag: 'div' },
45245 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45247 * @cfg {String} addTitle Text to include for adding a title.
45251 onResize : function(){
45252 Roo.form.Field.superclass.onResize.apply(this, arguments);
45255 initEvents : function(){
45256 // Roo.form.Checkbox.superclass.initEvents.call(this);
45257 // has no events...
45262 getResizeEl : function(){
45266 getPositionEl : function(){
45271 onRender : function(ct, position){
45273 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
45274 var style = this.style;
45277 Roo.form.GridField.superclass.onRender.call(this, ct, position);
45278 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
45279 this.viewEl = this.wrap.createChild({ tag: 'div' });
45281 this.viewEl.applyStyles(style);
45284 this.viewEl.setWidth(this.width);
45287 this.viewEl.setHeight(this.height);
45289 //if(this.inputValue !== undefined){
45290 //this.setValue(this.value);
45293 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
45296 this.grid.render();
45297 this.grid.getDataSource().on('remove', this.refreshValue, this);
45298 this.grid.getDataSource().on('update', this.refreshValue, this);
45299 this.grid.on('afteredit', this.refreshValue, this);
45305 * Sets the value of the item.
45306 * @param {String} either an object or a string..
45308 setValue : function(v){
45310 v = v || []; // empty set..
45311 // this does not seem smart - it really only affects memoryproxy grids..
45312 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
45313 var ds = this.grid.getDataSource();
45314 // assumes a json reader..
45316 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
45317 ds.loadData( data);
45319 // clear selection so it does not get stale.
45320 if (this.grid.sm) {
45321 this.grid.sm.clearSelections();
45324 Roo.form.GridField.superclass.setValue.call(this, v);
45325 this.refreshValue();
45326 // should load data in the grid really....
45330 refreshValue: function() {
45332 this.grid.getDataSource().each(function(r) {
45335 this.el.dom.value = Roo.encode(val);
45343 * Ext JS Library 1.1.1
45344 * Copyright(c) 2006-2007, Ext JS, LLC.
45346 * Originally Released Under LGPL - original licence link has changed is not relivant.
45349 * <script type="text/javascript">
45352 * @class Roo.form.DisplayField
45353 * @extends Roo.form.Field
45354 * A generic Field to display non-editable data.
45356 * Creates a new Display Field item.
45357 * @param {Object} config Configuration options
45359 Roo.form.DisplayField = function(config){
45360 Roo.form.DisplayField.superclass.constructor.call(this, config);
45364 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
45365 inputType: 'hidden',
45371 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45373 focusClass : undefined,
45375 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45377 fieldClass: 'x-form-field',
45380 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
45382 valueRenderer: undefined,
45386 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45387 * {tag: "input", type: "checkbox", autocomplete: "off"})
45390 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
45392 onResize : function(){
45393 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
45397 initEvents : function(){
45398 // Roo.form.Checkbox.superclass.initEvents.call(this);
45399 // has no events...
45404 getResizeEl : function(){
45408 getPositionEl : function(){
45413 onRender : function(ct, position){
45415 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
45416 //if(this.inputValue !== undefined){
45417 this.wrap = this.el.wrap();
45419 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
45421 if (this.bodyStyle) {
45422 this.viewEl.applyStyles(this.bodyStyle);
45424 //this.viewEl.setStyle('padding', '2px');
45426 this.setValue(this.value);
45431 initValue : Roo.emptyFn,
45436 onClick : function(){
45441 * Sets the checked state of the checkbox.
45442 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
45444 setValue : function(v){
45446 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
45447 // this might be called before we have a dom element..
45448 if (!this.viewEl) {
45451 this.viewEl.dom.innerHTML = html;
45452 Roo.form.DisplayField.superclass.setValue.call(this, v);
45462 * @class Roo.form.DayPicker
45463 * @extends Roo.form.Field
45464 * A Day picker show [M] [T] [W] ....
45466 * Creates a new Day Picker
45467 * @param {Object} config Configuration options
45469 Roo.form.DayPicker= function(config){
45470 Roo.form.DayPicker.superclass.constructor.call(this, config);
45474 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
45476 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
45478 focusClass : undefined,
45480 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
45482 fieldClass: "x-form-field",
45485 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
45486 * {tag: "input", type: "checkbox", autocomplete: "off"})
45488 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
45491 actionMode : 'viewEl',
45495 inputType : 'hidden',
45498 inputElement: false, // real input element?
45499 basedOn: false, // ????
45501 isFormField: true, // not sure where this is needed!!!!
45503 onResize : function(){
45504 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
45505 if(!this.boxLabel){
45506 this.el.alignTo(this.wrap, 'c-c');
45510 initEvents : function(){
45511 Roo.form.Checkbox.superclass.initEvents.call(this);
45512 this.el.on("click", this.onClick, this);
45513 this.el.on("change", this.onClick, this);
45517 getResizeEl : function(){
45521 getPositionEl : function(){
45527 onRender : function(ct, position){
45528 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
45530 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
45532 var r1 = '<table><tr>';
45533 var r2 = '<tr class="x-form-daypick-icons">';
45534 for (var i=0; i < 7; i++) {
45535 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
45536 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
45539 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
45540 viewEl.select('img').on('click', this.onClick, this);
45541 this.viewEl = viewEl;
45544 // this will not work on Chrome!!!
45545 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
45546 this.el.on('propertychange', this.setFromHidden, this); //ie
45554 initValue : Roo.emptyFn,
45557 * Returns the checked state of the checkbox.
45558 * @return {Boolean} True if checked, else false
45560 getValue : function(){
45561 return this.el.dom.value;
45566 onClick : function(e){
45567 //this.setChecked(!this.checked);
45568 Roo.get(e.target).toggleClass('x-menu-item-checked');
45569 this.refreshValue();
45570 //if(this.el.dom.checked != this.checked){
45571 // this.setValue(this.el.dom.checked);
45576 refreshValue : function()
45579 this.viewEl.select('img',true).each(function(e,i,n) {
45580 val += e.is(".x-menu-item-checked") ? String(n) : '';
45582 this.setValue(val, true);
45586 * Sets the checked state of the checkbox.
45587 * On is always based on a string comparison between inputValue and the param.
45588 * @param {Boolean/String} value - the value to set
45589 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
45591 setValue : function(v,suppressEvent){
45592 if (!this.el.dom) {
45595 var old = this.el.dom.value ;
45596 this.el.dom.value = v;
45597 if (suppressEvent) {
45601 // update display..
45602 this.viewEl.select('img',true).each(function(e,i,n) {
45604 var on = e.is(".x-menu-item-checked");
45605 var newv = v.indexOf(String(n)) > -1;
45607 e.toggleClass('x-menu-item-checked');
45613 this.fireEvent('change', this, v, old);
45618 // handle setting of hidden value by some other method!!?!?
45619 setFromHidden: function()
45624 //console.log("SET FROM HIDDEN");
45625 //alert('setFrom hidden');
45626 this.setValue(this.el.dom.value);
45629 onDestroy : function()
45632 Roo.get(this.viewEl).remove();
45635 Roo.form.DayPicker.superclass.onDestroy.call(this);
45639 * RooJS Library 1.1.1
45640 * Copyright(c) 2008-2011 Alan Knowles
45647 * @class Roo.form.ComboCheck
45648 * @extends Roo.form.ComboBox
45649 * A combobox for multiple select items.
45651 * FIXME - could do with a reset button..
45654 * Create a new ComboCheck
45655 * @param {Object} config Configuration options
45657 Roo.form.ComboCheck = function(config){
45658 Roo.form.ComboCheck.superclass.constructor.call(this, config);
45659 // should verify some data...
45661 // hiddenName = required..
45662 // displayField = required
45663 // valudField == required
45664 var req= [ 'hiddenName', 'displayField', 'valueField' ];
45666 Roo.each(req, function(e) {
45667 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
45668 throw "Roo.form.ComboCheck : missing value for: " + e;
45675 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
45680 selectedClass: 'x-menu-item-checked',
45683 onRender : function(ct, position){
45689 var cls = 'x-combo-list';
45692 this.tpl = new Roo.Template({
45693 html : '<div class="'+cls+'-item x-menu-check-item">' +
45694 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
45695 '<span>{' + this.displayField + '}</span>' +
45702 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
45703 this.view.singleSelect = false;
45704 this.view.multiSelect = true;
45705 this.view.toggleSelect = true;
45706 this.pageTb.add(new Roo.Toolbar.Fill(), {
45709 handler: function()
45716 onViewOver : function(e, t){
45722 onViewClick : function(doFocus,index){
45726 select: function () {
45727 //Roo.log("SELECT CALLED");
45730 selectByValue : function(xv, scrollIntoView){
45731 var ar = this.getValueArray();
45734 Roo.each(ar, function(v) {
45735 if(v === undefined || v === null){
45738 var r = this.findRecord(this.valueField, v);
45740 sels.push(this.store.indexOf(r))
45744 this.view.select(sels);
45750 onSelect : function(record, index){
45751 // Roo.log("onselect Called");
45752 // this is only called by the clear button now..
45753 this.view.clearSelections();
45754 this.setValue('[]');
45755 if (this.value != this.valueBefore) {
45756 this.fireEvent('change', this, this.value, this.valueBefore);
45757 this.valueBefore = this.value;
45760 getValueArray : function()
45765 //Roo.log(this.value);
45766 if (typeof(this.value) == 'undefined') {
45769 var ar = Roo.decode(this.value);
45770 return ar instanceof Array ? ar : []; //?? valid?
45773 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
45778 expand : function ()
45781 Roo.form.ComboCheck.superclass.expand.call(this);
45782 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
45783 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
45788 collapse : function(){
45789 Roo.form.ComboCheck.superclass.collapse.call(this);
45790 var sl = this.view.getSelectedIndexes();
45791 var st = this.store;
45795 Roo.each(sl, function(i) {
45797 nv.push(r.get(this.valueField));
45799 this.setValue(Roo.encode(nv));
45800 if (this.value != this.valueBefore) {
45802 this.fireEvent('change', this, this.value, this.valueBefore);
45803 this.valueBefore = this.value;
45808 setValue : function(v){
45812 var vals = this.getValueArray();
45814 Roo.each(vals, function(k) {
45815 var r = this.findRecord(this.valueField, k);
45817 tv.push(r.data[this.displayField]);
45818 }else if(this.valueNotFoundText !== undefined){
45819 tv.push( this.valueNotFoundText );
45824 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
45825 this.hiddenField.value = v;
45831 * Ext JS Library 1.1.1
45832 * Copyright(c) 2006-2007, Ext JS, LLC.
45834 * Originally Released Under LGPL - original licence link has changed is not relivant.
45837 * <script type="text/javascript">
45841 * @class Roo.form.Signature
45842 * @extends Roo.form.Field
45846 * @param {Object} config Configuration options
45849 Roo.form.Signature = function(config){
45850 Roo.form.Signature.superclass.constructor.call(this, config);
45852 this.addEvents({// not in used??
45855 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
45856 * @param {Roo.form.Signature} combo This combo box
45861 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
45862 * @param {Roo.form.ComboBox} combo This combo box
45863 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
45869 Roo.extend(Roo.form.Signature, Roo.form.Field, {
45871 * @cfg {Object} labels Label to use when rendering a form.
45875 * confirm : "Confirm"
45880 confirm : "Confirm"
45883 * @cfg {Number} width The signature panel width (defaults to 300)
45887 * @cfg {Number} height The signature panel height (defaults to 100)
45891 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
45893 allowBlank : false,
45896 // {Object} signPanel The signature SVG panel element (defaults to {})
45898 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
45899 isMouseDown : false,
45900 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
45901 isConfirmed : false,
45902 // {String} signatureTmp SVG mapping string (defaults to empty string)
45906 defaultAutoCreate : { // modified by initCompnoent..
45912 onRender : function(ct, position){
45914 Roo.form.Signature.superclass.onRender.call(this, ct, position);
45916 this.wrap = this.el.wrap({
45917 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
45920 this.createToolbar(this);
45921 this.signPanel = this.wrap.createChild({
45923 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
45927 this.svgID = Roo.id();
45928 this.svgEl = this.signPanel.createChild({
45929 xmlns : 'http://www.w3.org/2000/svg',
45931 id : this.svgID + "-svg",
45933 height: this.height,
45934 viewBox: '0 0 '+this.width+' '+this.height,
45938 id: this.svgID + "-svg-r",
45940 height: this.height,
45945 id: this.svgID + "-svg-l",
45947 y1: (this.height*0.8), // start set the line in 80% of height
45948 x2: this.width, // end
45949 y2: (this.height*0.8), // end set the line in 80% of height
45951 'stroke-width': "1",
45952 'stroke-dasharray': "3",
45953 'shape-rendering': "crispEdges",
45954 'pointer-events': "none"
45958 id: this.svgID + "-svg-p",
45960 'stroke-width': "3",
45962 'pointer-events': 'none'
45967 this.svgBox = this.svgEl.dom.getScreenCTM();
45969 createSVG : function(){
45970 var svg = this.signPanel;
45971 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
45974 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
45975 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
45976 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
45977 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
45978 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
45979 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
45980 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
45983 isTouchEvent : function(e){
45984 return e.type.match(/^touch/);
45986 getCoords : function (e) {
45987 var pt = this.svgEl.dom.createSVGPoint();
45990 if (this.isTouchEvent(e)) {
45991 pt.x = e.targetTouches[0].clientX
45992 pt.y = e.targetTouches[0].clientY;
45994 var a = this.svgEl.dom.getScreenCTM();
45995 var b = a.inverse();
45996 var mx = pt.matrixTransform(b);
45997 return mx.x + ',' + mx.y;
45999 //mouse event headler
46000 down : function (e) {
46001 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
46002 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
46004 this.isMouseDown = true;
46006 e.preventDefault();
46008 move : function (e) {
46009 if (this.isMouseDown) {
46010 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
46011 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
46014 e.preventDefault();
46016 up : function (e) {
46017 this.isMouseDown = false;
46018 var sp = this.signatureTmp.split(' ');
46021 if(!sp[sp.length-2].match(/^L/)){
46025 this.signatureTmp = sp.join(" ");
46028 if(this.getValue() != this.signatureTmp){
46029 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46030 this.isConfirmed = false;
46032 e.preventDefault();
46036 * Protected method that will not generally be called directly. It
46037 * is called when the editor creates its toolbar. Override this method if you need to
46038 * add custom toolbar buttons.
46039 * @param {HtmlEditor} editor
46041 createToolbar : function(editor){
46042 function btn(id, toggle, handler){
46043 var xid = fid + '-'+ id ;
46047 cls : 'x-btn-icon x-edit-'+id,
46048 enableToggle:toggle !== false,
46049 scope: editor, // was editor...
46050 handler:handler||editor.relayBtnCmd,
46051 clickEvent:'mousedown',
46052 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46058 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46062 cls : ' x-signature-btn x-signature-'+id,
46063 scope: editor, // was editor...
46064 handler: this.reset,
46065 clickEvent:'mousedown',
46066 text: this.labels.clear
46073 cls : ' x-signature-btn x-signature-'+id,
46074 scope: editor, // was editor...
46075 handler: this.confirmHandler,
46076 clickEvent:'mousedown',
46077 text: this.labels.confirm
46084 * when user is clicked confirm then show this image.....
46086 * @return {String} Image Data URI
46088 getImageDataURI : function(){
46089 var svg = this.svgEl.dom.parentNode.innerHTML;
46090 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
46095 * @return {Boolean} this.isConfirmed
46097 getConfirmed : function(){
46098 return this.isConfirmed;
46102 * @return {Number} this.width
46104 getWidth : function(){
46109 * @return {Number} this.height
46111 getHeight : function(){
46112 return this.height;
46115 getSignature : function(){
46116 return this.signatureTmp;
46119 reset : function(){
46120 this.signatureTmp = '';
46121 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46122 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
46123 this.isConfirmed = false;
46124 Roo.form.Signature.superclass.reset.call(this);
46126 setSignature : function(s){
46127 this.signatureTmp = s;
46128 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46129 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
46131 this.isConfirmed = false;
46132 Roo.form.Signature.superclass.reset.call(this);
46135 // Roo.log(this.signPanel.dom.contentWindow.up())
46138 setConfirmed : function(){
46142 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
46145 confirmHandler : function(){
46146 if(!this.getSignature()){
46150 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
46151 this.setValue(this.getSignature());
46152 this.isConfirmed = true;
46154 this.fireEvent('confirm', this);
46157 // Subclasses should provide the validation implementation by overriding this
46158 validateValue : function(value){
46159 if(this.allowBlank){
46163 if(this.isConfirmed){
46168 });//<script type="text/javasscript">
46172 * @class Roo.DDView
46173 * A DnD enabled version of Roo.View.
46174 * @param {Element/String} container The Element in which to create the View.
46175 * @param {String} tpl The template string used to create the markup for each element of the View
46176 * @param {Object} config The configuration properties. These include all the config options of
46177 * {@link Roo.View} plus some specific to this class.<br>
46179 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
46180 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
46182 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
46183 .x-view-drag-insert-above {
46184 border-top:1px dotted #3366cc;
46186 .x-view-drag-insert-below {
46187 border-bottom:1px dotted #3366cc;
46193 Roo.DDView = function(container, tpl, config) {
46194 Roo.DDView.superclass.constructor.apply(this, arguments);
46195 this.getEl().setStyle("outline", "0px none");
46196 this.getEl().unselectable();
46197 if (this.dragGroup) {
46198 this.setDraggable(this.dragGroup.split(","));
46200 if (this.dropGroup) {
46201 this.setDroppable(this.dropGroup.split(","));
46203 if (this.deletable) {
46204 this.setDeletable();
46206 this.isDirtyFlag = false;
46212 Roo.extend(Roo.DDView, Roo.View, {
46213 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
46214 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
46215 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
46216 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
46220 reset: Roo.emptyFn,
46222 clearInvalid: Roo.form.Field.prototype.clearInvalid,
46224 validate: function() {
46228 destroy: function() {
46229 this.purgeListeners();
46230 this.getEl.removeAllListeners();
46231 this.getEl().remove();
46232 if (this.dragZone) {
46233 if (this.dragZone.destroy) {
46234 this.dragZone.destroy();
46237 if (this.dropZone) {
46238 if (this.dropZone.destroy) {
46239 this.dropZone.destroy();
46244 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
46245 getName: function() {
46249 /** Loads the View from a JSON string representing the Records to put into the Store. */
46250 setValue: function(v) {
46252 throw "DDView.setValue(). DDView must be constructed with a valid Store";
46255 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
46256 this.store.proxy = new Roo.data.MemoryProxy(data);
46260 /** @return {String} a parenthesised list of the ids of the Records in the View. */
46261 getValue: function() {
46263 this.store.each(function(rec) {
46264 result += rec.id + ',';
46266 return result.substr(0, result.length - 1) + ')';
46269 getIds: function() {
46270 var i = 0, result = new Array(this.store.getCount());
46271 this.store.each(function(rec) {
46272 result[i++] = rec.id;
46277 isDirty: function() {
46278 return this.isDirtyFlag;
46282 * Part of the Roo.dd.DropZone interface. If no target node is found, the
46283 * whole Element becomes the target, and this causes the drop gesture to append.
46285 getTargetFromEvent : function(e) {
46286 var target = e.getTarget();
46287 while ((target !== null) && (target.parentNode != this.el.dom)) {
46288 target = target.parentNode;
46291 target = this.el.dom.lastChild || this.el.dom;
46297 * Create the drag data which consists of an object which has the property "ddel" as
46298 * the drag proxy element.
46300 getDragData : function(e) {
46301 var target = this.findItemFromChild(e.getTarget());
46303 this.handleSelection(e);
46304 var selNodes = this.getSelectedNodes();
46307 copy: this.copy || (this.allowCopy && e.ctrlKey),
46311 var selectedIndices = this.getSelectedIndexes();
46312 for (var i = 0; i < selectedIndices.length; i++) {
46313 dragData.records.push(this.store.getAt(selectedIndices[i]));
46315 if (selNodes.length == 1) {
46316 dragData.ddel = target.cloneNode(true); // the div element
46318 var div = document.createElement('div'); // create the multi element drag "ghost"
46319 div.className = 'multi-proxy';
46320 for (var i = 0, len = selNodes.length; i < len; i++) {
46321 div.appendChild(selNodes[i].cloneNode(true));
46323 dragData.ddel = div;
46325 //console.log(dragData)
46326 //console.log(dragData.ddel.innerHTML)
46329 //console.log('nodragData')
46333 /** Specify to which ddGroup items in this DDView may be dragged. */
46334 setDraggable: function(ddGroup) {
46335 if (ddGroup instanceof Array) {
46336 Roo.each(ddGroup, this.setDraggable, this);
46339 if (this.dragZone) {
46340 this.dragZone.addToGroup(ddGroup);
46342 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
46343 containerScroll: true,
46347 // Draggability implies selection. DragZone's mousedown selects the element.
46348 if (!this.multiSelect) { this.singleSelect = true; }
46350 // Wire the DragZone's handlers up to methods in *this*
46351 this.dragZone.getDragData = this.getDragData.createDelegate(this);
46355 /** Specify from which ddGroup this DDView accepts drops. */
46356 setDroppable: function(ddGroup) {
46357 if (ddGroup instanceof Array) {
46358 Roo.each(ddGroup, this.setDroppable, this);
46361 if (this.dropZone) {
46362 this.dropZone.addToGroup(ddGroup);
46364 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
46365 containerScroll: true,
46369 // Wire the DropZone's handlers up to methods in *this*
46370 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
46371 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
46372 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
46373 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
46374 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
46378 /** Decide whether to drop above or below a View node. */
46379 getDropPoint : function(e, n, dd){
46380 if (n == this.el.dom) { return "above"; }
46381 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
46382 var c = t + (b - t) / 2;
46383 var y = Roo.lib.Event.getPageY(e);
46391 onNodeEnter : function(n, dd, e, data){
46395 onNodeOver : function(n, dd, e, data){
46396 var pt = this.getDropPoint(e, n, dd);
46397 // set the insert point style on the target node
46398 var dragElClass = this.dropNotAllowed;
46401 if (pt == "above"){
46402 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
46403 targetElClass = "x-view-drag-insert-above";
46405 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
46406 targetElClass = "x-view-drag-insert-below";
46408 if (this.lastInsertClass != targetElClass){
46409 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
46410 this.lastInsertClass = targetElClass;
46413 return dragElClass;
46416 onNodeOut : function(n, dd, e, data){
46417 this.removeDropIndicators(n);
46420 onNodeDrop : function(n, dd, e, data){
46421 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
46424 var pt = this.getDropPoint(e, n, dd);
46425 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
46426 if (pt == "below") { insertAt++; }
46427 for (var i = 0; i < data.records.length; i++) {
46428 var r = data.records[i];
46429 var dup = this.store.getById(r.id);
46430 if (dup && (dd != this.dragZone)) {
46431 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
46434 this.store.insert(insertAt++, r.copy());
46436 data.source.isDirtyFlag = true;
46438 this.store.insert(insertAt++, r);
46440 this.isDirtyFlag = true;
46443 this.dragZone.cachedTarget = null;
46447 removeDropIndicators : function(n){
46449 Roo.fly(n).removeClass([
46450 "x-view-drag-insert-above",
46451 "x-view-drag-insert-below"]);
46452 this.lastInsertClass = "_noclass";
46457 * Utility method. Add a delete option to the DDView's context menu.
46458 * @param {String} imageUrl The URL of the "delete" icon image.
46460 setDeletable: function(imageUrl) {
46461 if (!this.singleSelect && !this.multiSelect) {
46462 this.singleSelect = true;
46464 var c = this.getContextMenu();
46465 this.contextMenu.on("itemclick", function(item) {
46468 this.remove(this.getSelectedIndexes());
46472 this.contextMenu.add({
46479 /** Return the context menu for this DDView. */
46480 getContextMenu: function() {
46481 if (!this.contextMenu) {
46482 // Create the View's context menu
46483 this.contextMenu = new Roo.menu.Menu({
46484 id: this.id + "-contextmenu"
46486 this.el.on("contextmenu", this.showContextMenu, this);
46488 return this.contextMenu;
46491 disableContextMenu: function() {
46492 if (this.contextMenu) {
46493 this.el.un("contextmenu", this.showContextMenu, this);
46497 showContextMenu: function(e, item) {
46498 item = this.findItemFromChild(e.getTarget());
46501 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
46502 this.contextMenu.showAt(e.getXY());
46507 * Remove {@link Roo.data.Record}s at the specified indices.
46508 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
46510 remove: function(selectedIndices) {
46511 selectedIndices = [].concat(selectedIndices);
46512 for (var i = 0; i < selectedIndices.length; i++) {
46513 var rec = this.store.getAt(selectedIndices[i]);
46514 this.store.remove(rec);
46519 * Double click fires the event, but also, if this is draggable, and there is only one other
46520 * related DropZone, it transfers the selected node.
46522 onDblClick : function(e){
46523 var item = this.findItemFromChild(e.getTarget());
46525 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
46528 if (this.dragGroup) {
46529 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
46530 while (targets.indexOf(this.dropZone) > -1) {
46531 targets.remove(this.dropZone);
46533 if (targets.length == 1) {
46534 this.dragZone.cachedTarget = null;
46535 var el = Roo.get(targets[0].getEl());
46536 var box = el.getBox(true);
46537 targets[0].onNodeDrop(el.dom, {
46539 xy: [box.x, box.y + box.height - 1]
46540 }, null, this.getDragData(e));
46546 handleSelection: function(e) {
46547 this.dragZone.cachedTarget = null;
46548 var item = this.findItemFromChild(e.getTarget());
46550 this.clearSelections(true);
46553 if (item && (this.multiSelect || this.singleSelect)){
46554 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
46555 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
46556 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
46557 this.unselect(item);
46559 this.select(item, this.multiSelect && e.ctrlKey);
46560 this.lastSelection = item;
46565 onItemClick : function(item, index, e){
46566 if(this.fireEvent("beforeclick", this, index, item, e) === false){
46572 unselect : function(nodeInfo, suppressEvent){
46573 var node = this.getNode(nodeInfo);
46574 if(node && this.isSelected(node)){
46575 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
46576 Roo.fly(node).removeClass(this.selectedClass);
46577 this.selections.remove(node);
46578 if(!suppressEvent){
46579 this.fireEvent("selectionchange", this, this.selections);
46587 * Ext JS Library 1.1.1
46588 * Copyright(c) 2006-2007, Ext JS, LLC.
46590 * Originally Released Under LGPL - original licence link has changed is not relivant.
46593 * <script type="text/javascript">
46597 * @class Roo.LayoutManager
46598 * @extends Roo.util.Observable
46599 * Base class for layout managers.
46601 Roo.LayoutManager = function(container, config){
46602 Roo.LayoutManager.superclass.constructor.call(this);
46603 this.el = Roo.get(container);
46604 // ie scrollbar fix
46605 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
46606 document.body.scroll = "no";
46607 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
46608 this.el.position('relative');
46610 this.id = this.el.id;
46611 this.el.addClass("x-layout-container");
46612 /** false to disable window resize monitoring @type Boolean */
46613 this.monitorWindowResize = true;
46618 * Fires when a layout is performed.
46619 * @param {Roo.LayoutManager} this
46623 * @event regionresized
46624 * Fires when the user resizes a region.
46625 * @param {Roo.LayoutRegion} region The resized region
46626 * @param {Number} newSize The new size (width for east/west, height for north/south)
46628 "regionresized" : true,
46630 * @event regioncollapsed
46631 * Fires when a region is collapsed.
46632 * @param {Roo.LayoutRegion} region The collapsed region
46634 "regioncollapsed" : true,
46636 * @event regionexpanded
46637 * Fires when a region is expanded.
46638 * @param {Roo.LayoutRegion} region The expanded region
46640 "regionexpanded" : true
46642 this.updating = false;
46643 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
46646 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
46648 * Returns true if this layout is currently being updated
46649 * @return {Boolean}
46651 isUpdating : function(){
46652 return this.updating;
46656 * Suspend the LayoutManager from doing auto-layouts while
46657 * making multiple add or remove calls
46659 beginUpdate : function(){
46660 this.updating = true;
46664 * Restore auto-layouts and optionally disable the manager from performing a layout
46665 * @param {Boolean} noLayout true to disable a layout update
46667 endUpdate : function(noLayout){
46668 this.updating = false;
46674 layout: function(){
46678 onRegionResized : function(region, newSize){
46679 this.fireEvent("regionresized", region, newSize);
46683 onRegionCollapsed : function(region){
46684 this.fireEvent("regioncollapsed", region);
46687 onRegionExpanded : function(region){
46688 this.fireEvent("regionexpanded", region);
46692 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
46693 * performs box-model adjustments.
46694 * @return {Object} The size as an object {width: (the width), height: (the height)}
46696 getViewSize : function(){
46698 if(this.el.dom != document.body){
46699 size = this.el.getSize();
46701 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
46703 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
46704 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
46709 * Returns the Element this layout is bound to.
46710 * @return {Roo.Element}
46712 getEl : function(){
46717 * Returns the specified region.
46718 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
46719 * @return {Roo.LayoutRegion}
46721 getRegion : function(target){
46722 return this.regions[target.toLowerCase()];
46725 onWindowResize : function(){
46726 if(this.monitorWindowResize){
46732 * Ext JS Library 1.1.1
46733 * Copyright(c) 2006-2007, Ext JS, LLC.
46735 * Originally Released Under LGPL - original licence link has changed is not relivant.
46738 * <script type="text/javascript">
46741 * @class Roo.BorderLayout
46742 * @extends Roo.LayoutManager
46743 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
46744 * please see: <br><br>
46745 * <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>
46746 * <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>
46749 var layout = new Roo.BorderLayout(document.body, {
46783 preferredTabWidth: 150
46788 var CP = Roo.ContentPanel;
46790 layout.beginUpdate();
46791 layout.add("north", new CP("north", "North"));
46792 layout.add("south", new CP("south", {title: "South", closable: true}));
46793 layout.add("west", new CP("west", {title: "West"}));
46794 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
46795 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
46796 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
46797 layout.getRegion("center").showPanel("center1");
46798 layout.endUpdate();
46801 <b>The container the layout is rendered into can be either the body element or any other element.
46802 If it is not the body element, the container needs to either be an absolute positioned element,
46803 or you will need to add "position:relative" to the css of the container. You will also need to specify
46804 the container size if it is not the body element.</b>
46807 * Create a new BorderLayout
46808 * @param {String/HTMLElement/Element} container The container this layout is bound to
46809 * @param {Object} config Configuration options
46811 Roo.BorderLayout = function(container, config){
46812 config = config || {};
46813 Roo.BorderLayout.superclass.constructor.call(this, container, config);
46814 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
46815 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
46816 var target = this.factory.validRegions[i];
46817 if(config[target]){
46818 this.addRegion(target, config[target]);
46823 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
46825 * Creates and adds a new region if it doesn't already exist.
46826 * @param {String} target The target region key (north, south, east, west or center).
46827 * @param {Object} config The regions config object
46828 * @return {BorderLayoutRegion} The new region
46830 addRegion : function(target, config){
46831 if(!this.regions[target]){
46832 var r = this.factory.create(target, this, config);
46833 this.bindRegion(target, r);
46835 return this.regions[target];
46839 bindRegion : function(name, r){
46840 this.regions[name] = r;
46841 r.on("visibilitychange", this.layout, this);
46842 r.on("paneladded", this.layout, this);
46843 r.on("panelremoved", this.layout, this);
46844 r.on("invalidated", this.layout, this);
46845 r.on("resized", this.onRegionResized, this);
46846 r.on("collapsed", this.onRegionCollapsed, this);
46847 r.on("expanded", this.onRegionExpanded, this);
46851 * Performs a layout update.
46853 layout : function(){
46854 if(this.updating) return;
46855 var size = this.getViewSize();
46856 var w = size.width;
46857 var h = size.height;
46862 //var x = 0, y = 0;
46864 var rs = this.regions;
46865 var north = rs["north"];
46866 var south = rs["south"];
46867 var west = rs["west"];
46868 var east = rs["east"];
46869 var center = rs["center"];
46870 //if(this.hideOnLayout){ // not supported anymore
46871 //c.el.setStyle("display", "none");
46873 if(north && north.isVisible()){
46874 var b = north.getBox();
46875 var m = north.getMargins();
46876 b.width = w - (m.left+m.right);
46879 centerY = b.height + b.y + m.bottom;
46880 centerH -= centerY;
46881 north.updateBox(this.safeBox(b));
46883 if(south && south.isVisible()){
46884 var b = south.getBox();
46885 var m = south.getMargins();
46886 b.width = w - (m.left+m.right);
46888 var totalHeight = (b.height + m.top + m.bottom);
46889 b.y = h - totalHeight + m.top;
46890 centerH -= totalHeight;
46891 south.updateBox(this.safeBox(b));
46893 if(west && west.isVisible()){
46894 var b = west.getBox();
46895 var m = west.getMargins();
46896 b.height = centerH - (m.top+m.bottom);
46898 b.y = centerY + m.top;
46899 var totalWidth = (b.width + m.left + m.right);
46900 centerX += totalWidth;
46901 centerW -= totalWidth;
46902 west.updateBox(this.safeBox(b));
46904 if(east && east.isVisible()){
46905 var b = east.getBox();
46906 var m = east.getMargins();
46907 b.height = centerH - (m.top+m.bottom);
46908 var totalWidth = (b.width + m.left + m.right);
46909 b.x = w - totalWidth + m.left;
46910 b.y = centerY + m.top;
46911 centerW -= totalWidth;
46912 east.updateBox(this.safeBox(b));
46915 var m = center.getMargins();
46917 x: centerX + m.left,
46918 y: centerY + m.top,
46919 width: centerW - (m.left+m.right),
46920 height: centerH - (m.top+m.bottom)
46922 //if(this.hideOnLayout){
46923 //center.el.setStyle("display", "block");
46925 center.updateBox(this.safeBox(centerBox));
46928 this.fireEvent("layout", this);
46932 safeBox : function(box){
46933 box.width = Math.max(0, box.width);
46934 box.height = Math.max(0, box.height);
46939 * Adds a ContentPanel (or subclass) to this layout.
46940 * @param {String} target The target region key (north, south, east, west or center).
46941 * @param {Roo.ContentPanel} panel The panel to add
46942 * @return {Roo.ContentPanel} The added panel
46944 add : function(target, panel){
46946 target = target.toLowerCase();
46947 return this.regions[target].add(panel);
46951 * Remove a ContentPanel (or subclass) to this layout.
46952 * @param {String} target The target region key (north, south, east, west or center).
46953 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
46954 * @return {Roo.ContentPanel} The removed panel
46956 remove : function(target, panel){
46957 target = target.toLowerCase();
46958 return this.regions[target].remove(panel);
46962 * Searches all regions for a panel with the specified id
46963 * @param {String} panelId
46964 * @return {Roo.ContentPanel} The panel or null if it wasn't found
46966 findPanel : function(panelId){
46967 var rs = this.regions;
46968 for(var target in rs){
46969 if(typeof rs[target] != "function"){
46970 var p = rs[target].getPanel(panelId);
46980 * Searches all regions for a panel with the specified id and activates (shows) it.
46981 * @param {String/ContentPanel} panelId The panels id or the panel itself
46982 * @return {Roo.ContentPanel} The shown panel or null
46984 showPanel : function(panelId) {
46985 var rs = this.regions;
46986 for(var target in rs){
46987 var r = rs[target];
46988 if(typeof r != "function"){
46989 if(r.hasPanel(panelId)){
46990 return r.showPanel(panelId);
46998 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
46999 * @param {Roo.state.Provider} provider (optional) An alternate state provider
47001 restoreState : function(provider){
47003 provider = Roo.state.Manager;
47005 var sm = new Roo.LayoutStateManager();
47006 sm.init(this, provider);
47010 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
47011 * object should contain properties for each region to add ContentPanels to, and each property's value should be
47012 * a valid ContentPanel config object. Example:
47014 // Create the main layout
47015 var layout = new Roo.BorderLayout('main-ct', {
47026 // Create and add multiple ContentPanels at once via configs
47029 id: 'source-files',
47031 title:'Ext Source Files',
47044 * @param {Object} regions An object containing ContentPanel configs by region name
47046 batchAdd : function(regions){
47047 this.beginUpdate();
47048 for(var rname in regions){
47049 var lr = this.regions[rname];
47051 this.addTypedPanels(lr, regions[rname]);
47058 addTypedPanels : function(lr, ps){
47059 if(typeof ps == 'string'){
47060 lr.add(new Roo.ContentPanel(ps));
47062 else if(ps instanceof Array){
47063 for(var i =0, len = ps.length; i < len; i++){
47064 this.addTypedPanels(lr, ps[i]);
47067 else if(!ps.events){ // raw config?
47069 delete ps.el; // prevent conflict
47070 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
47072 else { // panel object assumed!
47077 * Adds a xtype elements to the layout.
47081 xtype : 'ContentPanel',
47088 xtype : 'NestedLayoutPanel',
47094 items : [ ... list of content panels or nested layout panels.. ]
47098 * @param {Object} cfg Xtype definition of item to add.
47100 addxtype : function(cfg)
47102 // basically accepts a pannel...
47103 // can accept a layout region..!?!?
47104 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
47106 if (!cfg.xtype.match(/Panel$/)) {
47111 if (typeof(cfg.region) == 'undefined') {
47112 Roo.log("Failed to add Panel, region was not set");
47116 var region = cfg.region;
47122 xitems = cfg.items;
47129 case 'ContentPanel': // ContentPanel (el, cfg)
47130 case 'ScrollPanel': // ContentPanel (el, cfg)
47132 if(cfg.autoCreate) {
47133 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47135 var el = this.el.createChild();
47136 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
47139 this.add(region, ret);
47143 case 'TreePanel': // our new panel!
47144 cfg.el = this.el.createChild();
47145 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
47146 this.add(region, ret);
47149 case 'NestedLayoutPanel':
47150 // create a new Layout (which is a Border Layout...
47151 var el = this.el.createChild();
47152 var clayout = cfg.layout;
47154 clayout.items = clayout.items || [];
47155 // replace this exitems with the clayout ones..
47156 xitems = clayout.items;
47159 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
47160 cfg.background = false;
47162 var layout = new Roo.BorderLayout(el, clayout);
47164 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
47165 //console.log('adding nested layout panel ' + cfg.toSource());
47166 this.add(region, ret);
47167 nb = {}; /// find first...
47172 // needs grid and region
47174 //var el = this.getRegion(region).el.createChild();
47175 var el = this.el.createChild();
47176 // create the grid first...
47178 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
47180 if (region == 'center' && this.active ) {
47181 cfg.background = false;
47183 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
47185 this.add(region, ret);
47186 if (cfg.background) {
47187 ret.on('activate', function(gp) {
47188 if (!gp.grid.rendered) {
47203 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
47205 // GridPanel (grid, cfg)
47208 this.beginUpdate();
47212 Roo.each(xitems, function(i) {
47213 region = nb && i.region ? i.region : false;
47215 var add = ret.addxtype(i);
47218 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
47219 if (!i.background) {
47220 abn[region] = nb[region] ;
47227 // make the last non-background panel active..
47228 //if (nb) { Roo.log(abn); }
47231 for(var r in abn) {
47232 region = this.getRegion(r);
47234 // tried using nb[r], but it does not work..
47236 region.showPanel(abn[r]);
47247 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
47248 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
47249 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
47250 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
47253 var CP = Roo.ContentPanel;
47255 var layout = Roo.BorderLayout.create({
47259 panels: [new CP("north", "North")]
47268 panels: [new CP("west", {title: "West"})]
47277 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
47286 panels: [new CP("south", {title: "South", closable: true})]
47293 preferredTabWidth: 150,
47295 new CP("center1", {title: "Close Me", closable: true}),
47296 new CP("center2", {title: "Center Panel", closable: false})
47301 layout.getRegion("center").showPanel("center1");
47306 Roo.BorderLayout.create = function(config, targetEl){
47307 var layout = new Roo.BorderLayout(targetEl || document.body, config);
47308 layout.beginUpdate();
47309 var regions = Roo.BorderLayout.RegionFactory.validRegions;
47310 for(var j = 0, jlen = regions.length; j < jlen; j++){
47311 var lr = regions[j];
47312 if(layout.regions[lr] && config[lr].panels){
47313 var r = layout.regions[lr];
47314 var ps = config[lr].panels;
47315 layout.addTypedPanels(r, ps);
47318 layout.endUpdate();
47323 Roo.BorderLayout.RegionFactory = {
47325 validRegions : ["north","south","east","west","center"],
47328 create : function(target, mgr, config){
47329 target = target.toLowerCase();
47330 if(config.lightweight || config.basic){
47331 return new Roo.BasicLayoutRegion(mgr, config, target);
47335 return new Roo.NorthLayoutRegion(mgr, config);
47337 return new Roo.SouthLayoutRegion(mgr, config);
47339 return new Roo.EastLayoutRegion(mgr, config);
47341 return new Roo.WestLayoutRegion(mgr, config);
47343 return new Roo.CenterLayoutRegion(mgr, config);
47345 throw 'Layout region "'+target+'" not supported.';
47349 * Ext JS Library 1.1.1
47350 * Copyright(c) 2006-2007, Ext JS, LLC.
47352 * Originally Released Under LGPL - original licence link has changed is not relivant.
47355 * <script type="text/javascript">
47359 * @class Roo.BasicLayoutRegion
47360 * @extends Roo.util.Observable
47361 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
47362 * and does not have a titlebar, tabs or any other features. All it does is size and position
47363 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
47365 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
47367 this.position = pos;
47370 * @scope Roo.BasicLayoutRegion
47374 * @event beforeremove
47375 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
47376 * @param {Roo.LayoutRegion} this
47377 * @param {Roo.ContentPanel} panel The panel
47378 * @param {Object} e The cancel event object
47380 "beforeremove" : true,
47382 * @event invalidated
47383 * Fires when the layout for this region is changed.
47384 * @param {Roo.LayoutRegion} this
47386 "invalidated" : true,
47388 * @event visibilitychange
47389 * Fires when this region is shown or hidden
47390 * @param {Roo.LayoutRegion} this
47391 * @param {Boolean} visibility true or false
47393 "visibilitychange" : true,
47395 * @event paneladded
47396 * Fires when a panel is added.
47397 * @param {Roo.LayoutRegion} this
47398 * @param {Roo.ContentPanel} panel The panel
47400 "paneladded" : true,
47402 * @event panelremoved
47403 * Fires when a panel is removed.
47404 * @param {Roo.LayoutRegion} this
47405 * @param {Roo.ContentPanel} panel The panel
47407 "panelremoved" : true,
47410 * Fires when this region is collapsed.
47411 * @param {Roo.LayoutRegion} this
47413 "collapsed" : true,
47416 * Fires when this region is expanded.
47417 * @param {Roo.LayoutRegion} this
47422 * Fires when this region is slid into view.
47423 * @param {Roo.LayoutRegion} this
47425 "slideshow" : true,
47428 * Fires when this region slides out of view.
47429 * @param {Roo.LayoutRegion} this
47431 "slidehide" : true,
47433 * @event panelactivated
47434 * Fires when a panel is activated.
47435 * @param {Roo.LayoutRegion} this
47436 * @param {Roo.ContentPanel} panel The activated panel
47438 "panelactivated" : true,
47441 * Fires when the user resizes this region.
47442 * @param {Roo.LayoutRegion} this
47443 * @param {Number} newSize The new size (width for east/west, height for north/south)
47447 /** A collection of panels in this region. @type Roo.util.MixedCollection */
47448 this.panels = new Roo.util.MixedCollection();
47449 this.panels.getKey = this.getPanelId.createDelegate(this);
47451 this.activePanel = null;
47452 // ensure listeners are added...
47454 if (config.listeners || config.events) {
47455 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
47456 listeners : config.listeners || {},
47457 events : config.events || {}
47461 if(skipConfig !== true){
47462 this.applyConfig(config);
47466 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
47467 getPanelId : function(p){
47471 applyConfig : function(config){
47472 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
47473 this.config = config;
47478 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
47479 * the width, for horizontal (north, south) the height.
47480 * @param {Number} newSize The new width or height
47482 resizeTo : function(newSize){
47483 var el = this.el ? this.el :
47484 (this.activePanel ? this.activePanel.getEl() : null);
47486 switch(this.position){
47489 el.setWidth(newSize);
47490 this.fireEvent("resized", this, newSize);
47494 el.setHeight(newSize);
47495 this.fireEvent("resized", this, newSize);
47501 getBox : function(){
47502 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
47505 getMargins : function(){
47506 return this.margins;
47509 updateBox : function(box){
47511 var el = this.activePanel.getEl();
47512 el.dom.style.left = box.x + "px";
47513 el.dom.style.top = box.y + "px";
47514 this.activePanel.setSize(box.width, box.height);
47518 * Returns the container element for this region.
47519 * @return {Roo.Element}
47521 getEl : function(){
47522 return this.activePanel;
47526 * Returns true if this region is currently visible.
47527 * @return {Boolean}
47529 isVisible : function(){
47530 return this.activePanel ? true : false;
47533 setActivePanel : function(panel){
47534 panel = this.getPanel(panel);
47535 if(this.activePanel && this.activePanel != panel){
47536 this.activePanel.setActiveState(false);
47537 this.activePanel.getEl().setLeftTop(-10000,-10000);
47539 this.activePanel = panel;
47540 panel.setActiveState(true);
47542 panel.setSize(this.box.width, this.box.height);
47544 this.fireEvent("panelactivated", this, panel);
47545 this.fireEvent("invalidated");
47549 * Show the specified panel.
47550 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
47551 * @return {Roo.ContentPanel} The shown panel or null
47553 showPanel : function(panel){
47554 if(panel = this.getPanel(panel)){
47555 this.setActivePanel(panel);
47561 * Get the active panel for this region.
47562 * @return {Roo.ContentPanel} The active panel or null
47564 getActivePanel : function(){
47565 return this.activePanel;
47569 * Add the passed ContentPanel(s)
47570 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
47571 * @return {Roo.ContentPanel} The panel added (if only one was added)
47573 add : function(panel){
47574 if(arguments.length > 1){
47575 for(var i = 0, len = arguments.length; i < len; i++) {
47576 this.add(arguments[i]);
47580 if(this.hasPanel(panel)){
47581 this.showPanel(panel);
47584 var el = panel.getEl();
47585 if(el.dom.parentNode != this.mgr.el.dom){
47586 this.mgr.el.dom.appendChild(el.dom);
47588 if(panel.setRegion){
47589 panel.setRegion(this);
47591 this.panels.add(panel);
47592 el.setStyle("position", "absolute");
47593 if(!panel.background){
47594 this.setActivePanel(panel);
47595 if(this.config.initialSize && this.panels.getCount()==1){
47596 this.resizeTo(this.config.initialSize);
47599 this.fireEvent("paneladded", this, panel);
47604 * Returns true if the panel is in this region.
47605 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47606 * @return {Boolean}
47608 hasPanel : function(panel){
47609 if(typeof panel == "object"){ // must be panel obj
47610 panel = panel.getId();
47612 return this.getPanel(panel) ? true : false;
47616 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
47617 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47618 * @param {Boolean} preservePanel Overrides the config preservePanel option
47619 * @return {Roo.ContentPanel} The panel that was removed
47621 remove : function(panel, preservePanel){
47622 panel = this.getPanel(panel);
47627 this.fireEvent("beforeremove", this, panel, e);
47628 if(e.cancel === true){
47631 var panelId = panel.getId();
47632 this.panels.removeKey(panelId);
47637 * Returns the panel specified or null if it's not in this region.
47638 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
47639 * @return {Roo.ContentPanel}
47641 getPanel : function(id){
47642 if(typeof id == "object"){ // must be panel obj
47645 return this.panels.get(id);
47649 * Returns this regions position (north/south/east/west/center).
47652 getPosition: function(){
47653 return this.position;
47657 * Ext JS Library 1.1.1
47658 * Copyright(c) 2006-2007, Ext JS, LLC.
47660 * Originally Released Under LGPL - original licence link has changed is not relivant.
47663 * <script type="text/javascript">
47667 * @class Roo.LayoutRegion
47668 * @extends Roo.BasicLayoutRegion
47669 * This class represents a region in a layout manager.
47670 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
47671 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
47672 * @cfg {Boolean} floatable False to disable floating (defaults to true)
47673 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
47674 * @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})
47675 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
47676 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
47677 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
47678 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
47679 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
47680 * @cfg {String} title The title for the region (overrides panel titles)
47681 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
47682 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
47683 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
47684 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
47685 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
47686 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
47687 * the space available, similar to FireFox 1.5 tabs (defaults to false)
47688 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
47689 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
47690 * @cfg {Boolean} showPin True to show a pin button
47691 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
47692 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
47693 * @cfg {Boolean} disableTabTips True to disable tab tooltips
47694 * @cfg {Number} width For East/West panels
47695 * @cfg {Number} height For North/South panels
47696 * @cfg {Boolean} split To show the splitter
47697 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
47699 Roo.LayoutRegion = function(mgr, config, pos){
47700 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
47701 var dh = Roo.DomHelper;
47702 /** This region's container element
47703 * @type Roo.Element */
47704 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
47705 /** This region's title element
47706 * @type Roo.Element */
47708 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
47709 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
47710 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
47712 this.titleEl.enableDisplayMode();
47713 /** This region's title text element
47714 * @type HTMLElement */
47715 this.titleTextEl = this.titleEl.dom.firstChild;
47716 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
47717 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
47718 this.closeBtn.enableDisplayMode();
47719 this.closeBtn.on("click", this.closeClicked, this);
47720 this.closeBtn.hide();
47722 this.createBody(config);
47723 this.visible = true;
47724 this.collapsed = false;
47726 if(config.hideWhenEmpty){
47728 this.on("paneladded", this.validateVisibility, this);
47729 this.on("panelremoved", this.validateVisibility, this);
47731 this.applyConfig(config);
47734 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
47736 createBody : function(){
47737 /** This region's body element
47738 * @type Roo.Element */
47739 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
47742 applyConfig : function(c){
47743 if(c.collapsible && this.position != "center" && !this.collapsedEl){
47744 var dh = Roo.DomHelper;
47745 if(c.titlebar !== false){
47746 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
47747 this.collapseBtn.on("click", this.collapse, this);
47748 this.collapseBtn.enableDisplayMode();
47750 if(c.showPin === true || this.showPin){
47751 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
47752 this.stickBtn.enableDisplayMode();
47753 this.stickBtn.on("click", this.expand, this);
47754 this.stickBtn.hide();
47757 /** This region's collapsed element
47758 * @type Roo.Element */
47759 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
47760 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
47762 if(c.floatable !== false){
47763 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
47764 this.collapsedEl.on("click", this.collapseClick, this);
47767 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
47768 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
47769 id: "message", unselectable: "on", style:{"float":"left"}});
47770 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
47772 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
47773 this.expandBtn.on("click", this.expand, this);
47775 if(this.collapseBtn){
47776 this.collapseBtn.setVisible(c.collapsible == true);
47778 this.cmargins = c.cmargins || this.cmargins ||
47779 (this.position == "west" || this.position == "east" ?
47780 {top: 0, left: 2, right:2, bottom: 0} :
47781 {top: 2, left: 0, right:0, bottom: 2});
47782 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
47783 this.bottomTabs = c.tabPosition != "top";
47784 this.autoScroll = c.autoScroll || false;
47785 if(this.autoScroll){
47786 this.bodyEl.setStyle("overflow", "auto");
47788 this.bodyEl.setStyle("overflow", "hidden");
47790 //if(c.titlebar !== false){
47791 if((!c.titlebar && !c.title) || c.titlebar === false){
47792 this.titleEl.hide();
47794 this.titleEl.show();
47796 this.titleTextEl.innerHTML = c.title;
47800 this.duration = c.duration || .30;
47801 this.slideDuration = c.slideDuration || .45;
47804 this.collapse(true);
47811 * Returns true if this region is currently visible.
47812 * @return {Boolean}
47814 isVisible : function(){
47815 return this.visible;
47819 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
47820 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
47822 setCollapsedTitle : function(title){
47823 title = title || " ";
47824 if(this.collapsedTitleTextEl){
47825 this.collapsedTitleTextEl.innerHTML = title;
47829 getBox : function(){
47831 if(!this.collapsed){
47832 b = this.el.getBox(false, true);
47834 b = this.collapsedEl.getBox(false, true);
47839 getMargins : function(){
47840 return this.collapsed ? this.cmargins : this.margins;
47843 highlight : function(){
47844 this.el.addClass("x-layout-panel-dragover");
47847 unhighlight : function(){
47848 this.el.removeClass("x-layout-panel-dragover");
47851 updateBox : function(box){
47853 if(!this.collapsed){
47854 this.el.dom.style.left = box.x + "px";
47855 this.el.dom.style.top = box.y + "px";
47856 this.updateBody(box.width, box.height);
47858 this.collapsedEl.dom.style.left = box.x + "px";
47859 this.collapsedEl.dom.style.top = box.y + "px";
47860 this.collapsedEl.setSize(box.width, box.height);
47863 this.tabs.autoSizeTabs();
47867 updateBody : function(w, h){
47869 this.el.setWidth(w);
47870 w -= this.el.getBorderWidth("rl");
47871 if(this.config.adjustments){
47872 w += this.config.adjustments[0];
47876 this.el.setHeight(h);
47877 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
47878 h -= this.el.getBorderWidth("tb");
47879 if(this.config.adjustments){
47880 h += this.config.adjustments[1];
47882 this.bodyEl.setHeight(h);
47884 h = this.tabs.syncHeight(h);
47887 if(this.panelSize){
47888 w = w !== null ? w : this.panelSize.width;
47889 h = h !== null ? h : this.panelSize.height;
47891 if(this.activePanel){
47892 var el = this.activePanel.getEl();
47893 w = w !== null ? w : el.getWidth();
47894 h = h !== null ? h : el.getHeight();
47895 this.panelSize = {width: w, height: h};
47896 this.activePanel.setSize(w, h);
47898 if(Roo.isIE && this.tabs){
47899 this.tabs.el.repaint();
47904 * Returns the container element for this region.
47905 * @return {Roo.Element}
47907 getEl : function(){
47912 * Hides this region.
47915 if(!this.collapsed){
47916 this.el.dom.style.left = "-2000px";
47919 this.collapsedEl.dom.style.left = "-2000px";
47920 this.collapsedEl.hide();
47922 this.visible = false;
47923 this.fireEvent("visibilitychange", this, false);
47927 * Shows this region if it was previously hidden.
47930 if(!this.collapsed){
47933 this.collapsedEl.show();
47935 this.visible = true;
47936 this.fireEvent("visibilitychange", this, true);
47939 closeClicked : function(){
47940 if(this.activePanel){
47941 this.remove(this.activePanel);
47945 collapseClick : function(e){
47947 e.stopPropagation();
47950 e.stopPropagation();
47956 * Collapses this region.
47957 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
47959 collapse : function(skipAnim){
47960 if(this.collapsed) return;
47961 this.collapsed = true;
47963 this.split.el.hide();
47965 if(this.config.animate && skipAnim !== true){
47966 this.fireEvent("invalidated", this);
47967 this.animateCollapse();
47969 this.el.setLocation(-20000,-20000);
47971 this.collapsedEl.show();
47972 this.fireEvent("collapsed", this);
47973 this.fireEvent("invalidated", this);
47977 animateCollapse : function(){
47982 * Expands this region if it was previously collapsed.
47983 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
47984 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
47986 expand : function(e, skipAnim){
47987 if(e) e.stopPropagation();
47988 if(!this.collapsed || this.el.hasActiveFx()) return;
47990 this.afterSlideIn();
47993 this.collapsed = false;
47994 if(this.config.animate && skipAnim !== true){
47995 this.animateExpand();
47999 this.split.el.show();
48001 this.collapsedEl.setLocation(-2000,-2000);
48002 this.collapsedEl.hide();
48003 this.fireEvent("invalidated", this);
48004 this.fireEvent("expanded", this);
48008 animateExpand : function(){
48012 initTabs : function()
48014 this.bodyEl.setStyle("overflow", "hidden");
48015 var ts = new Roo.TabPanel(
48018 tabPosition: this.bottomTabs ? 'bottom' : 'top',
48019 disableTooltips: this.config.disableTabTips,
48020 toolbar : this.config.toolbar
48023 if(this.config.hideTabs){
48024 ts.stripWrap.setDisplayed(false);
48027 ts.resizeTabs = this.config.resizeTabs === true;
48028 ts.minTabWidth = this.config.minTabWidth || 40;
48029 ts.maxTabWidth = this.config.maxTabWidth || 250;
48030 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
48031 ts.monitorResize = false;
48032 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48033 ts.bodyEl.addClass('x-layout-tabs-body');
48034 this.panels.each(this.initPanelAsTab, this);
48037 initPanelAsTab : function(panel){
48038 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
48039 this.config.closeOnTab && panel.isClosable());
48040 if(panel.tabTip !== undefined){
48041 ti.setTooltip(panel.tabTip);
48043 ti.on("activate", function(){
48044 this.setActivePanel(panel);
48046 if(this.config.closeOnTab){
48047 ti.on("beforeclose", function(t, e){
48049 this.remove(panel);
48055 updatePanelTitle : function(panel, title){
48056 if(this.activePanel == panel){
48057 this.updateTitle(title);
48060 var ti = this.tabs.getTab(panel.getEl().id);
48062 if(panel.tabTip !== undefined){
48063 ti.setTooltip(panel.tabTip);
48068 updateTitle : function(title){
48069 if(this.titleTextEl && !this.config.title){
48070 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
48074 setActivePanel : function(panel){
48075 panel = this.getPanel(panel);
48076 if(this.activePanel && this.activePanel != panel){
48077 this.activePanel.setActiveState(false);
48079 this.activePanel = panel;
48080 panel.setActiveState(true);
48081 if(this.panelSize){
48082 panel.setSize(this.panelSize.width, this.panelSize.height);
48085 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
48087 this.updateTitle(panel.getTitle());
48089 this.fireEvent("invalidated", this);
48091 this.fireEvent("panelactivated", this, panel);
48095 * Shows the specified panel.
48096 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
48097 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
48099 showPanel : function(panel){
48100 if(panel = this.getPanel(panel)){
48102 var tab = this.tabs.getTab(panel.getEl().id);
48103 if(tab.isHidden()){
48104 this.tabs.unhideTab(tab.id);
48108 this.setActivePanel(panel);
48115 * Get the active panel for this region.
48116 * @return {Roo.ContentPanel} The active panel or null
48118 getActivePanel : function(){
48119 return this.activePanel;
48122 validateVisibility : function(){
48123 if(this.panels.getCount() < 1){
48124 this.updateTitle(" ");
48125 this.closeBtn.hide();
48128 if(!this.isVisible()){
48135 * Adds the passed ContentPanel(s) to this region.
48136 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
48137 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
48139 add : function(panel){
48140 if(arguments.length > 1){
48141 for(var i = 0, len = arguments.length; i < len; i++) {
48142 this.add(arguments[i]);
48146 if(this.hasPanel(panel)){
48147 this.showPanel(panel);
48150 panel.setRegion(this);
48151 this.panels.add(panel);
48152 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
48153 this.bodyEl.dom.appendChild(panel.getEl().dom);
48154 if(panel.background !== true){
48155 this.setActivePanel(panel);
48157 this.fireEvent("paneladded", this, panel);
48163 this.initPanelAsTab(panel);
48165 if(panel.background !== true){
48166 this.tabs.activate(panel.getEl().id);
48168 this.fireEvent("paneladded", this, panel);
48173 * Hides the tab for the specified panel.
48174 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48176 hidePanel : function(panel){
48177 if(this.tabs && (panel = this.getPanel(panel))){
48178 this.tabs.hideTab(panel.getEl().id);
48183 * Unhides the tab for a previously hidden panel.
48184 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48186 unhidePanel : function(panel){
48187 if(this.tabs && (panel = this.getPanel(panel))){
48188 this.tabs.unhideTab(panel.getEl().id);
48192 clearPanels : function(){
48193 while(this.panels.getCount() > 0){
48194 this.remove(this.panels.first());
48199 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
48200 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
48201 * @param {Boolean} preservePanel Overrides the config preservePanel option
48202 * @return {Roo.ContentPanel} The panel that was removed
48204 remove : function(panel, preservePanel){
48205 panel = this.getPanel(panel);
48210 this.fireEvent("beforeremove", this, panel, e);
48211 if(e.cancel === true){
48214 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
48215 var panelId = panel.getId();
48216 this.panels.removeKey(panelId);
48218 document.body.appendChild(panel.getEl().dom);
48221 this.tabs.removeTab(panel.getEl().id);
48222 }else if (!preservePanel){
48223 this.bodyEl.dom.removeChild(panel.getEl().dom);
48225 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
48226 var p = this.panels.first();
48227 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
48228 tempEl.appendChild(p.getEl().dom);
48229 this.bodyEl.update("");
48230 this.bodyEl.dom.appendChild(p.getEl().dom);
48232 this.updateTitle(p.getTitle());
48234 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
48235 this.setActivePanel(p);
48237 panel.setRegion(null);
48238 if(this.activePanel == panel){
48239 this.activePanel = null;
48241 if(this.config.autoDestroy !== false && preservePanel !== true){
48242 try{panel.destroy();}catch(e){}
48244 this.fireEvent("panelremoved", this, panel);
48249 * Returns the TabPanel component used by this region
48250 * @return {Roo.TabPanel}
48252 getTabs : function(){
48256 createTool : function(parentEl, className){
48257 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
48258 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
48259 btn.addClassOnOver("x-layout-tools-button-over");
48264 * Ext JS Library 1.1.1
48265 * Copyright(c) 2006-2007, Ext JS, LLC.
48267 * Originally Released Under LGPL - original licence link has changed is not relivant.
48270 * <script type="text/javascript">
48276 * @class Roo.SplitLayoutRegion
48277 * @extends Roo.LayoutRegion
48278 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
48280 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
48281 this.cursor = cursor;
48282 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
48285 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
48286 splitTip : "Drag to resize.",
48287 collapsibleSplitTip : "Drag to resize. Double click to hide.",
48288 useSplitTips : false,
48290 applyConfig : function(config){
48291 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
48294 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
48295 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
48296 /** The SplitBar for this region
48297 * @type Roo.SplitBar */
48298 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
48299 this.split.on("moved", this.onSplitMove, this);
48300 this.split.useShim = config.useShim === true;
48301 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
48302 if(this.useSplitTips){
48303 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
48305 if(config.collapsible){
48306 this.split.el.on("dblclick", this.collapse, this);
48309 if(typeof config.minSize != "undefined"){
48310 this.split.minSize = config.minSize;
48312 if(typeof config.maxSize != "undefined"){
48313 this.split.maxSize = config.maxSize;
48315 if(config.hideWhenEmpty || config.hidden || config.collapsed){
48316 this.hideSplitter();
48321 getHMaxSize : function(){
48322 var cmax = this.config.maxSize || 10000;
48323 var center = this.mgr.getRegion("center");
48324 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
48327 getVMaxSize : function(){
48328 var cmax = this.config.maxSize || 10000;
48329 var center = this.mgr.getRegion("center");
48330 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
48333 onSplitMove : function(split, newSize){
48334 this.fireEvent("resized", this, newSize);
48338 * Returns the {@link Roo.SplitBar} for this region.
48339 * @return {Roo.SplitBar}
48341 getSplitBar : function(){
48346 this.hideSplitter();
48347 Roo.SplitLayoutRegion.superclass.hide.call(this);
48350 hideSplitter : function(){
48352 this.split.el.setLocation(-2000,-2000);
48353 this.split.el.hide();
48359 this.split.el.show();
48361 Roo.SplitLayoutRegion.superclass.show.call(this);
48364 beforeSlide: function(){
48365 if(Roo.isGecko){// firefox overflow auto bug workaround
48366 this.bodyEl.clip();
48367 if(this.tabs) this.tabs.bodyEl.clip();
48368 if(this.activePanel){
48369 this.activePanel.getEl().clip();
48371 if(this.activePanel.beforeSlide){
48372 this.activePanel.beforeSlide();
48378 afterSlide : function(){
48379 if(Roo.isGecko){// firefox overflow auto bug workaround
48380 this.bodyEl.unclip();
48381 if(this.tabs) this.tabs.bodyEl.unclip();
48382 if(this.activePanel){
48383 this.activePanel.getEl().unclip();
48384 if(this.activePanel.afterSlide){
48385 this.activePanel.afterSlide();
48391 initAutoHide : function(){
48392 if(this.autoHide !== false){
48393 if(!this.autoHideHd){
48394 var st = new Roo.util.DelayedTask(this.slideIn, this);
48395 this.autoHideHd = {
48396 "mouseout": function(e){
48397 if(!e.within(this.el, true)){
48401 "mouseover" : function(e){
48407 this.el.on(this.autoHideHd);
48411 clearAutoHide : function(){
48412 if(this.autoHide !== false){
48413 this.el.un("mouseout", this.autoHideHd.mouseout);
48414 this.el.un("mouseover", this.autoHideHd.mouseover);
48418 clearMonitor : function(){
48419 Roo.get(document).un("click", this.slideInIf, this);
48422 // these names are backwards but not changed for compat
48423 slideOut : function(){
48424 if(this.isSlid || this.el.hasActiveFx()){
48427 this.isSlid = true;
48428 if(this.collapseBtn){
48429 this.collapseBtn.hide();
48431 this.closeBtnState = this.closeBtn.getStyle('display');
48432 this.closeBtn.hide();
48434 this.stickBtn.show();
48437 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
48438 this.beforeSlide();
48439 this.el.setStyle("z-index", 10001);
48440 this.el.slideIn(this.getSlideAnchor(), {
48441 callback: function(){
48443 this.initAutoHide();
48444 Roo.get(document).on("click", this.slideInIf, this);
48445 this.fireEvent("slideshow", this);
48452 afterSlideIn : function(){
48453 this.clearAutoHide();
48454 this.isSlid = false;
48455 this.clearMonitor();
48456 this.el.setStyle("z-index", "");
48457 if(this.collapseBtn){
48458 this.collapseBtn.show();
48460 this.closeBtn.setStyle('display', this.closeBtnState);
48462 this.stickBtn.hide();
48464 this.fireEvent("slidehide", this);
48467 slideIn : function(cb){
48468 if(!this.isSlid || this.el.hasActiveFx()){
48472 this.isSlid = false;
48473 this.beforeSlide();
48474 this.el.slideOut(this.getSlideAnchor(), {
48475 callback: function(){
48476 this.el.setLeftTop(-10000, -10000);
48478 this.afterSlideIn();
48486 slideInIf : function(e){
48487 if(!e.within(this.el)){
48492 animateCollapse : function(){
48493 this.beforeSlide();
48494 this.el.setStyle("z-index", 20000);
48495 var anchor = this.getSlideAnchor();
48496 this.el.slideOut(anchor, {
48497 callback : function(){
48498 this.el.setStyle("z-index", "");
48499 this.collapsedEl.slideIn(anchor, {duration:.3});
48501 this.el.setLocation(-10000,-10000);
48503 this.fireEvent("collapsed", this);
48510 animateExpand : function(){
48511 this.beforeSlide();
48512 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
48513 this.el.setStyle("z-index", 20000);
48514 this.collapsedEl.hide({
48517 this.el.slideIn(this.getSlideAnchor(), {
48518 callback : function(){
48519 this.el.setStyle("z-index", "");
48522 this.split.el.show();
48524 this.fireEvent("invalidated", this);
48525 this.fireEvent("expanded", this);
48553 getAnchor : function(){
48554 return this.anchors[this.position];
48557 getCollapseAnchor : function(){
48558 return this.canchors[this.position];
48561 getSlideAnchor : function(){
48562 return this.sanchors[this.position];
48565 getAlignAdj : function(){
48566 var cm = this.cmargins;
48567 switch(this.position){
48583 getExpandAdj : function(){
48584 var c = this.collapsedEl, cm = this.cmargins;
48585 switch(this.position){
48587 return [-(cm.right+c.getWidth()+cm.left), 0];
48590 return [cm.right+c.getWidth()+cm.left, 0];
48593 return [0, -(cm.top+cm.bottom+c.getHeight())];
48596 return [0, cm.top+cm.bottom+c.getHeight()];
48602 * Ext JS Library 1.1.1
48603 * Copyright(c) 2006-2007, Ext JS, LLC.
48605 * Originally Released Under LGPL - original licence link has changed is not relivant.
48608 * <script type="text/javascript">
48611 * These classes are private internal classes
48613 Roo.CenterLayoutRegion = function(mgr, config){
48614 Roo.LayoutRegion.call(this, mgr, config, "center");
48615 this.visible = true;
48616 this.minWidth = config.minWidth || 20;
48617 this.minHeight = config.minHeight || 20;
48620 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
48622 // center panel can't be hidden
48626 // center panel can't be hidden
48629 getMinWidth: function(){
48630 return this.minWidth;
48633 getMinHeight: function(){
48634 return this.minHeight;
48639 Roo.NorthLayoutRegion = function(mgr, config){
48640 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
48642 this.split.placement = Roo.SplitBar.TOP;
48643 this.split.orientation = Roo.SplitBar.VERTICAL;
48644 this.split.el.addClass("x-layout-split-v");
48646 var size = config.initialSize || config.height;
48647 if(typeof size != "undefined"){
48648 this.el.setHeight(size);
48651 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
48652 orientation: Roo.SplitBar.VERTICAL,
48653 getBox : function(){
48654 if(this.collapsed){
48655 return this.collapsedEl.getBox();
48657 var box = this.el.getBox();
48659 box.height += this.split.el.getHeight();
48664 updateBox : function(box){
48665 if(this.split && !this.collapsed){
48666 box.height -= this.split.el.getHeight();
48667 this.split.el.setLeft(box.x);
48668 this.split.el.setTop(box.y+box.height);
48669 this.split.el.setWidth(box.width);
48671 if(this.collapsed){
48672 this.updateBody(box.width, null);
48674 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48678 Roo.SouthLayoutRegion = function(mgr, config){
48679 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
48681 this.split.placement = Roo.SplitBar.BOTTOM;
48682 this.split.orientation = Roo.SplitBar.VERTICAL;
48683 this.split.el.addClass("x-layout-split-v");
48685 var size = config.initialSize || config.height;
48686 if(typeof size != "undefined"){
48687 this.el.setHeight(size);
48690 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
48691 orientation: Roo.SplitBar.VERTICAL,
48692 getBox : function(){
48693 if(this.collapsed){
48694 return this.collapsedEl.getBox();
48696 var box = this.el.getBox();
48698 var sh = this.split.el.getHeight();
48705 updateBox : function(box){
48706 if(this.split && !this.collapsed){
48707 var sh = this.split.el.getHeight();
48710 this.split.el.setLeft(box.x);
48711 this.split.el.setTop(box.y-sh);
48712 this.split.el.setWidth(box.width);
48714 if(this.collapsed){
48715 this.updateBody(box.width, null);
48717 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48721 Roo.EastLayoutRegion = function(mgr, config){
48722 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
48724 this.split.placement = Roo.SplitBar.RIGHT;
48725 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48726 this.split.el.addClass("x-layout-split-h");
48728 var size = config.initialSize || config.width;
48729 if(typeof size != "undefined"){
48730 this.el.setWidth(size);
48733 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
48734 orientation: Roo.SplitBar.HORIZONTAL,
48735 getBox : function(){
48736 if(this.collapsed){
48737 return this.collapsedEl.getBox();
48739 var box = this.el.getBox();
48741 var sw = this.split.el.getWidth();
48748 updateBox : function(box){
48749 if(this.split && !this.collapsed){
48750 var sw = this.split.el.getWidth();
48752 this.split.el.setLeft(box.x);
48753 this.split.el.setTop(box.y);
48754 this.split.el.setHeight(box.height);
48757 if(this.collapsed){
48758 this.updateBody(null, box.height);
48760 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48764 Roo.WestLayoutRegion = function(mgr, config){
48765 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
48767 this.split.placement = Roo.SplitBar.LEFT;
48768 this.split.orientation = Roo.SplitBar.HORIZONTAL;
48769 this.split.el.addClass("x-layout-split-h");
48771 var size = config.initialSize || config.width;
48772 if(typeof size != "undefined"){
48773 this.el.setWidth(size);
48776 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
48777 orientation: Roo.SplitBar.HORIZONTAL,
48778 getBox : function(){
48779 if(this.collapsed){
48780 return this.collapsedEl.getBox();
48782 var box = this.el.getBox();
48784 box.width += this.split.el.getWidth();
48789 updateBox : function(box){
48790 if(this.split && !this.collapsed){
48791 var sw = this.split.el.getWidth();
48793 this.split.el.setLeft(box.x+box.width);
48794 this.split.el.setTop(box.y);
48795 this.split.el.setHeight(box.height);
48797 if(this.collapsed){
48798 this.updateBody(null, box.height);
48800 Roo.LayoutRegion.prototype.updateBox.call(this, box);
48805 * Ext JS Library 1.1.1
48806 * Copyright(c) 2006-2007, Ext JS, LLC.
48808 * Originally Released Under LGPL - original licence link has changed is not relivant.
48811 * <script type="text/javascript">
48816 * Private internal class for reading and applying state
48818 Roo.LayoutStateManager = function(layout){
48819 // default empty state
48828 Roo.LayoutStateManager.prototype = {
48829 init : function(layout, provider){
48830 this.provider = provider;
48831 var state = provider.get(layout.id+"-layout-state");
48833 var wasUpdating = layout.isUpdating();
48835 layout.beginUpdate();
48837 for(var key in state){
48838 if(typeof state[key] != "function"){
48839 var rstate = state[key];
48840 var r = layout.getRegion(key);
48843 r.resizeTo(rstate.size);
48845 if(rstate.collapsed == true){
48848 r.expand(null, true);
48854 layout.endUpdate();
48856 this.state = state;
48858 this.layout = layout;
48859 layout.on("regionresized", this.onRegionResized, this);
48860 layout.on("regioncollapsed", this.onRegionCollapsed, this);
48861 layout.on("regionexpanded", this.onRegionExpanded, this);
48864 storeState : function(){
48865 this.provider.set(this.layout.id+"-layout-state", this.state);
48868 onRegionResized : function(region, newSize){
48869 this.state[region.getPosition()].size = newSize;
48873 onRegionCollapsed : function(region){
48874 this.state[region.getPosition()].collapsed = true;
48878 onRegionExpanded : function(region){
48879 this.state[region.getPosition()].collapsed = false;
48884 * Ext JS Library 1.1.1
48885 * Copyright(c) 2006-2007, Ext JS, LLC.
48887 * Originally Released Under LGPL - original licence link has changed is not relivant.
48890 * <script type="text/javascript">
48893 * @class Roo.ContentPanel
48894 * @extends Roo.util.Observable
48895 * A basic ContentPanel element.
48896 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
48897 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
48898 * @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
48899 * @cfg {Boolean} closable True if the panel can be closed/removed
48900 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
48901 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
48902 * @cfg {Toolbar} toolbar A toolbar for this panel
48903 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
48904 * @cfg {String} title The title for this panel
48905 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
48906 * @cfg {String} url Calls {@link #setUrl} with this value
48907 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
48908 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
48909 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
48910 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
48913 * Create a new ContentPanel.
48914 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
48915 * @param {String/Object} config A string to set only the title or a config object
48916 * @param {String} content (optional) Set the HTML content for this panel
48917 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
48919 Roo.ContentPanel = function(el, config, content){
48923 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
48927 if (config && config.parentLayout) {
48928 el = config.parentLayout.el.createChild();
48931 if(el.autoCreate){ // xtype is available if this is called from factory
48935 this.el = Roo.get(el);
48936 if(!this.el && config && config.autoCreate){
48937 if(typeof config.autoCreate == "object"){
48938 if(!config.autoCreate.id){
48939 config.autoCreate.id = config.id||el;
48941 this.el = Roo.DomHelper.append(document.body,
48942 config.autoCreate, true);
48944 this.el = Roo.DomHelper.append(document.body,
48945 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
48948 this.closable = false;
48949 this.loaded = false;
48950 this.active = false;
48951 if(typeof config == "string"){
48952 this.title = config;
48954 Roo.apply(this, config);
48957 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
48958 this.wrapEl = this.el.wrap();
48959 this.toolbar.container = this.el.insertSibling(false, 'before');
48960 this.toolbar = new Roo.Toolbar(this.toolbar);
48963 // xtype created footer. - not sure if will work as we normally have to render first..
48964 if (this.footer && !this.footer.el && this.footer.xtype) {
48965 if (!this.wrapEl) {
48966 this.wrapEl = this.el.wrap();
48969 this.footer.container = this.wrapEl.createChild();
48971 this.footer = Roo.factory(this.footer, Roo);
48976 this.resizeEl = Roo.get(this.resizeEl, true);
48978 this.resizeEl = this.el;
48980 // handle view.xtype
48988 * Fires when this panel is activated.
48989 * @param {Roo.ContentPanel} this
48993 * @event deactivate
48994 * Fires when this panel is activated.
48995 * @param {Roo.ContentPanel} this
48997 "deactivate" : true,
49001 * Fires when this panel is resized if fitToFrame is true.
49002 * @param {Roo.ContentPanel} this
49003 * @param {Number} width The width after any component adjustments
49004 * @param {Number} height The height after any component adjustments
49010 * Fires when this tab is created
49011 * @param {Roo.ContentPanel} this
49022 if(this.autoScroll){
49023 this.resizeEl.setStyle("overflow", "auto");
49025 // fix randome scrolling
49026 this.el.on('scroll', function() {
49027 Roo.log('fix random scolling');
49028 this.scrollTo('top',0);
49031 content = content || this.content;
49033 this.setContent(content);
49035 if(config && config.url){
49036 this.setUrl(this.url, this.params, this.loadOnce);
49041 Roo.ContentPanel.superclass.constructor.call(this);
49043 if (this.view && typeof(this.view.xtype) != 'undefined') {
49044 this.view.el = this.el.appendChild(document.createElement("div"));
49045 this.view = Roo.factory(this.view);
49046 this.view.render && this.view.render(false, '');
49050 this.fireEvent('render', this);
49053 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
49055 setRegion : function(region){
49056 this.region = region;
49058 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
49060 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
49065 * Returns the toolbar for this Panel if one was configured.
49066 * @return {Roo.Toolbar}
49068 getToolbar : function(){
49069 return this.toolbar;
49072 setActiveState : function(active){
49073 this.active = active;
49075 this.fireEvent("deactivate", this);
49077 this.fireEvent("activate", this);
49081 * Updates this panel's element
49082 * @param {String} content The new content
49083 * @param {Boolean} loadScripts (optional) true to look for and process scripts
49085 setContent : function(content, loadScripts){
49086 this.el.update(content, loadScripts);
49089 ignoreResize : function(w, h){
49090 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
49093 this.lastSize = {width: w, height: h};
49098 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
49099 * @return {Roo.UpdateManager} The UpdateManager
49101 getUpdateManager : function(){
49102 return this.el.getUpdateManager();
49105 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
49106 * @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:
49109 url: "your-url.php",
49110 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
49111 callback: yourFunction,
49112 scope: yourObject, //(optional scope)
49115 text: "Loading...",
49120 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
49121 * 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.
49122 * @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}
49123 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
49124 * @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.
49125 * @return {Roo.ContentPanel} this
49128 var um = this.el.getUpdateManager();
49129 um.update.apply(um, arguments);
49135 * 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.
49136 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
49137 * @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)
49138 * @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)
49139 * @return {Roo.UpdateManager} The UpdateManager
49141 setUrl : function(url, params, loadOnce){
49142 if(this.refreshDelegate){
49143 this.removeListener("activate", this.refreshDelegate);
49145 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
49146 this.on("activate", this.refreshDelegate);
49147 return this.el.getUpdateManager();
49150 _handleRefresh : function(url, params, loadOnce){
49151 if(!loadOnce || !this.loaded){
49152 var updater = this.el.getUpdateManager();
49153 updater.update(url, params, this._setLoaded.createDelegate(this));
49157 _setLoaded : function(){
49158 this.loaded = true;
49162 * Returns this panel's id
49165 getId : function(){
49170 * Returns this panel's element - used by regiosn to add.
49171 * @return {Roo.Element}
49173 getEl : function(){
49174 return this.wrapEl || this.el;
49177 adjustForComponents : function(width, height)
49179 //Roo.log('adjustForComponents ');
49180 if(this.resizeEl != this.el){
49181 width -= this.el.getFrameWidth('lr');
49182 height -= this.el.getFrameWidth('tb');
49185 var te = this.toolbar.getEl();
49186 height -= te.getHeight();
49187 te.setWidth(width);
49190 var te = this.footer.getEl();
49191 Roo.log("footer:" + te.getHeight());
49193 height -= te.getHeight();
49194 te.setWidth(width);
49198 if(this.adjustments){
49199 width += this.adjustments[0];
49200 height += this.adjustments[1];
49202 return {"width": width, "height": height};
49205 setSize : function(width, height){
49206 if(this.fitToFrame && !this.ignoreResize(width, height)){
49207 if(this.fitContainer && this.resizeEl != this.el){
49208 this.el.setSize(width, height);
49210 var size = this.adjustForComponents(width, height);
49211 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
49212 this.fireEvent('resize', this, size.width, size.height);
49217 * Returns this panel's title
49220 getTitle : function(){
49225 * Set this panel's title
49226 * @param {String} title
49228 setTitle : function(title){
49229 this.title = title;
49231 this.region.updatePanelTitle(this, title);
49236 * Returns true is this panel was configured to be closable
49237 * @return {Boolean}
49239 isClosable : function(){
49240 return this.closable;
49243 beforeSlide : function(){
49245 this.resizeEl.clip();
49248 afterSlide : function(){
49250 this.resizeEl.unclip();
49254 * Force a content refresh from the URL specified in the {@link #setUrl} method.
49255 * Will fail silently if the {@link #setUrl} method has not been called.
49256 * This does not activate the panel, just updates its content.
49258 refresh : function(){
49259 if(this.refreshDelegate){
49260 this.loaded = false;
49261 this.refreshDelegate();
49266 * Destroys this panel
49268 destroy : function(){
49269 this.el.removeAllListeners();
49270 var tempEl = document.createElement("span");
49271 tempEl.appendChild(this.el.dom);
49272 tempEl.innerHTML = "";
49278 * form - if the content panel contains a form - this is a reference to it.
49279 * @type {Roo.form.Form}
49283 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
49284 * This contains a reference to it.
49290 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
49300 * @param {Object} cfg Xtype definition of item to add.
49303 addxtype : function(cfg) {
49305 if (cfg.xtype.match(/^Form$/)) {
49308 //if (this.footer) {
49309 // el = this.footer.container.insertSibling(false, 'before');
49311 el = this.el.createChild();
49314 this.form = new Roo.form.Form(cfg);
49317 if ( this.form.allItems.length) this.form.render(el.dom);
49320 // should only have one of theses..
49321 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
49322 // views.. should not be just added - used named prop 'view''
49324 cfg.el = this.el.appendChild(document.createElement("div"));
49327 var ret = new Roo.factory(cfg);
49329 ret.render && ret.render(false, ''); // render blank..
49338 * @class Roo.GridPanel
49339 * @extends Roo.ContentPanel
49341 * Create a new GridPanel.
49342 * @param {Roo.grid.Grid} grid The grid for this panel
49343 * @param {String/Object} config A string to set only the panel's title, or a config object
49345 Roo.GridPanel = function(grid, config){
49348 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
49349 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
49351 this.wrapper.dom.appendChild(grid.getGridEl().dom);
49353 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
49356 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
49358 // xtype created footer. - not sure if will work as we normally have to render first..
49359 if (this.footer && !this.footer.el && this.footer.xtype) {
49361 this.footer.container = this.grid.getView().getFooterPanel(true);
49362 this.footer.dataSource = this.grid.dataSource;
49363 this.footer = Roo.factory(this.footer, Roo);
49367 grid.monitorWindowResize = false; // turn off autosizing
49368 grid.autoHeight = false;
49369 grid.autoWidth = false;
49371 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
49374 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
49375 getId : function(){
49376 return this.grid.id;
49380 * Returns the grid for this panel
49381 * @return {Roo.grid.Grid}
49383 getGrid : function(){
49387 setSize : function(width, height){
49388 if(!this.ignoreResize(width, height)){
49389 var grid = this.grid;
49390 var size = this.adjustForComponents(width, height);
49391 grid.getGridEl().setSize(size.width, size.height);
49396 beforeSlide : function(){
49397 this.grid.getView().scroller.clip();
49400 afterSlide : function(){
49401 this.grid.getView().scroller.unclip();
49404 destroy : function(){
49405 this.grid.destroy();
49407 Roo.GridPanel.superclass.destroy.call(this);
49413 * @class Roo.NestedLayoutPanel
49414 * @extends Roo.ContentPanel
49416 * Create a new NestedLayoutPanel.
49419 * @param {Roo.BorderLayout} layout The layout for this panel
49420 * @param {String/Object} config A string to set only the title or a config object
49422 Roo.NestedLayoutPanel = function(layout, config)
49424 // construct with only one argument..
49425 /* FIXME - implement nicer consturctors
49426 if (layout.layout) {
49428 layout = config.layout;
49429 delete config.layout;
49431 if (layout.xtype && !layout.getEl) {
49432 // then layout needs constructing..
49433 layout = Roo.factory(layout, Roo);
49438 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
49440 layout.monitorWindowResize = false; // turn off autosizing
49441 this.layout = layout;
49442 this.layout.getEl().addClass("x-layout-nested-layout");
49449 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
49451 setSize : function(width, height){
49452 if(!this.ignoreResize(width, height)){
49453 var size = this.adjustForComponents(width, height);
49454 var el = this.layout.getEl();
49455 el.setSize(size.width, size.height);
49456 var touch = el.dom.offsetWidth;
49457 this.layout.layout();
49458 // ie requires a double layout on the first pass
49459 if(Roo.isIE && !this.initialized){
49460 this.initialized = true;
49461 this.layout.layout();
49466 // activate all subpanels if not currently active..
49468 setActiveState : function(active){
49469 this.active = active;
49471 this.fireEvent("deactivate", this);
49475 this.fireEvent("activate", this);
49476 // not sure if this should happen before or after..
49477 if (!this.layout) {
49478 return; // should not happen..
49481 for (var r in this.layout.regions) {
49482 reg = this.layout.getRegion(r);
49483 if (reg.getActivePanel()) {
49484 //reg.showPanel(reg.getActivePanel()); // force it to activate..
49485 reg.setActivePanel(reg.getActivePanel());
49488 if (!reg.panels.length) {
49491 reg.showPanel(reg.getPanel(0));
49500 * Returns the nested BorderLayout for this panel
49501 * @return {Roo.BorderLayout}
49503 getLayout : function(){
49504 return this.layout;
49508 * Adds a xtype elements to the layout of the nested panel
49512 xtype : 'ContentPanel',
49519 xtype : 'NestedLayoutPanel',
49525 items : [ ... list of content panels or nested layout panels.. ]
49529 * @param {Object} cfg Xtype definition of item to add.
49531 addxtype : function(cfg) {
49532 return this.layout.addxtype(cfg);
49537 Roo.ScrollPanel = function(el, config, content){
49538 config = config || {};
49539 config.fitToFrame = true;
49540 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
49542 this.el.dom.style.overflow = "hidden";
49543 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
49544 this.el.removeClass("x-layout-inactive-content");
49545 this.el.on("mousewheel", this.onWheel, this);
49547 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
49548 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
49549 up.unselectable(); down.unselectable();
49550 up.on("click", this.scrollUp, this);
49551 down.on("click", this.scrollDown, this);
49552 up.addClassOnOver("x-scroller-btn-over");
49553 down.addClassOnOver("x-scroller-btn-over");
49554 up.addClassOnClick("x-scroller-btn-click");
49555 down.addClassOnClick("x-scroller-btn-click");
49556 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
49558 this.resizeEl = this.el;
49559 this.el = wrap; this.up = up; this.down = down;
49562 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
49564 wheelIncrement : 5,
49565 scrollUp : function(){
49566 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
49569 scrollDown : function(){
49570 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
49573 afterScroll : function(){
49574 var el = this.resizeEl;
49575 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
49576 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
49577 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
49580 setSize : function(){
49581 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
49582 this.afterScroll();
49585 onWheel : function(e){
49586 var d = e.getWheelDelta();
49587 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
49588 this.afterScroll();
49592 setContent : function(content, loadScripts){
49593 this.resizeEl.update(content, loadScripts);
49607 * @class Roo.TreePanel
49608 * @extends Roo.ContentPanel
49610 * Create a new TreePanel. - defaults to fit/scoll contents.
49611 * @param {String/Object} config A string to set only the panel's title, or a config object
49612 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
49614 Roo.TreePanel = function(config){
49615 var el = config.el;
49616 var tree = config.tree;
49617 delete config.tree;
49618 delete config.el; // hopefull!
49620 // wrapper for IE7 strict & safari scroll issue
49622 var treeEl = el.createChild();
49623 config.resizeEl = treeEl;
49627 Roo.TreePanel.superclass.constructor.call(this, el, config);
49630 this.tree = new Roo.tree.TreePanel(treeEl , tree);
49631 //console.log(tree);
49632 this.on('activate', function()
49634 if (this.tree.rendered) {
49637 //console.log('render tree');
49638 this.tree.render();
49640 // this should not be needed.. - it's actually the 'el' that resizes?
49641 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
49643 //this.on('resize', function (cp, w, h) {
49644 // this.tree.innerCt.setWidth(w);
49645 // this.tree.innerCt.setHeight(h);
49646 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
49653 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
49670 * Ext JS Library 1.1.1
49671 * Copyright(c) 2006-2007, Ext JS, LLC.
49673 * Originally Released Under LGPL - original licence link has changed is not relivant.
49676 * <script type="text/javascript">
49681 * @class Roo.ReaderLayout
49682 * @extends Roo.BorderLayout
49683 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
49684 * center region containing two nested regions (a top one for a list view and one for item preview below),
49685 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
49686 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
49687 * expedites the setup of the overall layout and regions for this common application style.
49690 var reader = new Roo.ReaderLayout();
49691 var CP = Roo.ContentPanel; // shortcut for adding
49693 reader.beginUpdate();
49694 reader.add("north", new CP("north", "North"));
49695 reader.add("west", new CP("west", {title: "West"}));
49696 reader.add("east", new CP("east", {title: "East"}));
49698 reader.regions.listView.add(new CP("listView", "List"));
49699 reader.regions.preview.add(new CP("preview", "Preview"));
49700 reader.endUpdate();
49703 * Create a new ReaderLayout
49704 * @param {Object} config Configuration options
49705 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
49706 * document.body if omitted)
49708 Roo.ReaderLayout = function(config, renderTo){
49709 var c = config || {size:{}};
49710 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
49711 north: c.north !== false ? Roo.apply({
49715 }, c.north) : false,
49716 west: c.west !== false ? Roo.apply({
49724 margins:{left:5,right:0,bottom:5,top:5},
49725 cmargins:{left:5,right:5,bottom:5,top:5}
49726 }, c.west) : false,
49727 east: c.east !== false ? Roo.apply({
49735 margins:{left:0,right:5,bottom:5,top:5},
49736 cmargins:{left:5,right:5,bottom:5,top:5}
49737 }, c.east) : false,
49738 center: Roo.apply({
49739 tabPosition: 'top',
49743 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
49747 this.el.addClass('x-reader');
49749 this.beginUpdate();
49751 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
49752 south: c.preview !== false ? Roo.apply({
49759 cmargins:{top:5,left:0, right:0, bottom:0}
49760 }, c.preview) : false,
49761 center: Roo.apply({
49767 this.add('center', new Roo.NestedLayoutPanel(inner,
49768 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
49772 this.regions.preview = inner.getRegion('south');
49773 this.regions.listView = inner.getRegion('center');
49776 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
49778 * Ext JS Library 1.1.1
49779 * Copyright(c) 2006-2007, Ext JS, LLC.
49781 * Originally Released Under LGPL - original licence link has changed is not relivant.
49784 * <script type="text/javascript">
49788 * @class Roo.grid.Grid
49789 * @extends Roo.util.Observable
49790 * This class represents the primary interface of a component based grid control.
49791 * <br><br>Usage:<pre><code>
49792 var grid = new Roo.grid.Grid("my-container-id", {
49795 selModel: mySelectionModel,
49796 autoSizeColumns: true,
49797 monitorWindowResize: false,
49798 trackMouseOver: true
49803 * <b>Common Problems:</b><br/>
49804 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
49805 * element will correct this<br/>
49806 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
49807 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
49808 * are unpredictable.<br/>
49809 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
49810 * grid to calculate dimensions/offsets.<br/>
49812 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
49813 * The container MUST have some type of size defined for the grid to fill. The container will be
49814 * automatically set to position relative if it isn't already.
49815 * @param {Object} config A config object that sets properties on this grid.
49817 Roo.grid.Grid = function(container, config){
49818 // initialize the container
49819 this.container = Roo.get(container);
49820 this.container.update("");
49821 this.container.setStyle("overflow", "hidden");
49822 this.container.addClass('x-grid-container');
49824 this.id = this.container.id;
49826 Roo.apply(this, config);
49827 // check and correct shorthanded configs
49829 this.dataSource = this.ds;
49833 this.colModel = this.cm;
49837 this.selModel = this.sm;
49841 if (this.selModel) {
49842 this.selModel = Roo.factory(this.selModel, Roo.grid);
49843 this.sm = this.selModel;
49844 this.sm.xmodule = this.xmodule || false;
49846 if (typeof(this.colModel.config) == 'undefined') {
49847 this.colModel = new Roo.grid.ColumnModel(this.colModel);
49848 this.cm = this.colModel;
49849 this.cm.xmodule = this.xmodule || false;
49851 if (this.dataSource) {
49852 this.dataSource= Roo.factory(this.dataSource, Roo.data);
49853 this.ds = this.dataSource;
49854 this.ds.xmodule = this.xmodule || false;
49861 this.container.setWidth(this.width);
49865 this.container.setHeight(this.height);
49872 * The raw click event for the entire grid.
49873 * @param {Roo.EventObject} e
49878 * The raw dblclick event for the entire grid.
49879 * @param {Roo.EventObject} e
49883 * @event contextmenu
49884 * The raw contextmenu event for the entire grid.
49885 * @param {Roo.EventObject} e
49887 "contextmenu" : true,
49890 * The raw mousedown event for the entire grid.
49891 * @param {Roo.EventObject} e
49893 "mousedown" : true,
49896 * The raw mouseup event for the entire grid.
49897 * @param {Roo.EventObject} e
49902 * The raw mouseover event for the entire grid.
49903 * @param {Roo.EventObject} e
49905 "mouseover" : true,
49908 * The raw mouseout event for the entire grid.
49909 * @param {Roo.EventObject} e
49914 * The raw keypress event for the entire grid.
49915 * @param {Roo.EventObject} e
49920 * The raw keydown event for the entire grid.
49921 * @param {Roo.EventObject} e
49929 * Fires when a cell is clicked
49930 * @param {Grid} this
49931 * @param {Number} rowIndex
49932 * @param {Number} columnIndex
49933 * @param {Roo.EventObject} e
49935 "cellclick" : true,
49937 * @event celldblclick
49938 * Fires when a cell is double clicked
49939 * @param {Grid} this
49940 * @param {Number} rowIndex
49941 * @param {Number} columnIndex
49942 * @param {Roo.EventObject} e
49944 "celldblclick" : true,
49947 * Fires when a row is clicked
49948 * @param {Grid} this
49949 * @param {Number} rowIndex
49950 * @param {Roo.EventObject} e
49954 * @event rowdblclick
49955 * Fires when a row is double clicked
49956 * @param {Grid} this
49957 * @param {Number} rowIndex
49958 * @param {Roo.EventObject} e
49960 "rowdblclick" : true,
49962 * @event headerclick
49963 * Fires when a header is clicked
49964 * @param {Grid} this
49965 * @param {Number} columnIndex
49966 * @param {Roo.EventObject} e
49968 "headerclick" : true,
49970 * @event headerdblclick
49971 * Fires when a header cell is double clicked
49972 * @param {Grid} this
49973 * @param {Number} columnIndex
49974 * @param {Roo.EventObject} e
49976 "headerdblclick" : true,
49978 * @event rowcontextmenu
49979 * Fires when a row is right clicked
49980 * @param {Grid} this
49981 * @param {Number} rowIndex
49982 * @param {Roo.EventObject} e
49984 "rowcontextmenu" : true,
49986 * @event cellcontextmenu
49987 * Fires when a cell is right clicked
49988 * @param {Grid} this
49989 * @param {Number} rowIndex
49990 * @param {Number} cellIndex
49991 * @param {Roo.EventObject} e
49993 "cellcontextmenu" : true,
49995 * @event headercontextmenu
49996 * Fires when a header is right clicked
49997 * @param {Grid} this
49998 * @param {Number} columnIndex
49999 * @param {Roo.EventObject} e
50001 "headercontextmenu" : true,
50003 * @event bodyscroll
50004 * Fires when the body element is scrolled
50005 * @param {Number} scrollLeft
50006 * @param {Number} scrollTop
50008 "bodyscroll" : true,
50010 * @event columnresize
50011 * Fires when the user resizes a column
50012 * @param {Number} columnIndex
50013 * @param {Number} newSize
50015 "columnresize" : true,
50017 * @event columnmove
50018 * Fires when the user moves a column
50019 * @param {Number} oldIndex
50020 * @param {Number} newIndex
50022 "columnmove" : true,
50025 * Fires when row(s) start being dragged
50026 * @param {Grid} this
50027 * @param {Roo.GridDD} dd The drag drop object
50028 * @param {event} e The raw browser event
50030 "startdrag" : true,
50033 * Fires when a drag operation is complete
50034 * @param {Grid} this
50035 * @param {Roo.GridDD} dd The drag drop object
50036 * @param {event} e The raw browser event
50041 * Fires when dragged row(s) are dropped on a valid DD target
50042 * @param {Grid} this
50043 * @param {Roo.GridDD} dd The drag drop object
50044 * @param {String} targetId The target drag drop object
50045 * @param {event} e The raw browser event
50050 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
50051 * @param {Grid} this
50052 * @param {Roo.GridDD} dd The drag drop object
50053 * @param {String} targetId The target drag drop object
50054 * @param {event} e The raw browser event
50059 * Fires when the dragged row(s) first cross another DD target while being dragged
50060 * @param {Grid} this
50061 * @param {Roo.GridDD} dd The drag drop object
50062 * @param {String} targetId The target drag drop object
50063 * @param {event} e The raw browser event
50065 "dragenter" : true,
50068 * Fires when the dragged row(s) leave another DD target while being dragged
50069 * @param {Grid} this
50070 * @param {Roo.GridDD} dd The drag drop object
50071 * @param {String} targetId The target drag drop object
50072 * @param {event} e The raw browser event
50077 * Fires when a row is rendered, so you can change add a style to it.
50078 * @param {GridView} gridview The grid view
50079 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
50085 * Fires when the grid is rendered
50086 * @param {Grid} grid
50091 Roo.grid.Grid.superclass.constructor.call(this);
50093 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
50096 * @cfg {String} ddGroup - drag drop group.
50100 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
50102 minColumnWidth : 25,
50105 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
50106 * <b>on initial render.</b> It is more efficient to explicitly size the columns
50107 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
50109 autoSizeColumns : false,
50112 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
50114 autoSizeHeaders : true,
50117 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
50119 monitorWindowResize : true,
50122 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
50123 * rows measured to get a columns size. Default is 0 (all rows).
50125 maxRowsToMeasure : 0,
50128 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
50130 trackMouseOver : true,
50133 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
50137 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
50139 enableDragDrop : false,
50142 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
50144 enableColumnMove : true,
50147 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
50149 enableColumnHide : true,
50152 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
50154 enableRowHeightSync : false,
50157 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
50162 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
50164 autoHeight : false,
50167 * @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.
50169 autoExpandColumn : false,
50172 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
50175 autoExpandMin : 50,
50178 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
50180 autoExpandMax : 1000,
50183 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
50188 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
50192 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
50202 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
50203 * of a fixed width. Default is false.
50206 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
50209 * Called once after all setup has been completed and the grid is ready to be rendered.
50210 * @return {Roo.grid.Grid} this
50212 render : function()
50214 var c = this.container;
50215 // try to detect autoHeight/width mode
50216 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
50217 this.autoHeight = true;
50219 var view = this.getView();
50222 c.on("click", this.onClick, this);
50223 c.on("dblclick", this.onDblClick, this);
50224 c.on("contextmenu", this.onContextMenu, this);
50225 c.on("keydown", this.onKeyDown, this);
50227 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
50229 this.getSelectionModel().init(this);
50234 this.loadMask = new Roo.LoadMask(this.container,
50235 Roo.apply({store:this.dataSource}, this.loadMask));
50239 if (this.toolbar && this.toolbar.xtype) {
50240 this.toolbar.container = this.getView().getHeaderPanel(true);
50241 this.toolbar = new Roo.Toolbar(this.toolbar);
50243 if (this.footer && this.footer.xtype) {
50244 this.footer.dataSource = this.getDataSource();
50245 this.footer.container = this.getView().getFooterPanel(true);
50246 this.footer = Roo.factory(this.footer, Roo);
50248 if (this.dropTarget && this.dropTarget.xtype) {
50249 delete this.dropTarget.xtype;
50250 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
50254 this.rendered = true;
50255 this.fireEvent('render', this);
50260 * Reconfigures the grid to use a different Store and Column Model.
50261 * The View will be bound to the new objects and refreshed.
50262 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
50263 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
50265 reconfigure : function(dataSource, colModel){
50267 this.loadMask.destroy();
50268 this.loadMask = new Roo.LoadMask(this.container,
50269 Roo.apply({store:dataSource}, this.loadMask));
50271 this.view.bind(dataSource, colModel);
50272 this.dataSource = dataSource;
50273 this.colModel = colModel;
50274 this.view.refresh(true);
50278 onKeyDown : function(e){
50279 this.fireEvent("keydown", e);
50283 * Destroy this grid.
50284 * @param {Boolean} removeEl True to remove the element
50286 destroy : function(removeEl, keepListeners){
50288 this.loadMask.destroy();
50290 var c = this.container;
50291 c.removeAllListeners();
50292 this.view.destroy();
50293 this.colModel.purgeListeners();
50294 if(!keepListeners){
50295 this.purgeListeners();
50298 if(removeEl === true){
50304 processEvent : function(name, e){
50305 this.fireEvent(name, e);
50306 var t = e.getTarget();
50308 var header = v.findHeaderIndex(t);
50309 if(header !== false){
50310 this.fireEvent("header" + name, this, header, e);
50312 var row = v.findRowIndex(t);
50313 var cell = v.findCellIndex(t);
50315 this.fireEvent("row" + name, this, row, e);
50316 if(cell !== false){
50317 this.fireEvent("cell" + name, this, row, cell, e);
50324 onClick : function(e){
50325 this.processEvent("click", e);
50329 onContextMenu : function(e, t){
50330 this.processEvent("contextmenu", e);
50334 onDblClick : function(e){
50335 this.processEvent("dblclick", e);
50339 walkCells : function(row, col, step, fn, scope){
50340 var cm = this.colModel, clen = cm.getColumnCount();
50341 var ds = this.dataSource, rlen = ds.getCount(), first = true;
50353 if(fn.call(scope || this, row, col, cm) === true){
50371 if(fn.call(scope || this, row, col, cm) === true){
50383 getSelections : function(){
50384 return this.selModel.getSelections();
50388 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
50389 * but if manual update is required this method will initiate it.
50391 autoSize : function(){
50393 this.view.layout();
50394 if(this.view.adjustForScroll){
50395 this.view.adjustForScroll();
50401 * Returns the grid's underlying element.
50402 * @return {Element} The element
50404 getGridEl : function(){
50405 return this.container;
50408 // private for compatibility, overridden by editor grid
50409 stopEditing : function(){},
50412 * Returns the grid's SelectionModel.
50413 * @return {SelectionModel}
50415 getSelectionModel : function(){
50416 if(!this.selModel){
50417 this.selModel = new Roo.grid.RowSelectionModel();
50419 return this.selModel;
50423 * Returns the grid's DataSource.
50424 * @return {DataSource}
50426 getDataSource : function(){
50427 return this.dataSource;
50431 * Returns the grid's ColumnModel.
50432 * @return {ColumnModel}
50434 getColumnModel : function(){
50435 return this.colModel;
50439 * Returns the grid's GridView object.
50440 * @return {GridView}
50442 getView : function(){
50444 this.view = new Roo.grid.GridView(this.viewConfig);
50449 * Called to get grid's drag proxy text, by default returns this.ddText.
50452 getDragDropText : function(){
50453 var count = this.selModel.getCount();
50454 return String.format(this.ddText, count, count == 1 ? '' : 's');
50458 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
50459 * %0 is replaced with the number of selected rows.
50462 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
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 Roo.grid.AbstractGridView = function(){
50477 "beforerowremoved" : true,
50478 "beforerowsinserted" : true,
50479 "beforerefresh" : true,
50480 "rowremoved" : true,
50481 "rowsinserted" : true,
50482 "rowupdated" : true,
50485 Roo.grid.AbstractGridView.superclass.constructor.call(this);
50488 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
50489 rowClass : "x-grid-row",
50490 cellClass : "x-grid-cell",
50491 tdClass : "x-grid-td",
50492 hdClass : "x-grid-hd",
50493 splitClass : "x-grid-hd-split",
50495 init: function(grid){
50497 var cid = this.grid.getGridEl().id;
50498 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
50499 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
50500 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
50501 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
50504 getColumnRenderers : function(){
50505 var renderers = [];
50506 var cm = this.grid.colModel;
50507 var colCount = cm.getColumnCount();
50508 for(var i = 0; i < colCount; i++){
50509 renderers[i] = cm.getRenderer(i);
50514 getColumnIds : function(){
50516 var cm = this.grid.colModel;
50517 var colCount = cm.getColumnCount();
50518 for(var i = 0; i < colCount; i++){
50519 ids[i] = cm.getColumnId(i);
50524 getDataIndexes : function(){
50525 if(!this.indexMap){
50526 this.indexMap = this.buildIndexMap();
50528 return this.indexMap.colToData;
50531 getColumnIndexByDataIndex : function(dataIndex){
50532 if(!this.indexMap){
50533 this.indexMap = this.buildIndexMap();
50535 return this.indexMap.dataToCol[dataIndex];
50539 * Set a css style for a column dynamically.
50540 * @param {Number} colIndex The index of the column
50541 * @param {String} name The css property name
50542 * @param {String} value The css value
50544 setCSSStyle : function(colIndex, name, value){
50545 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
50546 Roo.util.CSS.updateRule(selector, name, value);
50549 generateRules : function(cm){
50550 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
50551 Roo.util.CSS.removeStyleSheet(rulesId);
50552 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
50553 var cid = cm.getColumnId(i);
50554 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
50555 this.tdSelector, cid, " {\n}\n",
50556 this.hdSelector, cid, " {\n}\n",
50557 this.splitSelector, cid, " {\n}\n");
50559 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
50563 * Ext JS Library 1.1.1
50564 * Copyright(c) 2006-2007, Ext JS, LLC.
50566 * Originally Released Under LGPL - original licence link has changed is not relivant.
50569 * <script type="text/javascript">
50573 // This is a support class used internally by the Grid components
50574 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
50576 this.view = grid.getView();
50577 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
50578 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
50580 this.setHandleElId(Roo.id(hd));
50581 this.setOuterHandleElId(Roo.id(hd2));
50583 this.scroll = false;
50585 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
50587 getDragData : function(e){
50588 var t = Roo.lib.Event.getTarget(e);
50589 var h = this.view.findHeaderCell(t);
50591 return {ddel: h.firstChild, header:h};
50596 onInitDrag : function(e){
50597 this.view.headersDisabled = true;
50598 var clone = this.dragData.ddel.cloneNode(true);
50599 clone.id = Roo.id();
50600 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
50601 this.proxy.update(clone);
50605 afterValidDrop : function(){
50607 setTimeout(function(){
50608 v.headersDisabled = false;
50612 afterInvalidDrop : function(){
50614 setTimeout(function(){
50615 v.headersDisabled = false;
50621 * Ext JS Library 1.1.1
50622 * Copyright(c) 2006-2007, Ext JS, LLC.
50624 * Originally Released Under LGPL - original licence link has changed is not relivant.
50627 * <script type="text/javascript">
50630 // This is a support class used internally by the Grid components
50631 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
50633 this.view = grid.getView();
50634 // split the proxies so they don't interfere with mouse events
50635 this.proxyTop = Roo.DomHelper.append(document.body, {
50636 cls:"col-move-top", html:" "
50638 this.proxyBottom = Roo.DomHelper.append(document.body, {
50639 cls:"col-move-bottom", html:" "
50641 this.proxyTop.hide = this.proxyBottom.hide = function(){
50642 this.setLeftTop(-100,-100);
50643 this.setStyle("visibility", "hidden");
50645 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
50646 // temporarily disabled
50647 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
50648 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
50650 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
50651 proxyOffsets : [-4, -9],
50652 fly: Roo.Element.fly,
50654 getTargetFromEvent : function(e){
50655 var t = Roo.lib.Event.getTarget(e);
50656 var cindex = this.view.findCellIndex(t);
50657 if(cindex !== false){
50658 return this.view.getHeaderCell(cindex);
50663 nextVisible : function(h){
50664 var v = this.view, cm = this.grid.colModel;
50667 if(!cm.isHidden(v.getCellIndex(h))){
50675 prevVisible : function(h){
50676 var v = this.view, cm = this.grid.colModel;
50679 if(!cm.isHidden(v.getCellIndex(h))){
50687 positionIndicator : function(h, n, e){
50688 var x = Roo.lib.Event.getPageX(e);
50689 var r = Roo.lib.Dom.getRegion(n.firstChild);
50690 var px, pt, py = r.top + this.proxyOffsets[1];
50691 if((r.right - x) <= (r.right-r.left)/2){
50692 px = r.right+this.view.borderWidth;
50698 var oldIndex = this.view.getCellIndex(h);
50699 var newIndex = this.view.getCellIndex(n);
50701 if(this.grid.colModel.isFixed(newIndex)){
50705 var locked = this.grid.colModel.isLocked(newIndex);
50710 if(oldIndex < newIndex){
50713 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
50716 px += this.proxyOffsets[0];
50717 this.proxyTop.setLeftTop(px, py);
50718 this.proxyTop.show();
50719 if(!this.bottomOffset){
50720 this.bottomOffset = this.view.mainHd.getHeight();
50722 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
50723 this.proxyBottom.show();
50727 onNodeEnter : function(n, dd, e, data){
50728 if(data.header != n){
50729 this.positionIndicator(data.header, n, e);
50733 onNodeOver : function(n, dd, e, data){
50734 var result = false;
50735 if(data.header != n){
50736 result = this.positionIndicator(data.header, n, e);
50739 this.proxyTop.hide();
50740 this.proxyBottom.hide();
50742 return result ? this.dropAllowed : this.dropNotAllowed;
50745 onNodeOut : function(n, dd, e, data){
50746 this.proxyTop.hide();
50747 this.proxyBottom.hide();
50750 onNodeDrop : function(n, dd, e, data){
50751 var h = data.header;
50753 var cm = this.grid.colModel;
50754 var x = Roo.lib.Event.getPageX(e);
50755 var r = Roo.lib.Dom.getRegion(n.firstChild);
50756 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
50757 var oldIndex = this.view.getCellIndex(h);
50758 var newIndex = this.view.getCellIndex(n);
50759 var locked = cm.isLocked(newIndex);
50763 if(oldIndex < newIndex){
50766 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
50769 cm.setLocked(oldIndex, locked, true);
50770 cm.moveColumn(oldIndex, newIndex);
50771 this.grid.fireEvent("columnmove", oldIndex, newIndex);
50779 * Ext JS Library 1.1.1
50780 * Copyright(c) 2006-2007, Ext JS, LLC.
50782 * Originally Released Under LGPL - original licence link has changed is not relivant.
50785 * <script type="text/javascript">
50789 * @class Roo.grid.GridView
50790 * @extends Roo.util.Observable
50793 * @param {Object} config
50795 Roo.grid.GridView = function(config){
50796 Roo.grid.GridView.superclass.constructor.call(this);
50799 Roo.apply(this, config);
50802 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
50804 unselectable : 'unselectable="on"',
50805 unselectableCls : 'x-unselectable',
50808 rowClass : "x-grid-row",
50810 cellClass : "x-grid-col",
50812 tdClass : "x-grid-td",
50814 hdClass : "x-grid-hd",
50816 splitClass : "x-grid-split",
50818 sortClasses : ["sort-asc", "sort-desc"],
50820 enableMoveAnim : false,
50824 dh : Roo.DomHelper,
50826 fly : Roo.Element.fly,
50828 css : Roo.util.CSS,
50834 scrollIncrement : 22,
50836 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
50838 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
50840 bind : function(ds, cm){
50842 this.ds.un("load", this.onLoad, this);
50843 this.ds.un("datachanged", this.onDataChange, this);
50844 this.ds.un("add", this.onAdd, this);
50845 this.ds.un("remove", this.onRemove, this);
50846 this.ds.un("update", this.onUpdate, this);
50847 this.ds.un("clear", this.onClear, this);
50850 ds.on("load", this.onLoad, this);
50851 ds.on("datachanged", this.onDataChange, this);
50852 ds.on("add", this.onAdd, this);
50853 ds.on("remove", this.onRemove, this);
50854 ds.on("update", this.onUpdate, this);
50855 ds.on("clear", this.onClear, this);
50860 this.cm.un("widthchange", this.onColWidthChange, this);
50861 this.cm.un("headerchange", this.onHeaderChange, this);
50862 this.cm.un("hiddenchange", this.onHiddenChange, this);
50863 this.cm.un("columnmoved", this.onColumnMove, this);
50864 this.cm.un("columnlockchange", this.onColumnLock, this);
50867 this.generateRules(cm);
50868 cm.on("widthchange", this.onColWidthChange, this);
50869 cm.on("headerchange", this.onHeaderChange, this);
50870 cm.on("hiddenchange", this.onHiddenChange, this);
50871 cm.on("columnmoved", this.onColumnMove, this);
50872 cm.on("columnlockchange", this.onColumnLock, this);
50877 init: function(grid){
50878 Roo.grid.GridView.superclass.init.call(this, grid);
50880 this.bind(grid.dataSource, grid.colModel);
50882 grid.on("headerclick", this.handleHeaderClick, this);
50884 if(grid.trackMouseOver){
50885 grid.on("mouseover", this.onRowOver, this);
50886 grid.on("mouseout", this.onRowOut, this);
50888 grid.cancelTextSelection = function(){};
50889 this.gridId = grid.id;
50891 var tpls = this.templates || {};
50894 tpls.master = new Roo.Template(
50895 '<div class="x-grid" hidefocus="true">',
50896 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
50897 '<div class="x-grid-topbar"></div>',
50898 '<div class="x-grid-scroller"><div></div></div>',
50899 '<div class="x-grid-locked">',
50900 '<div class="x-grid-header">{lockedHeader}</div>',
50901 '<div class="x-grid-body">{lockedBody}</div>',
50903 '<div class="x-grid-viewport">',
50904 '<div class="x-grid-header">{header}</div>',
50905 '<div class="x-grid-body">{body}</div>',
50907 '<div class="x-grid-bottombar"></div>',
50909 '<div class="x-grid-resize-proxy"> </div>',
50912 tpls.master.disableformats = true;
50916 tpls.header = new Roo.Template(
50917 '<table border="0" cellspacing="0" cellpadding="0">',
50918 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
50921 tpls.header.disableformats = true;
50923 tpls.header.compile();
50926 tpls.hcell = new Roo.Template(
50927 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
50928 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
50931 tpls.hcell.disableFormats = true;
50933 tpls.hcell.compile();
50936 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
50937 this.unselectableCls + '" ' + this.unselectable +'> </div>');
50938 tpls.hsplit.disableFormats = true;
50940 tpls.hsplit.compile();
50943 tpls.body = new Roo.Template(
50944 '<table border="0" cellspacing="0" cellpadding="0">',
50945 "<tbody>{rows}</tbody>",
50948 tpls.body.disableFormats = true;
50950 tpls.body.compile();
50953 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
50954 tpls.row.disableFormats = true;
50956 tpls.row.compile();
50959 tpls.cell = new Roo.Template(
50960 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
50961 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
50962 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
50965 tpls.cell.disableFormats = true;
50967 tpls.cell.compile();
50969 this.templates = tpls;
50972 // remap these for backwards compat
50973 onColWidthChange : function(){
50974 this.updateColumns.apply(this, arguments);
50976 onHeaderChange : function(){
50977 this.updateHeaders.apply(this, arguments);
50979 onHiddenChange : function(){
50980 this.handleHiddenChange.apply(this, arguments);
50982 onColumnMove : function(){
50983 this.handleColumnMove.apply(this, arguments);
50985 onColumnLock : function(){
50986 this.handleLockChange.apply(this, arguments);
50989 onDataChange : function(){
50991 this.updateHeaderSortState();
50994 onClear : function(){
50998 onUpdate : function(ds, record){
50999 this.refreshRow(record);
51002 refreshRow : function(record){
51003 var ds = this.ds, index;
51004 if(typeof record == 'number'){
51006 record = ds.getAt(index);
51008 index = ds.indexOf(record);
51010 this.insertRows(ds, index, index, true);
51011 this.onRemove(ds, record, index+1, true);
51012 this.syncRowHeights(index, index);
51014 this.fireEvent("rowupdated", this, index, record);
51017 onAdd : function(ds, records, index){
51018 this.insertRows(ds, index, index + (records.length-1));
51021 onRemove : function(ds, record, index, isUpdate){
51022 if(isUpdate !== true){
51023 this.fireEvent("beforerowremoved", this, index, record);
51025 var bt = this.getBodyTable(), lt = this.getLockedTable();
51026 if(bt.rows[index]){
51027 bt.firstChild.removeChild(bt.rows[index]);
51029 if(lt.rows[index]){
51030 lt.firstChild.removeChild(lt.rows[index]);
51032 if(isUpdate !== true){
51033 this.stripeRows(index);
51034 this.syncRowHeights(index, index);
51036 this.fireEvent("rowremoved", this, index, record);
51040 onLoad : function(){
51041 this.scrollToTop();
51045 * Scrolls the grid to the top
51047 scrollToTop : function(){
51049 this.scroller.dom.scrollTop = 0;
51055 * Gets a panel in the header of the grid that can be used for toolbars etc.
51056 * After modifying the contents of this panel a call to grid.autoSize() may be
51057 * required to register any changes in size.
51058 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
51059 * @return Roo.Element
51061 getHeaderPanel : function(doShow){
51063 this.headerPanel.show();
51065 return this.headerPanel;
51069 * Gets a panel in the footer of the grid that can be used for toolbars etc.
51070 * After modifying the contents of this panel a call to grid.autoSize() may be
51071 * required to register any changes in size.
51072 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
51073 * @return Roo.Element
51075 getFooterPanel : function(doShow){
51077 this.footerPanel.show();
51079 return this.footerPanel;
51082 initElements : function(){
51083 var E = Roo.Element;
51084 var el = this.grid.getGridEl().dom.firstChild;
51085 var cs = el.childNodes;
51087 this.el = new E(el);
51089 this.focusEl = new E(el.firstChild);
51090 this.focusEl.swallowEvent("click", true);
51092 this.headerPanel = new E(cs[1]);
51093 this.headerPanel.enableDisplayMode("block");
51095 this.scroller = new E(cs[2]);
51096 this.scrollSizer = new E(this.scroller.dom.firstChild);
51098 this.lockedWrap = new E(cs[3]);
51099 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
51100 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
51102 this.mainWrap = new E(cs[4]);
51103 this.mainHd = new E(this.mainWrap.dom.firstChild);
51104 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
51106 this.footerPanel = new E(cs[5]);
51107 this.footerPanel.enableDisplayMode("block");
51109 this.resizeProxy = new E(cs[6]);
51111 this.headerSelector = String.format(
51112 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
51113 this.lockedHd.id, this.mainHd.id
51116 this.splitterSelector = String.format(
51117 '#{0} div.x-grid-split, #{1} div.x-grid-split',
51118 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
51121 idToCssName : function(s)
51123 return s.replace(/[^a-z0-9]+/ig, '-');
51126 getHeaderCell : function(index){
51127 return Roo.DomQuery.select(this.headerSelector)[index];
51130 getHeaderCellMeasure : function(index){
51131 return this.getHeaderCell(index).firstChild;
51134 getHeaderCellText : function(index){
51135 return this.getHeaderCell(index).firstChild.firstChild;
51138 getLockedTable : function(){
51139 return this.lockedBody.dom.firstChild;
51142 getBodyTable : function(){
51143 return this.mainBody.dom.firstChild;
51146 getLockedRow : function(index){
51147 return this.getLockedTable().rows[index];
51150 getRow : function(index){
51151 return this.getBodyTable().rows[index];
51154 getRowComposite : function(index){
51156 this.rowEl = new Roo.CompositeElementLite();
51158 var els = [], lrow, mrow;
51159 if(lrow = this.getLockedRow(index)){
51162 if(mrow = this.getRow(index)){
51165 this.rowEl.elements = els;
51169 * Gets the 'td' of the cell
51171 * @param {Integer} rowIndex row to select
51172 * @param {Integer} colIndex column to select
51176 getCell : function(rowIndex, colIndex){
51177 var locked = this.cm.getLockedCount();
51179 if(colIndex < locked){
51180 source = this.lockedBody.dom.firstChild;
51182 source = this.mainBody.dom.firstChild;
51183 colIndex -= locked;
51185 return source.rows[rowIndex].childNodes[colIndex];
51188 getCellText : function(rowIndex, colIndex){
51189 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
51192 getCellBox : function(cell){
51193 var b = this.fly(cell).getBox();
51194 if(Roo.isOpera){ // opera fails to report the Y
51195 b.y = cell.offsetTop + this.mainBody.getY();
51200 getCellIndex : function(cell){
51201 var id = String(cell.className).match(this.cellRE);
51203 return parseInt(id[1], 10);
51208 findHeaderIndex : function(n){
51209 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51210 return r ? this.getCellIndex(r) : false;
51213 findHeaderCell : function(n){
51214 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
51215 return r ? r : false;
51218 findRowIndex : function(n){
51222 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
51223 return r ? r.rowIndex : false;
51226 findCellIndex : function(node){
51227 var stop = this.el.dom;
51228 while(node && node != stop){
51229 if(this.findRE.test(node.className)){
51230 return this.getCellIndex(node);
51232 node = node.parentNode;
51237 getColumnId : function(index){
51238 return this.cm.getColumnId(index);
51241 getSplitters : function()
51243 if(this.splitterSelector){
51244 return Roo.DomQuery.select(this.splitterSelector);
51250 getSplitter : function(index){
51251 return this.getSplitters()[index];
51254 onRowOver : function(e, t){
51256 if((row = this.findRowIndex(t)) !== false){
51257 this.getRowComposite(row).addClass("x-grid-row-over");
51261 onRowOut : function(e, t){
51263 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
51264 this.getRowComposite(row).removeClass("x-grid-row-over");
51268 renderHeaders : function(){
51270 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
51271 var cb = [], lb = [], sb = [], lsb = [], p = {};
51272 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51273 p.cellId = "x-grid-hd-0-" + i;
51274 p.splitId = "x-grid-csplit-0-" + i;
51275 p.id = cm.getColumnId(i);
51276 p.title = cm.getColumnTooltip(i) || "";
51277 p.value = cm.getColumnHeader(i) || "";
51278 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
51279 if(!cm.isLocked(i)){
51280 cb[cb.length] = ct.apply(p);
51281 sb[sb.length] = st.apply(p);
51283 lb[lb.length] = ct.apply(p);
51284 lsb[lsb.length] = st.apply(p);
51287 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
51288 ht.apply({cells: cb.join(""), splits:sb.join("")})];
51291 updateHeaders : function(){
51292 var html = this.renderHeaders();
51293 this.lockedHd.update(html[0]);
51294 this.mainHd.update(html[1]);
51298 * Focuses the specified row.
51299 * @param {Number} row The row index
51301 focusRow : function(row)
51303 //Roo.log('GridView.focusRow');
51304 var x = this.scroller.dom.scrollLeft;
51305 this.focusCell(row, 0, false);
51306 this.scroller.dom.scrollLeft = x;
51310 * Focuses the specified cell.
51311 * @param {Number} row The row index
51312 * @param {Number} col The column index
51313 * @param {Boolean} hscroll false to disable horizontal scrolling
51315 focusCell : function(row, col, hscroll)
51317 //Roo.log('GridView.focusCell');
51318 var el = this.ensureVisible(row, col, hscroll);
51319 this.focusEl.alignTo(el, "tl-tl");
51321 this.focusEl.focus();
51323 this.focusEl.focus.defer(1, this.focusEl);
51328 * Scrolls the specified cell into view
51329 * @param {Number} row The row index
51330 * @param {Number} col The column index
51331 * @param {Boolean} hscroll false to disable horizontal scrolling
51333 ensureVisible : function(row, col, hscroll)
51335 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
51336 //return null; //disable for testing.
51337 if(typeof row != "number"){
51338 row = row.rowIndex;
51340 if(row < 0 && row >= this.ds.getCount()){
51343 col = (col !== undefined ? col : 0);
51344 var cm = this.grid.colModel;
51345 while(cm.isHidden(col)){
51349 var el = this.getCell(row, col);
51353 var c = this.scroller.dom;
51355 var ctop = parseInt(el.offsetTop, 10);
51356 var cleft = parseInt(el.offsetLeft, 10);
51357 var cbot = ctop + el.offsetHeight;
51358 var cright = cleft + el.offsetWidth;
51360 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
51361 var stop = parseInt(c.scrollTop, 10);
51362 var sleft = parseInt(c.scrollLeft, 10);
51363 var sbot = stop + ch;
51364 var sright = sleft + c.clientWidth;
51366 Roo.log('GridView.ensureVisible:' +
51368 ' c.clientHeight:' + c.clientHeight +
51369 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
51377 c.scrollTop = ctop;
51378 //Roo.log("set scrolltop to ctop DISABLE?");
51379 }else if(cbot > sbot){
51380 //Roo.log("set scrolltop to cbot-ch");
51381 c.scrollTop = cbot-ch;
51384 if(hscroll !== false){
51386 c.scrollLeft = cleft;
51387 }else if(cright > sright){
51388 c.scrollLeft = cright-c.clientWidth;
51395 updateColumns : function(){
51396 this.grid.stopEditing();
51397 var cm = this.grid.colModel, colIds = this.getColumnIds();
51398 //var totalWidth = cm.getTotalWidth();
51400 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51401 //if(cm.isHidden(i)) continue;
51402 var w = cm.getColumnWidth(i);
51403 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
51404 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
51406 this.updateSplitters();
51409 generateRules : function(cm){
51410 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
51411 Roo.util.CSS.removeStyleSheet(rulesId);
51412 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51413 var cid = cm.getColumnId(i);
51415 if(cm.config[i].align){
51416 align = 'text-align:'+cm.config[i].align+';';
51419 if(cm.isHidden(i)){
51420 hidden = 'display:none;';
51422 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
51424 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
51425 this.hdSelector, cid, " {\n", align, width, "}\n",
51426 this.tdSelector, cid, " {\n",hidden,"\n}\n",
51427 this.splitSelector, cid, " {\n", hidden , "\n}\n");
51429 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
51432 updateSplitters : function(){
51433 var cm = this.cm, s = this.getSplitters();
51434 if(s){ // splitters not created yet
51435 var pos = 0, locked = true;
51436 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
51437 if(cm.isHidden(i)) continue;
51438 var w = cm.getColumnWidth(i); // make sure it's a number
51439 if(!cm.isLocked(i) && locked){
51444 s[i].style.left = (pos-this.splitOffset) + "px";
51449 handleHiddenChange : function(colModel, colIndex, hidden){
51451 this.hideColumn(colIndex);
51453 this.unhideColumn(colIndex);
51457 hideColumn : function(colIndex){
51458 var cid = this.getColumnId(colIndex);
51459 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
51460 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
51462 this.updateHeaders();
51464 this.updateSplitters();
51468 unhideColumn : function(colIndex){
51469 var cid = this.getColumnId(colIndex);
51470 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
51471 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
51474 this.updateHeaders();
51476 this.updateSplitters();
51480 insertRows : function(dm, firstRow, lastRow, isUpdate){
51481 if(firstRow == 0 && lastRow == dm.getCount()-1){
51485 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
51487 var s = this.getScrollState();
51488 var markup = this.renderRows(firstRow, lastRow);
51489 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
51490 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
51491 this.restoreScroll(s);
51493 this.fireEvent("rowsinserted", this, firstRow, lastRow);
51494 this.syncRowHeights(firstRow, lastRow);
51495 this.stripeRows(firstRow);
51501 bufferRows : function(markup, target, index){
51502 var before = null, trows = target.rows, tbody = target.tBodies[0];
51503 if(index < trows.length){
51504 before = trows[index];
51506 var b = document.createElement("div");
51507 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
51508 var rows = b.firstChild.rows;
51509 for(var i = 0, len = rows.length; i < len; i++){
51511 tbody.insertBefore(rows[0], before);
51513 tbody.appendChild(rows[0]);
51520 deleteRows : function(dm, firstRow, lastRow){
51521 if(dm.getRowCount()<1){
51522 this.fireEvent("beforerefresh", this);
51523 this.mainBody.update("");
51524 this.lockedBody.update("");
51525 this.fireEvent("refresh", this);
51527 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
51528 var bt = this.getBodyTable();
51529 var tbody = bt.firstChild;
51530 var rows = bt.rows;
51531 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
51532 tbody.removeChild(rows[firstRow]);
51534 this.stripeRows(firstRow);
51535 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
51539 updateRows : function(dataSource, firstRow, lastRow){
51540 var s = this.getScrollState();
51542 this.restoreScroll(s);
51545 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
51549 this.updateHeaderSortState();
51552 getScrollState : function(){
51554 var sb = this.scroller.dom;
51555 return {left: sb.scrollLeft, top: sb.scrollTop};
51558 stripeRows : function(startRow){
51559 if(!this.grid.stripeRows || this.ds.getCount() < 1){
51562 startRow = startRow || 0;
51563 var rows = this.getBodyTable().rows;
51564 var lrows = this.getLockedTable().rows;
51565 var cls = ' x-grid-row-alt ';
51566 for(var i = startRow, len = rows.length; i < len; i++){
51567 var row = rows[i], lrow = lrows[i];
51568 var isAlt = ((i+1) % 2 == 0);
51569 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
51570 if(isAlt == hasAlt){
51574 row.className += " x-grid-row-alt";
51576 row.className = row.className.replace("x-grid-row-alt", "");
51579 lrow.className = row.className;
51584 restoreScroll : function(state){
51585 //Roo.log('GridView.restoreScroll');
51586 var sb = this.scroller.dom;
51587 sb.scrollLeft = state.left;
51588 sb.scrollTop = state.top;
51592 syncScroll : function(){
51593 //Roo.log('GridView.syncScroll');
51594 var sb = this.scroller.dom;
51595 var sh = this.mainHd.dom;
51596 var bs = this.mainBody.dom;
51597 var lv = this.lockedBody.dom;
51598 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
51599 lv.scrollTop = bs.scrollTop = sb.scrollTop;
51602 handleScroll : function(e){
51604 var sb = this.scroller.dom;
51605 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
51609 handleWheel : function(e){
51610 var d = e.getWheelDelta();
51611 this.scroller.dom.scrollTop -= d*22;
51612 // set this here to prevent jumpy scrolling on large tables
51613 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
51617 renderRows : function(startRow, endRow){
51618 // pull in all the crap needed to render rows
51619 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
51620 var colCount = cm.getColumnCount();
51622 if(ds.getCount() < 1){
51626 // build a map for all the columns
51628 for(var i = 0; i < colCount; i++){
51629 var name = cm.getDataIndex(i);
51631 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
51632 renderer : cm.getRenderer(i),
51633 id : cm.getColumnId(i),
51634 locked : cm.isLocked(i)
51638 startRow = startRow || 0;
51639 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
51641 // records to render
51642 var rs = ds.getRange(startRow, endRow);
51644 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
51647 // As much as I hate to duplicate code, this was branched because FireFox really hates
51648 // [].join("") on strings. The performance difference was substantial enough to
51649 // branch this function
51650 doRender : Roo.isGecko ?
51651 function(cs, rs, ds, startRow, colCount, stripe){
51652 var ts = this.templates, ct = ts.cell, rt = ts.row;
51654 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
51656 var hasListener = this.grid.hasListener('rowclass');
51658 for(var j = 0, len = rs.length; j < len; j++){
51659 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
51660 for(var i = 0; i < colCount; i++){
51662 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
51664 p.css = p.attr = "";
51665 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
51666 if(p.value == undefined || p.value === "") p.value = " ";
51667 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
51668 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
51670 var markup = ct.apply(p);
51678 if(stripe && ((rowIndex+1) % 2 == 0)){
51679 alt.push("x-grid-row-alt")
51682 alt.push( " x-grid-dirty-row");
51685 if(this.getRowClass){
51686 alt.push(this.getRowClass(r, rowIndex));
51692 rowIndex : rowIndex,
51695 this.grid.fireEvent('rowclass', this, rowcfg);
51696 alt.push(rowcfg.rowClass);
51698 rp.alt = alt.join(" ");
51699 lbuf+= rt.apply(rp);
51701 buf+= rt.apply(rp);
51703 return [lbuf, buf];
51705 function(cs, rs, ds, startRow, colCount, stripe){
51706 var ts = this.templates, ct = ts.cell, rt = ts.row;
51708 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
51709 var hasListener = this.grid.hasListener('rowclass');
51712 for(var j = 0, len = rs.length; j < len; j++){
51713 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
51714 for(var i = 0; i < colCount; i++){
51716 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
51718 p.css = p.attr = "";
51719 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
51720 if(p.value == undefined || p.value === "") p.value = " ";
51721 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
51722 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
51725 var markup = ct.apply(p);
51727 cb[cb.length] = markup;
51729 lcb[lcb.length] = markup;
51733 if(stripe && ((rowIndex+1) % 2 == 0)){
51734 alt.push( "x-grid-row-alt");
51737 alt.push(" x-grid-dirty-row");
51740 if(this.getRowClass){
51741 alt.push( this.getRowClass(r, rowIndex));
51747 rowIndex : rowIndex,
51750 this.grid.fireEvent('rowclass', this, rowcfg);
51751 alt.push(rowcfg.rowClass);
51753 rp.alt = alt.join(" ");
51754 rp.cells = lcb.join("");
51755 lbuf[lbuf.length] = rt.apply(rp);
51756 rp.cells = cb.join("");
51757 buf[buf.length] = rt.apply(rp);
51759 return [lbuf.join(""), buf.join("")];
51762 renderBody : function(){
51763 var markup = this.renderRows();
51764 var bt = this.templates.body;
51765 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
51769 * Refreshes the grid
51770 * @param {Boolean} headersToo
51772 refresh : function(headersToo){
51773 this.fireEvent("beforerefresh", this);
51774 this.grid.stopEditing();
51775 var result = this.renderBody();
51776 this.lockedBody.update(result[0]);
51777 this.mainBody.update(result[1]);
51778 if(headersToo === true){
51779 this.updateHeaders();
51780 this.updateColumns();
51781 this.updateSplitters();
51782 this.updateHeaderSortState();
51784 this.syncRowHeights();
51786 this.fireEvent("refresh", this);
51789 handleColumnMove : function(cm, oldIndex, newIndex){
51790 this.indexMap = null;
51791 var s = this.getScrollState();
51792 this.refresh(true);
51793 this.restoreScroll(s);
51794 this.afterMove(newIndex);
51797 afterMove : function(colIndex){
51798 if(this.enableMoveAnim && Roo.enableFx){
51799 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
51801 // if multisort - fix sortOrder, and reload..
51802 if (this.grid.dataSource.multiSort) {
51803 // the we can call sort again..
51804 var dm = this.grid.dataSource;
51805 var cm = this.grid.colModel;
51807 for(var i = 0; i < cm.config.length; i++ ) {
51809 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
51810 continue; // dont' bother, it's not in sort list or being set.
51813 so.push(cm.config[i].dataIndex);
51816 dm.load(dm.lastOptions);
51823 updateCell : function(dm, rowIndex, dataIndex){
51824 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
51825 if(typeof colIndex == "undefined"){ // not present in grid
51828 var cm = this.grid.colModel;
51829 var cell = this.getCell(rowIndex, colIndex);
51830 var cellText = this.getCellText(rowIndex, colIndex);
51833 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
51834 id : cm.getColumnId(colIndex),
51835 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
51837 var renderer = cm.getRenderer(colIndex);
51838 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
51839 if(typeof val == "undefined" || val === "") val = " ";
51840 cellText.innerHTML = val;
51841 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
51842 this.syncRowHeights(rowIndex, rowIndex);
51845 calcColumnWidth : function(colIndex, maxRowsToMeasure){
51847 if(this.grid.autoSizeHeaders){
51848 var h = this.getHeaderCellMeasure(colIndex);
51849 maxWidth = Math.max(maxWidth, h.scrollWidth);
51852 if(this.cm.isLocked(colIndex)){
51853 tb = this.getLockedTable();
51856 tb = this.getBodyTable();
51857 index = colIndex - this.cm.getLockedCount();
51860 var rows = tb.rows;
51861 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
51862 for(var i = 0; i < stopIndex; i++){
51863 var cell = rows[i].childNodes[index].firstChild;
51864 maxWidth = Math.max(maxWidth, cell.scrollWidth);
51867 return maxWidth + /*margin for error in IE*/ 5;
51870 * Autofit a column to its content.
51871 * @param {Number} colIndex
51872 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
51874 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
51875 if(this.cm.isHidden(colIndex)){
51876 return; // can't calc a hidden column
51879 var cid = this.cm.getColumnId(colIndex);
51880 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
51881 if(this.grid.autoSizeHeaders){
51882 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
51885 var newWidth = this.calcColumnWidth(colIndex);
51886 this.cm.setColumnWidth(colIndex,
51887 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
51888 if(!suppressEvent){
51889 this.grid.fireEvent("columnresize", colIndex, newWidth);
51894 * Autofits all columns to their content and then expands to fit any extra space in the grid
51896 autoSizeColumns : function(){
51897 var cm = this.grid.colModel;
51898 var colCount = cm.getColumnCount();
51899 for(var i = 0; i < colCount; i++){
51900 this.autoSizeColumn(i, true, true);
51902 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
51905 this.updateColumns();
51911 * Autofits all columns to the grid's width proportionate with their current size
51912 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
51914 fitColumns : function(reserveScrollSpace){
51915 var cm = this.grid.colModel;
51916 var colCount = cm.getColumnCount();
51920 for (i = 0; i < colCount; i++){
51921 if(!cm.isHidden(i) && !cm.isFixed(i)){
51922 w = cm.getColumnWidth(i);
51928 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
51929 if(reserveScrollSpace){
51932 var frac = (avail - cm.getTotalWidth())/width;
51933 while (cols.length){
51936 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
51938 this.updateColumns();
51942 onRowSelect : function(rowIndex){
51943 var row = this.getRowComposite(rowIndex);
51944 row.addClass("x-grid-row-selected");
51947 onRowDeselect : function(rowIndex){
51948 var row = this.getRowComposite(rowIndex);
51949 row.removeClass("x-grid-row-selected");
51952 onCellSelect : function(row, col){
51953 var cell = this.getCell(row, col);
51955 Roo.fly(cell).addClass("x-grid-cell-selected");
51959 onCellDeselect : function(row, col){
51960 var cell = this.getCell(row, col);
51962 Roo.fly(cell).removeClass("x-grid-cell-selected");
51966 updateHeaderSortState : function(){
51968 // sort state can be single { field: xxx, direction : yyy}
51969 // or { xxx=>ASC , yyy : DESC ..... }
51972 if (!this.ds.multiSort) {
51973 var state = this.ds.getSortState();
51977 mstate[state.field] = state.direction;
51978 // FIXME... - this is not used here.. but might be elsewhere..
51979 this.sortState = state;
51982 mstate = this.ds.sortToggle;
51984 //remove existing sort classes..
51986 var sc = this.sortClasses;
51987 var hds = this.el.select(this.headerSelector).removeClass(sc);
51989 for(var f in mstate) {
51991 var sortColumn = this.cm.findColumnIndex(f);
51993 if(sortColumn != -1){
51994 var sortDir = mstate[f];
51995 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
52004 handleHeaderClick : function(g, index){
52005 if(this.headersDisabled){
52008 var dm = g.dataSource, cm = g.colModel;
52009 if(!cm.isSortable(index)){
52014 if (dm.multiSort) {
52015 // update the sortOrder
52017 for(var i = 0; i < cm.config.length; i++ ) {
52019 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
52020 continue; // dont' bother, it's not in sort list or being set.
52023 so.push(cm.config[i].dataIndex);
52029 dm.sort(cm.getDataIndex(index));
52033 destroy : function(){
52035 this.colMenu.removeAll();
52036 Roo.menu.MenuMgr.unregister(this.colMenu);
52037 this.colMenu.getEl().remove();
52038 delete this.colMenu;
52041 this.hmenu.removeAll();
52042 Roo.menu.MenuMgr.unregister(this.hmenu);
52043 this.hmenu.getEl().remove();
52046 if(this.grid.enableColumnMove){
52047 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52049 for(var dd in dds){
52050 if(!dds[dd].config.isTarget && dds[dd].dragElId){
52051 var elid = dds[dd].dragElId;
52053 Roo.get(elid).remove();
52054 } else if(dds[dd].config.isTarget){
52055 dds[dd].proxyTop.remove();
52056 dds[dd].proxyBottom.remove();
52059 if(Roo.dd.DDM.locationCache[dd]){
52060 delete Roo.dd.DDM.locationCache[dd];
52063 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
52066 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
52067 this.bind(null, null);
52068 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
52071 handleLockChange : function(){
52072 this.refresh(true);
52075 onDenyColumnLock : function(){
52079 onDenyColumnHide : function(){
52083 handleHdMenuClick : function(item){
52084 var index = this.hdCtxIndex;
52085 var cm = this.cm, ds = this.ds;
52088 ds.sort(cm.getDataIndex(index), "ASC");
52091 ds.sort(cm.getDataIndex(index), "DESC");
52094 var lc = cm.getLockedCount();
52095 if(cm.getColumnCount(true) <= lc+1){
52096 this.onDenyColumnLock();
52100 cm.setLocked(index, true, true);
52101 cm.moveColumn(index, lc);
52102 this.grid.fireEvent("columnmove", index, lc);
52104 cm.setLocked(index, true);
52108 var lc = cm.getLockedCount();
52109 if((lc-1) != index){
52110 cm.setLocked(index, false, true);
52111 cm.moveColumn(index, lc-1);
52112 this.grid.fireEvent("columnmove", index, lc-1);
52114 cm.setLocked(index, false);
52118 index = cm.getIndexById(item.id.substr(4));
52120 if(item.checked && cm.getColumnCount(true) <= 1){
52121 this.onDenyColumnHide();
52124 cm.setHidden(index, item.checked);
52130 beforeColMenuShow : function(){
52131 var cm = this.cm, colCount = cm.getColumnCount();
52132 this.colMenu.removeAll();
52133 for(var i = 0; i < colCount; i++){
52134 this.colMenu.add(new Roo.menu.CheckItem({
52135 id: "col-"+cm.getColumnId(i),
52136 text: cm.getColumnHeader(i),
52137 checked: !cm.isHidden(i),
52143 handleHdCtx : function(g, index, e){
52145 var hd = this.getHeaderCell(index);
52146 this.hdCtxIndex = index;
52147 var ms = this.hmenu.items, cm = this.cm;
52148 ms.get("asc").setDisabled(!cm.isSortable(index));
52149 ms.get("desc").setDisabled(!cm.isSortable(index));
52150 if(this.grid.enableColLock !== false){
52151 ms.get("lock").setDisabled(cm.isLocked(index));
52152 ms.get("unlock").setDisabled(!cm.isLocked(index));
52154 this.hmenu.show(hd, "tl-bl");
52157 handleHdOver : function(e){
52158 var hd = this.findHeaderCell(e.getTarget());
52159 if(hd && !this.headersDisabled){
52160 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
52161 this.fly(hd).addClass("x-grid-hd-over");
52166 handleHdOut : function(e){
52167 var hd = this.findHeaderCell(e.getTarget());
52169 this.fly(hd).removeClass("x-grid-hd-over");
52173 handleSplitDblClick : function(e, t){
52174 var i = this.getCellIndex(t);
52175 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
52176 this.autoSizeColumn(i, true);
52181 render : function(){
52184 var colCount = cm.getColumnCount();
52186 if(this.grid.monitorWindowResize === true){
52187 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52189 var header = this.renderHeaders();
52190 var body = this.templates.body.apply({rows:""});
52191 var html = this.templates.master.apply({
52194 lockedHeader: header[0],
52198 //this.updateColumns();
52200 this.grid.getGridEl().dom.innerHTML = html;
52202 this.initElements();
52204 // a kludge to fix the random scolling effect in webkit
52205 this.el.on("scroll", function() {
52206 this.el.dom.scrollTop=0; // hopefully not recursive..
52209 this.scroller.on("scroll", this.handleScroll, this);
52210 this.lockedBody.on("mousewheel", this.handleWheel, this);
52211 this.mainBody.on("mousewheel", this.handleWheel, this);
52213 this.mainHd.on("mouseover", this.handleHdOver, this);
52214 this.mainHd.on("mouseout", this.handleHdOut, this);
52215 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
52216 {delegate: "."+this.splitClass});
52218 this.lockedHd.on("mouseover", this.handleHdOver, this);
52219 this.lockedHd.on("mouseout", this.handleHdOut, this);
52220 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
52221 {delegate: "."+this.splitClass});
52223 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
52224 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52227 this.updateSplitters();
52229 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
52230 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52231 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
52234 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
52235 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
52237 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
52238 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
52240 if(this.grid.enableColLock !== false){
52241 this.hmenu.add('-',
52242 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
52243 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
52246 if(this.grid.enableColumnHide !== false){
52248 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
52249 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
52250 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
52252 this.hmenu.add('-',
52253 {id:"columns", text: this.columnsText, menu: this.colMenu}
52256 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
52258 this.grid.on("headercontextmenu", this.handleHdCtx, this);
52261 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
52262 this.dd = new Roo.grid.GridDragZone(this.grid, {
52263 ddGroup : this.grid.ddGroup || 'GridDD'
52269 for(var i = 0; i < colCount; i++){
52270 if(cm.isHidden(i)){
52271 this.hideColumn(i);
52273 if(cm.config[i].align){
52274 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
52275 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
52279 this.updateHeaderSortState();
52281 this.beforeInitialResize();
52284 // two part rendering gives faster view to the user
52285 this.renderPhase2.defer(1, this);
52288 renderPhase2 : function(){
52289 // render the rows now
52291 if(this.grid.autoSizeColumns){
52292 this.autoSizeColumns();
52296 beforeInitialResize : function(){
52300 onColumnSplitterMoved : function(i, w){
52301 this.userResized = true;
52302 var cm = this.grid.colModel;
52303 cm.setColumnWidth(i, w, true);
52304 var cid = cm.getColumnId(i);
52305 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52306 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
52307 this.updateSplitters();
52309 this.grid.fireEvent("columnresize", i, w);
52312 syncRowHeights : function(startIndex, endIndex){
52313 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
52314 startIndex = startIndex || 0;
52315 var mrows = this.getBodyTable().rows;
52316 var lrows = this.getLockedTable().rows;
52317 var len = mrows.length-1;
52318 endIndex = Math.min(endIndex || len, len);
52319 for(var i = startIndex; i <= endIndex; i++){
52320 var m = mrows[i], l = lrows[i];
52321 var h = Math.max(m.offsetHeight, l.offsetHeight);
52322 m.style.height = l.style.height = h + "px";
52327 layout : function(initialRender, is2ndPass){
52329 var auto = g.autoHeight;
52330 var scrollOffset = 16;
52331 var c = g.getGridEl(), cm = this.cm,
52332 expandCol = g.autoExpandColumn,
52334 //c.beginMeasure();
52336 if(!c.dom.offsetWidth){ // display:none?
52338 this.lockedWrap.show();
52339 this.mainWrap.show();
52344 var hasLock = this.cm.isLocked(0);
52346 var tbh = this.headerPanel.getHeight();
52347 var bbh = this.footerPanel.getHeight();
52350 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
52351 var newHeight = ch + c.getBorderWidth("tb");
52353 newHeight = Math.min(g.maxHeight, newHeight);
52355 c.setHeight(newHeight);
52359 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
52362 var s = this.scroller;
52364 var csize = c.getSize(true);
52366 this.el.setSize(csize.width, csize.height);
52368 this.headerPanel.setWidth(csize.width);
52369 this.footerPanel.setWidth(csize.width);
52371 var hdHeight = this.mainHd.getHeight();
52372 var vw = csize.width;
52373 var vh = csize.height - (tbh + bbh);
52377 var bt = this.getBodyTable();
52378 var ltWidth = hasLock ?
52379 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
52381 var scrollHeight = bt.offsetHeight;
52382 var scrollWidth = ltWidth + bt.offsetWidth;
52383 var vscroll = false, hscroll = false;
52385 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
52387 var lw = this.lockedWrap, mw = this.mainWrap;
52388 var lb = this.lockedBody, mb = this.mainBody;
52390 setTimeout(function(){
52391 var t = s.dom.offsetTop;
52392 var w = s.dom.clientWidth,
52393 h = s.dom.clientHeight;
52396 lw.setSize(ltWidth, h);
52398 mw.setLeftTop(ltWidth, t);
52399 mw.setSize(w-ltWidth, h);
52401 lb.setHeight(h-hdHeight);
52402 mb.setHeight(h-hdHeight);
52404 if(is2ndPass !== true && !gv.userResized && expandCol){
52405 // high speed resize without full column calculation
52407 var ci = cm.getIndexById(expandCol);
52409 ci = cm.findColumnIndex(expandCol);
52411 ci = Math.max(0, ci); // make sure it's got at least the first col.
52412 var expandId = cm.getColumnId(ci);
52413 var tw = cm.getTotalWidth(false);
52414 var currentWidth = cm.getColumnWidth(ci);
52415 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
52416 if(currentWidth != cw){
52417 cm.setColumnWidth(ci, cw, true);
52418 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
52419 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
52420 gv.updateSplitters();
52421 gv.layout(false, true);
52433 onWindowResize : function(){
52434 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
52440 appendFooter : function(parentEl){
52444 sortAscText : "Sort Ascending",
52445 sortDescText : "Sort Descending",
52446 lockText : "Lock Column",
52447 unlockText : "Unlock Column",
52448 columnsText : "Columns"
52452 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
52453 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
52454 this.proxy.el.addClass('x-grid3-col-dd');
52457 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
52458 handleMouseDown : function(e){
52462 callHandleMouseDown : function(e){
52463 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
52468 * Ext JS Library 1.1.1
52469 * Copyright(c) 2006-2007, Ext JS, LLC.
52471 * Originally Released Under LGPL - original licence link has changed is not relivant.
52474 * <script type="text/javascript">
52478 // This is a support class used internally by the Grid components
52479 Roo.grid.SplitDragZone = function(grid, hd, hd2){
52481 this.view = grid.getView();
52482 this.proxy = this.view.resizeProxy;
52483 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
52484 "gridSplitters" + this.grid.getGridEl().id, {
52485 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
52487 this.setHandleElId(Roo.id(hd));
52488 this.setOuterHandleElId(Roo.id(hd2));
52489 this.scroll = false;
52491 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
52492 fly: Roo.Element.fly,
52494 b4StartDrag : function(x, y){
52495 this.view.headersDisabled = true;
52496 this.proxy.setHeight(this.view.mainWrap.getHeight());
52497 var w = this.cm.getColumnWidth(this.cellIndex);
52498 var minw = Math.max(w-this.grid.minColumnWidth, 0);
52499 this.resetConstraints();
52500 this.setXConstraint(minw, 1000);
52501 this.setYConstraint(0, 0);
52502 this.minX = x - minw;
52503 this.maxX = x + 1000;
52505 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
52509 handleMouseDown : function(e){
52510 ev = Roo.EventObject.setEvent(e);
52511 var t = this.fly(ev.getTarget());
52512 if(t.hasClass("x-grid-split")){
52513 this.cellIndex = this.view.getCellIndex(t.dom);
52514 this.split = t.dom;
52515 this.cm = this.grid.colModel;
52516 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
52517 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
52522 endDrag : function(e){
52523 this.view.headersDisabled = false;
52524 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
52525 var diff = endX - this.startPos;
52526 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
52529 autoOffset : function(){
52530 this.setDelta(0,0);
52534 * Ext JS Library 1.1.1
52535 * Copyright(c) 2006-2007, Ext JS, LLC.
52537 * Originally Released Under LGPL - original licence link has changed is not relivant.
52540 * <script type="text/javascript">
52544 // This is a support class used internally by the Grid components
52545 Roo.grid.GridDragZone = function(grid, config){
52546 this.view = grid.getView();
52547 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
52548 if(this.view.lockedBody){
52549 this.setHandleElId(Roo.id(this.view.mainBody.dom));
52550 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
52552 this.scroll = false;
52554 this.ddel = document.createElement('div');
52555 this.ddel.className = 'x-grid-dd-wrap';
52558 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
52559 ddGroup : "GridDD",
52561 getDragData : function(e){
52562 var t = Roo.lib.Event.getTarget(e);
52563 var rowIndex = this.view.findRowIndex(t);
52564 var sm = this.grid.selModel;
52566 //Roo.log(rowIndex);
52568 if (sm.getSelectedCell) {
52569 // cell selection..
52570 if (!sm.getSelectedCell()) {
52573 if (rowIndex != sm.getSelectedCell()[0]) {
52579 if(rowIndex !== false){
52584 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
52586 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
52589 if (e.hasModifier()){
52590 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
52593 Roo.log("getDragData");
52598 rowIndex: rowIndex,
52599 selections:sm.getSelections ? sm.getSelections() : (
52600 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
52607 onInitDrag : function(e){
52608 var data = this.dragData;
52609 this.ddel.innerHTML = this.grid.getDragDropText();
52610 this.proxy.update(this.ddel);
52611 // fire start drag?
52614 afterRepair : function(){
52615 this.dragging = false;
52618 getRepairXY : function(e, data){
52622 onEndDrag : function(data, e){
52626 onValidDrop : function(dd, e, id){
52631 beforeInvalidDrop : function(e, id){
52636 * Ext JS Library 1.1.1
52637 * Copyright(c) 2006-2007, Ext JS, LLC.
52639 * Originally Released Under LGPL - original licence link has changed is not relivant.
52642 * <script type="text/javascript">
52647 * @class Roo.grid.ColumnModel
52648 * @extends Roo.util.Observable
52649 * This is the default implementation of a ColumnModel used by the Grid. It defines
52650 * the columns in the grid.
52653 var colModel = new Roo.grid.ColumnModel([
52654 {header: "Ticker", width: 60, sortable: true, locked: true},
52655 {header: "Company Name", width: 150, sortable: true},
52656 {header: "Market Cap.", width: 100, sortable: true},
52657 {header: "$ Sales", width: 100, sortable: true, renderer: money},
52658 {header: "Employees", width: 100, sortable: true, resizable: false}
52663 * The config options listed for this class are options which may appear in each
52664 * individual column definition.
52665 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
52667 * @param {Object} config An Array of column config objects. See this class's
52668 * config objects for details.
52670 Roo.grid.ColumnModel = function(config){
52672 * The config passed into the constructor
52674 this.config = config;
52677 // if no id, create one
52678 // if the column does not have a dataIndex mapping,
52679 // map it to the order it is in the config
52680 for(var i = 0, len = config.length; i < len; i++){
52682 if(typeof c.dataIndex == "undefined"){
52685 if(typeof c.renderer == "string"){
52686 c.renderer = Roo.util.Format[c.renderer];
52688 if(typeof c.id == "undefined"){
52691 if(c.editor && c.editor.xtype){
52692 c.editor = Roo.factory(c.editor, Roo.grid);
52694 if(c.editor && c.editor.isFormField){
52695 c.editor = new Roo.grid.GridEditor(c.editor);
52697 this.lookup[c.id] = c;
52701 * The width of columns which have no width specified (defaults to 100)
52704 this.defaultWidth = 100;
52707 * Default sortable of columns which have no sortable specified (defaults to false)
52710 this.defaultSortable = false;
52714 * @event widthchange
52715 * Fires when the width of a column changes.
52716 * @param {ColumnModel} this
52717 * @param {Number} columnIndex The column index
52718 * @param {Number} newWidth The new width
52720 "widthchange": true,
52722 * @event headerchange
52723 * Fires when the text of a header changes.
52724 * @param {ColumnModel} this
52725 * @param {Number} columnIndex The column index
52726 * @param {Number} newText The new header text
52728 "headerchange": true,
52730 * @event hiddenchange
52731 * Fires when a column is hidden or "unhidden".
52732 * @param {ColumnModel} this
52733 * @param {Number} columnIndex The column index
52734 * @param {Boolean} hidden true if hidden, false otherwise
52736 "hiddenchange": true,
52738 * @event columnmoved
52739 * Fires when a column is moved.
52740 * @param {ColumnModel} this
52741 * @param {Number} oldIndex
52742 * @param {Number} newIndex
52744 "columnmoved" : true,
52746 * @event columlockchange
52747 * Fires when a column's locked state is changed
52748 * @param {ColumnModel} this
52749 * @param {Number} colIndex
52750 * @param {Boolean} locked true if locked
52752 "columnlockchange" : true
52754 Roo.grid.ColumnModel.superclass.constructor.call(this);
52756 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
52758 * @cfg {String} header The header text to display in the Grid view.
52761 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
52762 * {@link Roo.data.Record} definition from which to draw the column's value. If not
52763 * specified, the column's index is used as an index into the Record's data Array.
52766 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
52767 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
52770 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
52771 * Defaults to the value of the {@link #defaultSortable} property.
52772 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
52775 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
52778 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
52781 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
52784 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
52787 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
52788 * given the cell's data value. See {@link #setRenderer}. If not specified, the
52789 * default renderer uses the raw data value.
52792 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
52795 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
52799 * Returns the id of the column at the specified index.
52800 * @param {Number} index The column index
52801 * @return {String} the id
52803 getColumnId : function(index){
52804 return this.config[index].id;
52808 * Returns the column for a specified id.
52809 * @param {String} id The column id
52810 * @return {Object} the column
52812 getColumnById : function(id){
52813 return this.lookup[id];
52818 * Returns the column for a specified dataIndex.
52819 * @param {String} dataIndex The column dataIndex
52820 * @return {Object|Boolean} the column or false if not found
52822 getColumnByDataIndex: function(dataIndex){
52823 var index = this.findColumnIndex(dataIndex);
52824 return index > -1 ? this.config[index] : false;
52828 * Returns the index for a specified column id.
52829 * @param {String} id The column id
52830 * @return {Number} the index, or -1 if not found
52832 getIndexById : function(id){
52833 for(var i = 0, len = this.config.length; i < len; i++){
52834 if(this.config[i].id == id){
52842 * Returns the index for a specified column dataIndex.
52843 * @param {String} dataIndex The column dataIndex
52844 * @return {Number} the index, or -1 if not found
52847 findColumnIndex : function(dataIndex){
52848 for(var i = 0, len = this.config.length; i < len; i++){
52849 if(this.config[i].dataIndex == dataIndex){
52857 moveColumn : function(oldIndex, newIndex){
52858 var c = this.config[oldIndex];
52859 this.config.splice(oldIndex, 1);
52860 this.config.splice(newIndex, 0, c);
52861 this.dataMap = null;
52862 this.fireEvent("columnmoved", this, oldIndex, newIndex);
52865 isLocked : function(colIndex){
52866 return this.config[colIndex].locked === true;
52869 setLocked : function(colIndex, value, suppressEvent){
52870 if(this.isLocked(colIndex) == value){
52873 this.config[colIndex].locked = value;
52874 if(!suppressEvent){
52875 this.fireEvent("columnlockchange", this, colIndex, value);
52879 getTotalLockedWidth : function(){
52880 var totalWidth = 0;
52881 for(var i = 0; i < this.config.length; i++){
52882 if(this.isLocked(i) && !this.isHidden(i)){
52883 this.totalWidth += this.getColumnWidth(i);
52889 getLockedCount : function(){
52890 for(var i = 0, len = this.config.length; i < len; i++){
52891 if(!this.isLocked(i)){
52898 * Returns the number of columns.
52901 getColumnCount : function(visibleOnly){
52902 if(visibleOnly === true){
52904 for(var i = 0, len = this.config.length; i < len; i++){
52905 if(!this.isHidden(i)){
52911 return this.config.length;
52915 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
52916 * @param {Function} fn
52917 * @param {Object} scope (optional)
52918 * @return {Array} result
52920 getColumnsBy : function(fn, scope){
52922 for(var i = 0, len = this.config.length; i < len; i++){
52923 var c = this.config[i];
52924 if(fn.call(scope||this, c, i) === true){
52932 * Returns true if the specified column is sortable.
52933 * @param {Number} col The column index
52934 * @return {Boolean}
52936 isSortable : function(col){
52937 if(typeof this.config[col].sortable == "undefined"){
52938 return this.defaultSortable;
52940 return this.config[col].sortable;
52944 * Returns the rendering (formatting) function defined for the column.
52945 * @param {Number} col The column index.
52946 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
52948 getRenderer : function(col){
52949 if(!this.config[col].renderer){
52950 return Roo.grid.ColumnModel.defaultRenderer;
52952 return this.config[col].renderer;
52956 * Sets the rendering (formatting) function for a column.
52957 * @param {Number} col The column index
52958 * @param {Function} fn The function to use to process the cell's raw data
52959 * to return HTML markup for the grid view. The render function is called with
52960 * the following parameters:<ul>
52961 * <li>Data value.</li>
52962 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
52963 * <li>css A CSS style string to apply to the table cell.</li>
52964 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
52965 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
52966 * <li>Row index</li>
52967 * <li>Column index</li>
52968 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
52970 setRenderer : function(col, fn){
52971 this.config[col].renderer = fn;
52975 * Returns the width for the specified column.
52976 * @param {Number} col The column index
52979 getColumnWidth : function(col){
52980 return this.config[col].width * 1 || this.defaultWidth;
52984 * Sets the width for a column.
52985 * @param {Number} col The column index
52986 * @param {Number} width The new width
52988 setColumnWidth : function(col, width, suppressEvent){
52989 this.config[col].width = width;
52990 this.totalWidth = null;
52991 if(!suppressEvent){
52992 this.fireEvent("widthchange", this, col, width);
52997 * Returns the total width of all columns.
52998 * @param {Boolean} includeHidden True to include hidden column widths
53001 getTotalWidth : function(includeHidden){
53002 if(!this.totalWidth){
53003 this.totalWidth = 0;
53004 for(var i = 0, len = this.config.length; i < len; i++){
53005 if(includeHidden || !this.isHidden(i)){
53006 this.totalWidth += this.getColumnWidth(i);
53010 return this.totalWidth;
53014 * Returns the header for the specified column.
53015 * @param {Number} col The column index
53018 getColumnHeader : function(col){
53019 return this.config[col].header;
53023 * Sets the header for a column.
53024 * @param {Number} col The column index
53025 * @param {String} header The new header
53027 setColumnHeader : function(col, header){
53028 this.config[col].header = header;
53029 this.fireEvent("headerchange", this, col, header);
53033 * Returns the tooltip for the specified column.
53034 * @param {Number} col The column index
53037 getColumnTooltip : function(col){
53038 return this.config[col].tooltip;
53041 * Sets the tooltip for a column.
53042 * @param {Number} col The column index
53043 * @param {String} tooltip The new tooltip
53045 setColumnTooltip : function(col, tooltip){
53046 this.config[col].tooltip = tooltip;
53050 * Returns the dataIndex for the specified column.
53051 * @param {Number} col The column index
53054 getDataIndex : function(col){
53055 return this.config[col].dataIndex;
53059 * Sets the dataIndex for a column.
53060 * @param {Number} col The column index
53061 * @param {Number} dataIndex The new dataIndex
53063 setDataIndex : function(col, dataIndex){
53064 this.config[col].dataIndex = dataIndex;
53070 * Returns true if the cell is editable.
53071 * @param {Number} colIndex The column index
53072 * @param {Number} rowIndex The row index
53073 * @return {Boolean}
53075 isCellEditable : function(colIndex, rowIndex){
53076 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
53080 * Returns the editor defined for the cell/column.
53081 * return false or null to disable editing.
53082 * @param {Number} colIndex The column index
53083 * @param {Number} rowIndex The row index
53086 getCellEditor : function(colIndex, rowIndex){
53087 return this.config[colIndex].editor;
53091 * Sets if a column is editable.
53092 * @param {Number} col The column index
53093 * @param {Boolean} editable True if the column is editable
53095 setEditable : function(col, editable){
53096 this.config[col].editable = editable;
53101 * Returns true if the column is hidden.
53102 * @param {Number} colIndex The column index
53103 * @return {Boolean}
53105 isHidden : function(colIndex){
53106 return this.config[colIndex].hidden;
53111 * Returns true if the column width cannot be changed
53113 isFixed : function(colIndex){
53114 return this.config[colIndex].fixed;
53118 * Returns true if the column can be resized
53119 * @return {Boolean}
53121 isResizable : function(colIndex){
53122 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
53125 * Sets if a column is hidden.
53126 * @param {Number} colIndex The column index
53127 * @param {Boolean} hidden True if the column is hidden
53129 setHidden : function(colIndex, hidden){
53130 this.config[colIndex].hidden = hidden;
53131 this.totalWidth = null;
53132 this.fireEvent("hiddenchange", this, colIndex, hidden);
53136 * Sets the editor for a column.
53137 * @param {Number} col The column index
53138 * @param {Object} editor The editor object
53140 setEditor : function(col, editor){
53141 this.config[col].editor = editor;
53145 Roo.grid.ColumnModel.defaultRenderer = function(value){
53146 if(typeof value == "string" && value.length < 1){
53152 // Alias for backwards compatibility
53153 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
53156 * Ext JS Library 1.1.1
53157 * Copyright(c) 2006-2007, Ext JS, LLC.
53159 * Originally Released Under LGPL - original licence link has changed is not relivant.
53162 * <script type="text/javascript">
53166 * @class Roo.grid.AbstractSelectionModel
53167 * @extends Roo.util.Observable
53168 * Abstract base class for grid SelectionModels. It provides the interface that should be
53169 * implemented by descendant classes. This class should not be directly instantiated.
53172 Roo.grid.AbstractSelectionModel = function(){
53173 this.locked = false;
53174 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
53177 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
53178 /** @ignore Called by the grid automatically. Do not call directly. */
53179 init : function(grid){
53185 * Locks the selections.
53188 this.locked = true;
53192 * Unlocks the selections.
53194 unlock : function(){
53195 this.locked = false;
53199 * Returns true if the selections are locked.
53200 * @return {Boolean}
53202 isLocked : function(){
53203 return this.locked;
53207 * Ext JS Library 1.1.1
53208 * Copyright(c) 2006-2007, Ext JS, LLC.
53210 * Originally Released Under LGPL - original licence link has changed is not relivant.
53213 * <script type="text/javascript">
53216 * @extends Roo.grid.AbstractSelectionModel
53217 * @class Roo.grid.RowSelectionModel
53218 * The default SelectionModel used by {@link Roo.grid.Grid}.
53219 * It supports multiple selections and keyboard selection/navigation.
53221 * @param {Object} config
53223 Roo.grid.RowSelectionModel = function(config){
53224 Roo.apply(this, config);
53225 this.selections = new Roo.util.MixedCollection(false, function(o){
53230 this.lastActive = false;
53234 * @event selectionchange
53235 * Fires when the selection changes
53236 * @param {SelectionModel} this
53238 "selectionchange" : true,
53240 * @event afterselectionchange
53241 * Fires after the selection changes (eg. by key press or clicking)
53242 * @param {SelectionModel} this
53244 "afterselectionchange" : true,
53246 * @event beforerowselect
53247 * Fires when a row is selected being selected, return false to cancel.
53248 * @param {SelectionModel} this
53249 * @param {Number} rowIndex The selected index
53250 * @param {Boolean} keepExisting False if other selections will be cleared
53252 "beforerowselect" : true,
53255 * Fires when a row is selected.
53256 * @param {SelectionModel} this
53257 * @param {Number} rowIndex The selected index
53258 * @param {Roo.data.Record} r The record
53260 "rowselect" : true,
53262 * @event rowdeselect
53263 * Fires when a row is deselected.
53264 * @param {SelectionModel} this
53265 * @param {Number} rowIndex The selected index
53267 "rowdeselect" : true
53269 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
53270 this.locked = false;
53273 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
53275 * @cfg {Boolean} singleSelect
53276 * True to allow selection of only one row at a time (defaults to false)
53278 singleSelect : false,
53281 initEvents : function(){
53283 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
53284 this.grid.on("mousedown", this.handleMouseDown, this);
53285 }else{ // allow click to work like normal
53286 this.grid.on("rowclick", this.handleDragableRowClick, this);
53289 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
53290 "up" : function(e){
53292 this.selectPrevious(e.shiftKey);
53293 }else if(this.last !== false && this.lastActive !== false){
53294 var last = this.last;
53295 this.selectRange(this.last, this.lastActive-1);
53296 this.grid.getView().focusRow(this.lastActive);
53297 if(last !== false){
53301 this.selectFirstRow();
53303 this.fireEvent("afterselectionchange", this);
53305 "down" : function(e){
53307 this.selectNext(e.shiftKey);
53308 }else if(this.last !== false && this.lastActive !== false){
53309 var last = this.last;
53310 this.selectRange(this.last, this.lastActive+1);
53311 this.grid.getView().focusRow(this.lastActive);
53312 if(last !== false){
53316 this.selectFirstRow();
53318 this.fireEvent("afterselectionchange", this);
53323 var view = this.grid.view;
53324 view.on("refresh", this.onRefresh, this);
53325 view.on("rowupdated", this.onRowUpdated, this);
53326 view.on("rowremoved", this.onRemove, this);
53330 onRefresh : function(){
53331 var ds = this.grid.dataSource, i, v = this.grid.view;
53332 var s = this.selections;
53333 s.each(function(r){
53334 if((i = ds.indexOfId(r.id)) != -1){
53343 onRemove : function(v, index, r){
53344 this.selections.remove(r);
53348 onRowUpdated : function(v, index, r){
53349 if(this.isSelected(r)){
53350 v.onRowSelect(index);
53356 * @param {Array} records The records to select
53357 * @param {Boolean} keepExisting (optional) True to keep existing selections
53359 selectRecords : function(records, keepExisting){
53361 this.clearSelections();
53363 var ds = this.grid.dataSource;
53364 for(var i = 0, len = records.length; i < len; i++){
53365 this.selectRow(ds.indexOf(records[i]), true);
53370 * Gets the number of selected rows.
53373 getCount : function(){
53374 return this.selections.length;
53378 * Selects the first row in the grid.
53380 selectFirstRow : function(){
53385 * Select the last row.
53386 * @param {Boolean} keepExisting (optional) True to keep existing selections
53388 selectLastRow : function(keepExisting){
53389 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
53393 * Selects the row immediately following the last selected row.
53394 * @param {Boolean} keepExisting (optional) True to keep existing selections
53396 selectNext : function(keepExisting){
53397 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
53398 this.selectRow(this.last+1, keepExisting);
53399 this.grid.getView().focusRow(this.last);
53404 * Selects the row that precedes the last selected row.
53405 * @param {Boolean} keepExisting (optional) True to keep existing selections
53407 selectPrevious : function(keepExisting){
53409 this.selectRow(this.last-1, keepExisting);
53410 this.grid.getView().focusRow(this.last);
53415 * Returns the selected records
53416 * @return {Array} Array of selected records
53418 getSelections : function(){
53419 return [].concat(this.selections.items);
53423 * Returns the first selected record.
53426 getSelected : function(){
53427 return this.selections.itemAt(0);
53432 * Clears all selections.
53434 clearSelections : function(fast){
53435 if(this.locked) return;
53437 var ds = this.grid.dataSource;
53438 var s = this.selections;
53439 s.each(function(r){
53440 this.deselectRow(ds.indexOfId(r.id));
53444 this.selections.clear();
53451 * Selects all rows.
53453 selectAll : function(){
53454 if(this.locked) return;
53455 this.selections.clear();
53456 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
53457 this.selectRow(i, true);
53462 * Returns True if there is a selection.
53463 * @return {Boolean}
53465 hasSelection : function(){
53466 return this.selections.length > 0;
53470 * Returns True if the specified row is selected.
53471 * @param {Number/Record} record The record or index of the record to check
53472 * @return {Boolean}
53474 isSelected : function(index){
53475 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
53476 return (r && this.selections.key(r.id) ? true : false);
53480 * Returns True if the specified record id is selected.
53481 * @param {String} id The id of record to check
53482 * @return {Boolean}
53484 isIdSelected : function(id){
53485 return (this.selections.key(id) ? true : false);
53489 handleMouseDown : function(e, t){
53490 var view = this.grid.getView(), rowIndex;
53491 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
53494 if(e.shiftKey && this.last !== false){
53495 var last = this.last;
53496 this.selectRange(last, rowIndex, e.ctrlKey);
53497 this.last = last; // reset the last
53498 view.focusRow(rowIndex);
53500 var isSelected = this.isSelected(rowIndex);
53501 if(e.button !== 0 && isSelected){
53502 view.focusRow(rowIndex);
53503 }else if(e.ctrlKey && isSelected){
53504 this.deselectRow(rowIndex);
53505 }else if(!isSelected){
53506 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
53507 view.focusRow(rowIndex);
53510 this.fireEvent("afterselectionchange", this);
53513 handleDragableRowClick : function(grid, rowIndex, e)
53515 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
53516 this.selectRow(rowIndex, false);
53517 grid.view.focusRow(rowIndex);
53518 this.fireEvent("afterselectionchange", this);
53523 * Selects multiple rows.
53524 * @param {Array} rows Array of the indexes of the row to select
53525 * @param {Boolean} keepExisting (optional) True to keep existing selections
53527 selectRows : function(rows, keepExisting){
53529 this.clearSelections();
53531 for(var i = 0, len = rows.length; i < len; i++){
53532 this.selectRow(rows[i], true);
53537 * Selects a range of rows. All rows in between startRow and endRow are also selected.
53538 * @param {Number} startRow The index of the first row in the range
53539 * @param {Number} endRow The index of the last row in the range
53540 * @param {Boolean} keepExisting (optional) True to retain existing selections
53542 selectRange : function(startRow, endRow, keepExisting){
53543 if(this.locked) return;
53545 this.clearSelections();
53547 if(startRow <= endRow){
53548 for(var i = startRow; i <= endRow; i++){
53549 this.selectRow(i, true);
53552 for(var i = startRow; i >= endRow; i--){
53553 this.selectRow(i, true);
53559 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
53560 * @param {Number} startRow The index of the first row in the range
53561 * @param {Number} endRow The index of the last row in the range
53563 deselectRange : function(startRow, endRow, preventViewNotify){
53564 if(this.locked) return;
53565 for(var i = startRow; i <= endRow; i++){
53566 this.deselectRow(i, preventViewNotify);
53572 * @param {Number} row The index of the row to select
53573 * @param {Boolean} keepExisting (optional) True to keep existing selections
53575 selectRow : function(index, keepExisting, preventViewNotify){
53576 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
53577 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
53578 if(!keepExisting || this.singleSelect){
53579 this.clearSelections();
53581 var r = this.grid.dataSource.getAt(index);
53582 this.selections.add(r);
53583 this.last = this.lastActive = index;
53584 if(!preventViewNotify){
53585 this.grid.getView().onRowSelect(index);
53587 this.fireEvent("rowselect", this, index, r);
53588 this.fireEvent("selectionchange", this);
53594 * @param {Number} row The index of the row to deselect
53596 deselectRow : function(index, preventViewNotify){
53597 if(this.locked) return;
53598 if(this.last == index){
53601 if(this.lastActive == index){
53602 this.lastActive = false;
53604 var r = this.grid.dataSource.getAt(index);
53605 this.selections.remove(r);
53606 if(!preventViewNotify){
53607 this.grid.getView().onRowDeselect(index);
53609 this.fireEvent("rowdeselect", this, index);
53610 this.fireEvent("selectionchange", this);
53614 restoreLast : function(){
53616 this.last = this._last;
53621 acceptsNav : function(row, col, cm){
53622 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53626 onEditorKey : function(field, e){
53627 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
53632 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53634 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53636 }else if(k == e.ENTER && !e.ctrlKey){
53640 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
53642 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
53644 }else if(k == e.ESC){
53648 g.startEditing(newCell[0], newCell[1]);
53653 * Ext JS Library 1.1.1
53654 * Copyright(c) 2006-2007, Ext JS, LLC.
53656 * Originally Released Under LGPL - original licence link has changed is not relivant.
53659 * <script type="text/javascript">
53662 * @class Roo.grid.CellSelectionModel
53663 * @extends Roo.grid.AbstractSelectionModel
53664 * This class provides the basic implementation for cell selection in a grid.
53666 * @param {Object} config The object containing the configuration of this model.
53667 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
53669 Roo.grid.CellSelectionModel = function(config){
53670 Roo.apply(this, config);
53672 this.selection = null;
53676 * @event beforerowselect
53677 * Fires before a cell is selected.
53678 * @param {SelectionModel} this
53679 * @param {Number} rowIndex The selected row index
53680 * @param {Number} colIndex The selected cell index
53682 "beforecellselect" : true,
53684 * @event cellselect
53685 * Fires when a cell is selected.
53686 * @param {SelectionModel} this
53687 * @param {Number} rowIndex The selected row index
53688 * @param {Number} colIndex The selected cell index
53690 "cellselect" : true,
53692 * @event selectionchange
53693 * Fires when the active selection changes.
53694 * @param {SelectionModel} this
53695 * @param {Object} selection null for no selection or an object (o) with two properties
53697 <li>o.record: the record object for the row the selection is in</li>
53698 <li>o.cell: An array of [rowIndex, columnIndex]</li>
53701 "selectionchange" : true,
53704 * Fires when the tab (or enter) was pressed on the last editable cell
53705 * You can use this to trigger add new row.
53706 * @param {SelectionModel} this
53710 * @event beforeeditnext
53711 * Fires before the next editable sell is made active
53712 * You can use this to skip to another cell or fire the tabend
53713 * if you set cell to false
53714 * @param {Object} eventdata object : { cell : [ row, col ] }
53716 "beforeeditnext" : true
53718 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
53721 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
53723 enter_is_tab: false,
53726 initEvents : function(){
53727 this.grid.on("mousedown", this.handleMouseDown, this);
53728 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
53729 var view = this.grid.view;
53730 view.on("refresh", this.onViewChange, this);
53731 view.on("rowupdated", this.onRowUpdated, this);
53732 view.on("beforerowremoved", this.clearSelections, this);
53733 view.on("beforerowsinserted", this.clearSelections, this);
53734 if(this.grid.isEditor){
53735 this.grid.on("beforeedit", this.beforeEdit, this);
53740 beforeEdit : function(e){
53741 this.select(e.row, e.column, false, true, e.record);
53745 onRowUpdated : function(v, index, r){
53746 if(this.selection && this.selection.record == r){
53747 v.onCellSelect(index, this.selection.cell[1]);
53752 onViewChange : function(){
53753 this.clearSelections(true);
53757 * Returns the currently selected cell,.
53758 * @return {Array} The selected cell (row, column) or null if none selected.
53760 getSelectedCell : function(){
53761 return this.selection ? this.selection.cell : null;
53765 * Clears all selections.
53766 * @param {Boolean} true to prevent the gridview from being notified about the change.
53768 clearSelections : function(preventNotify){
53769 var s = this.selection;
53771 if(preventNotify !== true){
53772 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
53774 this.selection = null;
53775 this.fireEvent("selectionchange", this, null);
53780 * Returns true if there is a selection.
53781 * @return {Boolean}
53783 hasSelection : function(){
53784 return this.selection ? true : false;
53788 handleMouseDown : function(e, t){
53789 var v = this.grid.getView();
53790 if(this.isLocked()){
53793 var row = v.findRowIndex(t);
53794 var cell = v.findCellIndex(t);
53795 if(row !== false && cell !== false){
53796 this.select(row, cell);
53802 * @param {Number} rowIndex
53803 * @param {Number} collIndex
53805 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
53806 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
53807 this.clearSelections();
53808 r = r || this.grid.dataSource.getAt(rowIndex);
53811 cell : [rowIndex, colIndex]
53813 if(!preventViewNotify){
53814 var v = this.grid.getView();
53815 v.onCellSelect(rowIndex, colIndex);
53816 if(preventFocus !== true){
53817 v.focusCell(rowIndex, colIndex);
53820 this.fireEvent("cellselect", this, rowIndex, colIndex);
53821 this.fireEvent("selectionchange", this, this.selection);
53826 isSelectable : function(rowIndex, colIndex, cm){
53827 return !cm.isHidden(colIndex);
53831 handleKeyDown : function(e){
53832 //Roo.log('Cell Sel Model handleKeyDown');
53833 if(!e.isNavKeyPress()){
53836 var g = this.grid, s = this.selection;
53839 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
53841 this.select(cell[0], cell[1]);
53846 var walk = function(row, col, step){
53847 return g.walkCells(row, col, step, sm.isSelectable, sm);
53849 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
53856 // handled by onEditorKey
53857 if (g.isEditor && g.editing) {
53861 newCell = walk(r, c-1, -1);
53863 newCell = walk(r, c+1, 1);
53868 newCell = walk(r+1, c, 1);
53872 newCell = walk(r-1, c, -1);
53876 newCell = walk(r, c+1, 1);
53880 newCell = walk(r, c-1, -1);
53885 if(g.isEditor && !g.editing){
53886 g.startEditing(r, c);
53895 this.select(newCell[0], newCell[1]);
53901 acceptsNav : function(row, col, cm){
53902 return !cm.isHidden(col) && cm.isCellEditable(col, row);
53906 * @param {Number} field (not used) - as it's normally used as a listener
53907 * @param {Number} e - event - fake it by using
53909 * var e = Roo.EventObjectImpl.prototype;
53910 * e.keyCode = e.TAB
53914 onEditorKey : function(field, e){
53916 var k = e.getKey(),
53919 ed = g.activeEditor,
53921 ///Roo.log('onEditorKey' + k);
53924 if (this.enter_is_tab && k == e.ENTER) {
53930 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
53932 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53938 } else if(k == e.ENTER && !e.ctrlKey){
53941 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
53943 } else if(k == e.ESC){
53948 var ecall = { cell : newCell, forward : forward };
53949 this.fireEvent('beforeeditnext', ecall );
53950 newCell = ecall.cell;
53951 forward = ecall.forward;
53955 //Roo.log('next cell after edit');
53956 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
53957 } else if (forward) {
53958 // tabbed past last
53959 this.fireEvent.defer(100, this, ['tabend',this]);
53964 * Ext JS Library 1.1.1
53965 * Copyright(c) 2006-2007, Ext JS, LLC.
53967 * Originally Released Under LGPL - original licence link has changed is not relivant.
53970 * <script type="text/javascript">
53974 * @class Roo.grid.EditorGrid
53975 * @extends Roo.grid.Grid
53976 * Class for creating and editable grid.
53977 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
53978 * The container MUST have some type of size defined for the grid to fill. The container will be
53979 * automatically set to position relative if it isn't already.
53980 * @param {Object} dataSource The data model to bind to
53981 * @param {Object} colModel The column model with info about this grid's columns
53983 Roo.grid.EditorGrid = function(container, config){
53984 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
53985 this.getGridEl().addClass("xedit-grid");
53987 if(!this.selModel){
53988 this.selModel = new Roo.grid.CellSelectionModel();
53991 this.activeEditor = null;
53995 * @event beforeedit
53996 * Fires before cell editing is triggered. The edit event object has the following properties <br />
53997 * <ul style="padding:5px;padding-left:16px;">
53998 * <li>grid - This grid</li>
53999 * <li>record - The record being edited</li>
54000 * <li>field - The field name being edited</li>
54001 * <li>value - The value for the field being edited.</li>
54002 * <li>row - The grid row index</li>
54003 * <li>column - The grid column index</li>
54004 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54006 * @param {Object} e An edit event (see above for description)
54008 "beforeedit" : true,
54011 * Fires after a cell is edited. <br />
54012 * <ul style="padding:5px;padding-left:16px;">
54013 * <li>grid - This grid</li>
54014 * <li>record - The record being edited</li>
54015 * <li>field - The field name being edited</li>
54016 * <li>value - The value being set</li>
54017 * <li>originalValue - The original value for the field, before the edit.</li>
54018 * <li>row - The grid row index</li>
54019 * <li>column - The grid column index</li>
54021 * @param {Object} e An edit event (see above for description)
54023 "afteredit" : true,
54025 * @event validateedit
54026 * Fires after a cell is edited, but before the value is set in the record.
54027 * You can use this to modify the value being set in the field, Return false
54028 * to cancel the change. The edit event object has the following properties <br />
54029 * <ul style="padding:5px;padding-left:16px;">
54030 * <li>editor - This editor</li>
54031 * <li>grid - This grid</li>
54032 * <li>record - The record being edited</li>
54033 * <li>field - The field name being edited</li>
54034 * <li>value - The value being set</li>
54035 * <li>originalValue - The original value for the field, before the edit.</li>
54036 * <li>row - The grid row index</li>
54037 * <li>column - The grid column index</li>
54038 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
54040 * @param {Object} e An edit event (see above for description)
54042 "validateedit" : true
54044 this.on("bodyscroll", this.stopEditing, this);
54045 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
54048 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
54050 * @cfg {Number} clicksToEdit
54051 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
54058 trackMouseOver: false, // causes very odd FF errors
54060 onCellDblClick : function(g, row, col){
54061 this.startEditing(row, col);
54064 onEditComplete : function(ed, value, startValue){
54065 this.editing = false;
54066 this.activeEditor = null;
54067 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
54069 var field = this.colModel.getDataIndex(ed.col);
54074 originalValue: startValue,
54081 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
54084 if(String(value) !== String(startValue)){
54086 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
54087 r.set(field, e.value);
54088 // if we are dealing with a combo box..
54089 // then we also set the 'name' colum to be the displayField
54090 if (ed.field.displayField && ed.field.name) {
54091 r.set(ed.field.name, ed.field.el.dom.value);
54094 delete e.cancel; //?? why!!!
54095 this.fireEvent("afteredit", e);
54098 this.fireEvent("afteredit", e); // always fire it!
54100 this.view.focusCell(ed.row, ed.col);
54104 * Starts editing the specified for the specified row/column
54105 * @param {Number} rowIndex
54106 * @param {Number} colIndex
54108 startEditing : function(row, col){
54109 this.stopEditing();
54110 if(this.colModel.isCellEditable(col, row)){
54111 this.view.ensureVisible(row, col, true);
54113 var r = this.dataSource.getAt(row);
54114 var field = this.colModel.getDataIndex(col);
54115 var cell = Roo.get(this.view.getCell(row,col));
54120 value: r.data[field],
54125 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
54126 this.editing = true;
54127 var ed = this.colModel.getCellEditor(col, row);
54133 ed.render(ed.parentEl || document.body);
54139 (function(){ // complex but required for focus issues in safari, ie and opera
54143 ed.on("complete", this.onEditComplete, this, {single: true});
54144 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
54145 this.activeEditor = ed;
54146 var v = r.data[field];
54147 ed.startEdit(this.view.getCell(row, col), v);
54148 // combo's with 'displayField and name set
54149 if (ed.field.displayField && ed.field.name) {
54150 ed.field.el.dom.value = r.data[ed.field.name];
54154 }).defer(50, this);
54160 * Stops any active editing
54162 stopEditing : function(){
54163 if(this.activeEditor){
54164 this.activeEditor.completeEdit();
54166 this.activeEditor = null;
54170 * Called to get grid's drag proxy text, by default returns this.ddText.
54173 getDragDropText : function(){
54174 var count = this.selModel.getSelectedCell() ? 1 : 0;
54175 return String.format(this.ddText, count, count == 1 ? '' : 's');
54180 * Ext JS Library 1.1.1
54181 * Copyright(c) 2006-2007, Ext JS, LLC.
54183 * Originally Released Under LGPL - original licence link has changed is not relivant.
54186 * <script type="text/javascript">
54189 // private - not really -- you end up using it !
54190 // This is a support class used internally by the Grid components
54193 * @class Roo.grid.GridEditor
54194 * @extends Roo.Editor
54195 * Class for creating and editable grid elements.
54196 * @param {Object} config any settings (must include field)
54198 Roo.grid.GridEditor = function(field, config){
54199 if (!config && field.field) {
54201 field = Roo.factory(config.field, Roo.form);
54203 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
54204 field.monitorTab = false;
54207 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
54210 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
54213 alignment: "tl-tl",
54216 cls: "x-small-editor x-grid-editor",
54221 * Ext JS Library 1.1.1
54222 * Copyright(c) 2006-2007, Ext JS, LLC.
54224 * Originally Released Under LGPL - original licence link has changed is not relivant.
54227 * <script type="text/javascript">
54232 Roo.grid.PropertyRecord = Roo.data.Record.create([
54233 {name:'name',type:'string'}, 'value'
54237 Roo.grid.PropertyStore = function(grid, source){
54239 this.store = new Roo.data.Store({
54240 recordType : Roo.grid.PropertyRecord
54242 this.store.on('update', this.onUpdate, this);
54244 this.setSource(source);
54246 Roo.grid.PropertyStore.superclass.constructor.call(this);
54251 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
54252 setSource : function(o){
54254 this.store.removeAll();
54257 if(this.isEditableValue(o[k])){
54258 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
54261 this.store.loadRecords({records: data}, {}, true);
54264 onUpdate : function(ds, record, type){
54265 if(type == Roo.data.Record.EDIT){
54266 var v = record.data['value'];
54267 var oldValue = record.modified['value'];
54268 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
54269 this.source[record.id] = v;
54271 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
54278 getProperty : function(row){
54279 return this.store.getAt(row);
54282 isEditableValue: function(val){
54283 if(val && val instanceof Date){
54285 }else if(typeof val == 'object' || typeof val == 'function'){
54291 setValue : function(prop, value){
54292 this.source[prop] = value;
54293 this.store.getById(prop).set('value', value);
54296 getSource : function(){
54297 return this.source;
54301 Roo.grid.PropertyColumnModel = function(grid, store){
54304 g.PropertyColumnModel.superclass.constructor.call(this, [
54305 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
54306 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
54308 this.store = store;
54309 this.bselect = Roo.DomHelper.append(document.body, {
54310 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
54311 {tag: 'option', value: 'true', html: 'true'},
54312 {tag: 'option', value: 'false', html: 'false'}
54315 Roo.id(this.bselect);
54318 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
54319 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
54320 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
54321 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
54322 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
54324 this.renderCellDelegate = this.renderCell.createDelegate(this);
54325 this.renderPropDelegate = this.renderProp.createDelegate(this);
54328 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
54332 valueText : 'Value',
54334 dateFormat : 'm/j/Y',
54337 renderDate : function(dateVal){
54338 return dateVal.dateFormat(this.dateFormat);
54341 renderBool : function(bVal){
54342 return bVal ? 'true' : 'false';
54345 isCellEditable : function(colIndex, rowIndex){
54346 return colIndex == 1;
54349 getRenderer : function(col){
54351 this.renderCellDelegate : this.renderPropDelegate;
54354 renderProp : function(v){
54355 return this.getPropertyName(v);
54358 renderCell : function(val){
54360 if(val instanceof Date){
54361 rv = this.renderDate(val);
54362 }else if(typeof val == 'boolean'){
54363 rv = this.renderBool(val);
54365 return Roo.util.Format.htmlEncode(rv);
54368 getPropertyName : function(name){
54369 var pn = this.grid.propertyNames;
54370 return pn && pn[name] ? pn[name] : name;
54373 getCellEditor : function(colIndex, rowIndex){
54374 var p = this.store.getProperty(rowIndex);
54375 var n = p.data['name'], val = p.data['value'];
54377 if(typeof(this.grid.customEditors[n]) == 'string'){
54378 return this.editors[this.grid.customEditors[n]];
54380 if(typeof(this.grid.customEditors[n]) != 'undefined'){
54381 return this.grid.customEditors[n];
54383 if(val instanceof Date){
54384 return this.editors['date'];
54385 }else if(typeof val == 'number'){
54386 return this.editors['number'];
54387 }else if(typeof val == 'boolean'){
54388 return this.editors['boolean'];
54390 return this.editors['string'];
54396 * @class Roo.grid.PropertyGrid
54397 * @extends Roo.grid.EditorGrid
54398 * This class represents the interface of a component based property grid control.
54399 * <br><br>Usage:<pre><code>
54400 var grid = new Roo.grid.PropertyGrid("my-container-id", {
54408 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54409 * The container MUST have some type of size defined for the grid to fill. The container will be
54410 * automatically set to position relative if it isn't already.
54411 * @param {Object} config A config object that sets properties on this grid.
54413 Roo.grid.PropertyGrid = function(container, config){
54414 config = config || {};
54415 var store = new Roo.grid.PropertyStore(this);
54416 this.store = store;
54417 var cm = new Roo.grid.PropertyColumnModel(this, store);
54418 store.store.sort('name', 'ASC');
54419 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
54422 enableColLock:false,
54423 enableColumnMove:false,
54425 trackMouseOver: false,
54428 this.getGridEl().addClass('x-props-grid');
54429 this.lastEditRow = null;
54430 this.on('columnresize', this.onColumnResize, this);
54433 * @event beforepropertychange
54434 * Fires before a property changes (return false to stop?)
54435 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
54436 * @param {String} id Record Id
54437 * @param {String} newval New Value
54438 * @param {String} oldval Old Value
54440 "beforepropertychange": true,
54442 * @event propertychange
54443 * Fires after a property changes
54444 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
54445 * @param {String} id Record Id
54446 * @param {String} newval New Value
54447 * @param {String} oldval Old Value
54449 "propertychange": true
54451 this.customEditors = this.customEditors || {};
54453 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
54456 * @cfg {Object} customEditors map of colnames=> custom editors.
54457 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
54458 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
54459 * false disables editing of the field.
54463 * @cfg {Object} propertyNames map of property Names to their displayed value
54466 render : function(){
54467 Roo.grid.PropertyGrid.superclass.render.call(this);
54468 this.autoSize.defer(100, this);
54471 autoSize : function(){
54472 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
54474 this.view.fitColumns();
54478 onColumnResize : function(){
54479 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
54483 * Sets the data for the Grid
54484 * accepts a Key => Value object of all the elements avaiable.
54485 * @param {Object} data to appear in grid.
54487 setSource : function(source){
54488 this.store.setSource(source);
54492 * Gets all the data from the grid.
54493 * @return {Object} data data stored in grid
54495 getSource : function(){
54496 return this.store.getSource();
54500 * Ext JS Library 1.1.1
54501 * Copyright(c) 2006-2007, Ext JS, LLC.
54503 * Originally Released Under LGPL - original licence link has changed is not relivant.
54506 * <script type="text/javascript">
54510 * @class Roo.LoadMask
54511 * A simple utility class for generically masking elements while loading data. If the element being masked has
54512 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
54513 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
54514 * element's UpdateManager load indicator and will be destroyed after the initial load.
54516 * Create a new LoadMask
54517 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
54518 * @param {Object} config The config object
54520 Roo.LoadMask = function(el, config){
54521 this.el = Roo.get(el);
54522 Roo.apply(this, config);
54524 this.store.on('beforeload', this.onBeforeLoad, this);
54525 this.store.on('load', this.onLoad, this);
54526 this.store.on('loadexception', this.onLoadException, this);
54527 this.removeMask = false;
54529 var um = this.el.getUpdateManager();
54530 um.showLoadIndicator = false; // disable the default indicator
54531 um.on('beforeupdate', this.onBeforeLoad, this);
54532 um.on('update', this.onLoad, this);
54533 um.on('failure', this.onLoad, this);
54534 this.removeMask = true;
54538 Roo.LoadMask.prototype = {
54540 * @cfg {Boolean} removeMask
54541 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
54542 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
54545 * @cfg {String} msg
54546 * The text to display in a centered loading message box (defaults to 'Loading...')
54548 msg : 'Loading...',
54550 * @cfg {String} msgCls
54551 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
54553 msgCls : 'x-mask-loading',
54556 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
54562 * Disables the mask to prevent it from being displayed
54564 disable : function(){
54565 this.disabled = true;
54569 * Enables the mask so that it can be displayed
54571 enable : function(){
54572 this.disabled = false;
54575 onLoadException : function()
54577 Roo.log(arguments);
54579 if (typeof(arguments[3]) != 'undefined') {
54580 Roo.MessageBox.alert("Error loading",arguments[3]);
54584 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
54585 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
54594 this.el.unmask(this.removeMask);
54597 onLoad : function()
54599 this.el.unmask(this.removeMask);
54603 onBeforeLoad : function(){
54604 if(!this.disabled){
54605 this.el.mask(this.msg, this.msgCls);
54610 destroy : function(){
54612 this.store.un('beforeload', this.onBeforeLoad, this);
54613 this.store.un('load', this.onLoad, this);
54614 this.store.un('loadexception', this.onLoadException, this);
54616 var um = this.el.getUpdateManager();
54617 um.un('beforeupdate', this.onBeforeLoad, this);
54618 um.un('update', this.onLoad, this);
54619 um.un('failure', this.onLoad, this);
54624 * Ext JS Library 1.1.1
54625 * Copyright(c) 2006-2007, Ext JS, LLC.
54627 * Originally Released Under LGPL - original licence link has changed is not relivant.
54630 * <script type="text/javascript">
54635 * @class Roo.XTemplate
54636 * @extends Roo.Template
54637 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
54639 var t = new Roo.XTemplate(
54640 '<select name="{name}">',
54641 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
54645 // then append, applying the master template values
54648 * Supported features:
54653 {a_variable} - output encoded.
54654 {a_variable.format:("Y-m-d")} - call a method on the variable
54655 {a_variable:raw} - unencoded output
54656 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
54657 {a_variable:this.method_on_template(...)} - call a method on the template object.
54662 <tpl for="a_variable or condition.."></tpl>
54663 <tpl if="a_variable or condition"></tpl>
54664 <tpl exec="some javascript"></tpl>
54665 <tpl name="named_template"></tpl> (experimental)
54667 <tpl for="."></tpl> - just iterate the property..
54668 <tpl for=".."></tpl> - iterates with the parent (probably the template)
54672 Roo.XTemplate = function()
54674 Roo.XTemplate.superclass.constructor.apply(this, arguments);
54681 Roo.extend(Roo.XTemplate, Roo.Template, {
54684 * The various sub templates
54689 * basic tag replacing syntax
54692 * // you can fake an object call by doing this
54696 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
54699 * compile the template
54701 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
54704 compile: function()
54708 s = ['<tpl>', s, '</tpl>'].join('');
54710 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
54711 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
54712 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
54713 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
54714 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
54719 while(true == !!(m = s.match(re))){
54720 var forMatch = m[0].match(nameRe),
54721 ifMatch = m[0].match(ifRe),
54722 execMatch = m[0].match(execRe),
54723 namedMatch = m[0].match(namedRe),
54728 name = forMatch && forMatch[1] ? forMatch[1] : '';
54731 // if - puts fn into test..
54732 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
54734 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
54739 // exec - calls a function... returns empty if true is returned.
54740 exp = execMatch && execMatch[1] ? execMatch[1] : null;
54742 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
54750 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
54751 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
54752 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
54755 var uid = namedMatch ? namedMatch[1] : id;
54759 id: namedMatch ? namedMatch[1] : id,
54766 s = s.replace(m[0], '');
54768 s = s.replace(m[0], '{xtpl'+ id + '}');
54773 for(var i = tpls.length-1; i >= 0; --i){
54774 this.compileTpl(tpls[i]);
54775 this.tpls[tpls[i].id] = tpls[i];
54777 this.master = tpls[tpls.length-1];
54781 * same as applyTemplate, except it's done to one of the subTemplates
54782 * when using named templates, you can do:
54784 * var str = pl.applySubTemplate('your-name', values);
54787 * @param {Number} id of the template
54788 * @param {Object} values to apply to template
54789 * @param {Object} parent (normaly the instance of this object)
54791 applySubTemplate : function(id, values, parent)
54795 var t = this.tpls[id];
54799 if(t.test && !t.test.call(this, values, parent)){
54803 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
54804 Roo.log(e.toString());
54810 if(t.exec && t.exec.call(this, values, parent)){
54814 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
54815 Roo.log(e.toString());
54820 var vs = t.target ? t.target.call(this, values, parent) : values;
54821 parent = t.target ? values : parent;
54822 if(t.target && vs instanceof Array){
54824 for(var i = 0, len = vs.length; i < len; i++){
54825 buf[buf.length] = t.compiled.call(this, vs[i], parent);
54827 return buf.join('');
54829 return t.compiled.call(this, vs, parent);
54831 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
54832 Roo.log(e.toString());
54833 Roo.log(t.compiled);
54838 compileTpl : function(tpl)
54840 var fm = Roo.util.Format;
54841 var useF = this.disableFormats !== true;
54842 var sep = Roo.isGecko ? "+" : ",";
54843 var undef = function(str) {
54844 Roo.log("Property not found :" + str);
54848 var fn = function(m, name, format, args)
54850 //Roo.log(arguments);
54851 args = args ? args.replace(/\\'/g,"'") : args;
54852 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
54853 if (typeof(format) == 'undefined') {
54854 format= 'htmlEncode';
54856 if (format == 'raw' ) {
54860 if(name.substr(0, 4) == 'xtpl'){
54861 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
54864 // build an array of options to determine if value is undefined..
54866 // basically get 'xxxx.yyyy' then do
54867 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
54868 // (function () { Roo.log("Property not found"); return ''; })() :
54873 Roo.each(name.split('.'), function(st) {
54874 lookfor += (lookfor.length ? '.': '') + st;
54875 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
54878 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
54881 if(format && useF){
54883 args = args ? ',' + args : "";
54885 if(format.substr(0, 5) != "this."){
54886 format = "fm." + format + '(';
54888 format = 'this.call("'+ format.substr(5) + '", ';
54892 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
54896 // called with xxyx.yuu:(test,test)
54898 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
54900 // raw.. - :raw modifier..
54901 return "'"+ sep + udef_st + name + ")"+sep+"'";
54905 // branched to use + in gecko and [].join() in others
54907 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
54908 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
54911 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
54912 body.push(tpl.body.replace(/(\r\n|\n)/g,
54913 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
54914 body.push("'].join('');};};");
54915 body = body.join('');
54918 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
54920 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
54926 applyTemplate : function(values){
54927 return this.master.compiled.call(this, values, {});
54928 //var s = this.subs;
54931 apply : function(){
54932 return this.applyTemplate.apply(this, arguments);
54937 Roo.XTemplate.from = function(el){
54938 el = Roo.getDom(el);
54939 return new Roo.XTemplate(el.value || el.innerHTML);
54941 * Original code for Roojs - LGPL
54942 * <script type="text/javascript">
54946 * @class Roo.XComponent
54947 * A delayed Element creator...
54948 * Or a way to group chunks of interface together.
54950 * Mypart.xyx = new Roo.XComponent({
54952 parent : 'Mypart.xyz', // empty == document.element.!!
54956 disabled : function() {}
54958 tree : function() { // return an tree of xtype declared components
54962 xtype : 'NestedLayoutPanel',
54969 * It can be used to build a big heiracy, with parent etc.
54970 * or you can just use this to render a single compoent to a dom element
54971 * MYPART.render(Roo.Element | String(id) | dom_element )
54973 * @extends Roo.util.Observable
54975 * @param cfg {Object} configuration of component
54978 Roo.XComponent = function(cfg) {
54979 Roo.apply(this, cfg);
54983 * Fires when this the componnt is built
54984 * @param {Roo.XComponent} c the component
54989 this.region = this.region || 'center'; // default..
54990 Roo.XComponent.register(this);
54991 this.modules = false;
54992 this.el = false; // where the layout goes..
54996 Roo.extend(Roo.XComponent, Roo.util.Observable, {
54999 * The created element (with Roo.factory())
55000 * @type {Roo.Layout}
55006 * for BC - use el in new code
55007 * @type {Roo.Layout}
55013 * for BC - use el in new code
55014 * @type {Roo.Layout}
55019 * @cfg {Function|boolean} disabled
55020 * If this module is disabled by some rule, return true from the funtion
55025 * @cfg {String} parent
55026 * Name of parent element which it get xtype added to..
55031 * @cfg {String} order
55032 * Used to set the order in which elements are created (usefull for multiple tabs)
55037 * @cfg {String} name
55038 * String to display while loading.
55042 * @cfg {String} region
55043 * Region to render component to (defaults to center)
55048 * @cfg {Array} items
55049 * A single item array - the first element is the root of the tree..
55050 * It's done this way to stay compatible with the Xtype system...
55056 * The method that retuns the tree of parts that make up this compoennt
55063 * render element to dom or tree
55064 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
55067 render : function(el)
55071 var hp = this.parent ? 1 : 0;
55073 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
55074 // if parent is a '#.....' string, then let's use that..
55075 var ename = this.parent.substr(1)
55076 this.parent = false;
55077 el = Roo.get(ename);
55079 Roo.log("Warning - element can not be found :#" + ename );
55085 if (!this.parent) {
55087 el = el ? Roo.get(el) : false;
55089 // it's a top level one..
55091 el : new Roo.BorderLayout(el || document.body, {
55097 tabPosition: 'top',
55098 //resizeTabs: true,
55099 alwaysShowTabs: el && hp? false : true,
55100 hideTabs: el || !hp ? true : false,
55107 if (!this.parent.el) {
55108 // probably an old style ctor, which has been disabled.
55112 // The 'tree' method is '_tree now'
55114 var tree = this._tree ? this._tree() : this.tree();
55115 tree.region = tree.region || this.region;
55116 this.el = this.parent.el.addxtype(tree);
55117 this.fireEvent('built', this);
55119 this.panel = this.el;
55120 this.layout = this.panel.layout;
55121 this.parentLayout = this.parent.layout || false;
55127 Roo.apply(Roo.XComponent, {
55129 * @property hideProgress
55130 * true to disable the building progress bar.. usefull on single page renders.
55133 hideProgress : false,
55135 * @property buildCompleted
55136 * True when the builder has completed building the interface.
55139 buildCompleted : false,
55142 * @property topModule
55143 * the upper most module - uses document.element as it's constructor.
55150 * @property modules
55151 * array of modules to be created by registration system.
55152 * @type {Array} of Roo.XComponent
55157 * @property elmodules
55158 * array of modules to be created by which use #ID
55159 * @type {Array} of Roo.XComponent
55166 * Register components to be built later.
55168 * This solves the following issues
55169 * - Building is not done on page load, but after an authentication process has occured.
55170 * - Interface elements are registered on page load
55171 * - Parent Interface elements may not be loaded before child, so this handles that..
55178 module : 'Pman.Tab.projectMgr',
55180 parent : 'Pman.layout',
55181 disabled : false, // or use a function..
55184 * * @param {Object} details about module
55186 register : function(obj) {
55188 Roo.XComponent.event.fireEvent('register', obj);
55189 switch(typeof(obj.disabled) ) {
55195 if ( obj.disabled() ) {
55201 if (obj.disabled) {
55207 this.modules.push(obj);
55211 * convert a string to an object..
55212 * eg. 'AAA.BBB' -> finds AAA.BBB
55216 toObject : function(str)
55218 if (!str || typeof(str) == 'object') {
55221 if (str.substring(0,1) == '#') {
55225 var ar = str.split('.');
55230 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
55232 throw "Module not found : " + str;
55236 throw "Module not found : " + str;
55238 Roo.each(ar, function(e) {
55239 if (typeof(o[e]) == 'undefined') {
55240 throw "Module not found : " + str;
55251 * move modules into their correct place in the tree..
55254 preBuild : function ()
55257 Roo.each(this.modules , function (obj)
55259 Roo.XComponent.event.fireEvent('beforebuild', obj);
55261 var opar = obj.parent;
55263 obj.parent = this.toObject(opar);
55265 Roo.log("parent:toObject failed: " + e.toString());
55270 Roo.debug && Roo.log("GOT top level module");
55271 Roo.debug && Roo.log(obj);
55272 obj.modules = new Roo.util.MixedCollection(false,
55273 function(o) { return o.order + '' }
55275 this.topModule = obj;
55278 // parent is a string (usually a dom element name..)
55279 if (typeof(obj.parent) == 'string') {
55280 this.elmodules.push(obj);
55283 if (obj.parent.constructor != Roo.XComponent) {
55284 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
55286 if (!obj.parent.modules) {
55287 obj.parent.modules = new Roo.util.MixedCollection(false,
55288 function(o) { return o.order + '' }
55291 if (obj.parent.disabled) {
55292 obj.disabled = true;
55294 obj.parent.modules.add(obj);
55299 * make a list of modules to build.
55300 * @return {Array} list of modules.
55303 buildOrder : function()
55306 var cmp = function(a,b) {
55307 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
55309 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
55310 throw "No top level modules to build";
55313 // make a flat list in order of modules to build.
55314 var mods = this.topModule ? [ this.topModule ] : [];
55317 // elmodules (is a list of DOM based modules )
55318 Roo.each(this.elmodules, function(e) {
55320 if (!this.topModule &&
55321 typeof(e.parent) == 'string' &&
55322 e.parent.substring(0,1) == '#' &&
55323 Roo.get(e.parent.substr(1))
55326 _this.topModule = e;
55332 // add modules to their parents..
55333 var addMod = function(m) {
55334 Roo.debug && Roo.log("build Order: add: " + m.name);
55337 if (m.modules && !m.disabled) {
55338 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
55339 m.modules.keySort('ASC', cmp );
55340 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
55342 m.modules.each(addMod);
55344 Roo.debug && Roo.log("build Order: no child modules");
55346 // not sure if this is used any more..
55348 m.finalize.name = m.name + " (clean up) ";
55349 mods.push(m.finalize);
55353 if (this.topModule && this.topModule.modules) {
55354 this.topModule.modules.keySort('ASC', cmp );
55355 this.topModule.modules.each(addMod);
55361 * Build the registered modules.
55362 * @param {Object} parent element.
55363 * @param {Function} optional method to call after module has been added.
55371 var mods = this.buildOrder();
55373 //this.allmods = mods;
55374 //Roo.debug && Roo.log(mods);
55376 if (!mods.length) { // should not happen
55377 throw "NO modules!!!";
55381 var msg = "Building Interface...";
55382 // flash it up as modal - so we store the mask!?
55383 if (!this.hideProgress) {
55384 Roo.MessageBox.show({ title: 'loading' });
55385 Roo.MessageBox.show({
55386 title: "Please wait...",
55395 var total = mods.length;
55398 var progressRun = function() {
55399 if (!mods.length) {
55400 Roo.debug && Roo.log('hide?');
55401 if (!this.hideProgress) {
55402 Roo.MessageBox.hide();
55404 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
55410 var m = mods.shift();
55413 Roo.debug && Roo.log(m);
55414 // not sure if this is supported any more.. - modules that are are just function
55415 if (typeof(m) == 'function') {
55417 return progressRun.defer(10, _this);
55421 msg = "Building Interface " + (total - mods.length) +
55423 (m.name ? (' - ' + m.name) : '');
55424 Roo.debug && Roo.log(msg);
55425 if (!this.hideProgress) {
55426 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
55430 // is the module disabled?
55431 var disabled = (typeof(m.disabled) == 'function') ?
55432 m.disabled.call(m.module.disabled) : m.disabled;
55436 return progressRun(); // we do not update the display!
55444 // it's 10 on top level, and 1 on others??? why...
55445 return progressRun.defer(10, _this);
55448 progressRun.defer(1, _this);
55462 * wrapper for event.on - aliased later..
55463 * Typically use to register a event handler for register:
55465 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
55474 Roo.XComponent.event = new Roo.util.Observable({
55478 * Fires when an Component is registered,
55479 * set the disable property on the Component to stop registration.
55480 * @param {Roo.XComponent} c the component being registerd.
55485 * @event beforebuild
55486 * Fires before each Component is built
55487 * can be used to apply permissions.
55488 * @param {Roo.XComponent} c the component being registerd.
55491 'beforebuild' : true,
55493 * @event buildcomplete
55494 * Fires on the top level element when all elements have been built
55495 * @param {Roo.XComponent} the top level component.
55497 'buildcomplete' : true
55502 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);