4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isIOS = /iphone|ipad/.test(ua),
67 isTouch = (function() {
69 document.createEvent("TouchEvent");
76 // remove css image flicker
79 document.execCommand("BackgroundImageCache", false, true);
85 * True if the browser is in strict mode
90 * True if the page is running over SSL
95 * True when the document is fully initialized and ready for action
100 * Turn on debugging output (currently only the factory uses this)
107 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
110 enableGarbageCollector : true,
113 * True to automatically purge event listeners after uncaching an element (defaults to false).
114 * Note: this only happens if enableGarbageCollector is true.
117 enableListenerCollection:false,
120 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121 * the IE insecure content warning (defaults to javascript:false).
124 SSL_SECURE_URL : "javascript:false",
127 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
131 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
133 emptyFn : function(){},
136 * Copies all the properties of config to obj if they don't already exist.
137 * @param {Object} obj The receiver of the properties
138 * @param {Object} config The source of the properties
139 * @return {Object} returns obj
141 applyIf : function(o, c){
144 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
151 * Applies event listeners to elements by selectors when the document is ready.
152 * The event name is specified with an @ suffix.
155 // add a listener for click on all anchors in element with id foo
156 '#foo a@click' : function(e, t){
160 // add the same listener to multiple selectors (separated by comma BEFORE the @)
161 '#foo a, #bar span.some-class@mouseover' : function(){
166 * @param {Object} obj The list of behaviors to apply
168 addBehaviors : function(o){
170 Roo.onReady(function(){
175 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
177 var parts = b.split('@');
178 if(parts[1]){ // for Object prototype breakers
181 cache[s] = Roo.select(s);
183 cache[s].on(parts[1], o[b]);
190 * Generates unique ids. If the element already has an id, it is unchanged
191 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193 * @return {String} The generated Id.
195 id : function(el, prefix){
196 prefix = prefix || "roo-gen";
198 var id = prefix + (++idSeed);
199 return el ? (el.id ? el.id : (el.id = id)) : id;
204 * Extends one class with another class and optionally overrides members with the passed literal. This class
205 * also adds the function "override()" to the class that can be used to override
206 * members on an instance.
207 * @param {Object} subclass The class inheriting the functionality
208 * @param {Object} superclass The class being extended
209 * @param {Object} overrides (optional) A literal with members
214 var io = function(o){
219 return function(sb, sp, overrides){
220 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
223 sb = function(){sp.apply(this, arguments);};
225 var F = function(){}, sbp, spp = sp.prototype;
227 sbp = sb.prototype = new F();
231 if(spp.constructor == Object.prototype.constructor){
236 sb.override = function(o){
240 Roo.override(sb, overrides);
246 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
248 Roo.override(MyClass, {
249 newMethod1: function(){
252 newMethod2: function(foo){
257 * @param {Object} origclass The class to override
258 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
259 * containing one or more methods.
262 override : function(origclass, overrides){
264 var p = origclass.prototype;
265 for(var method in overrides){
266 p[method] = overrides[method];
271 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
277 * @param {String} namespace1
278 * @param {String} namespace2
279 * @param {String} etc
282 namespace : function(){
283 var a=arguments, o=null, i, j, d, rt;
284 for (i=0; i<a.length; ++i) {
288 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289 for (j=1; j<d.length; ++j) {
290 o[d[j]]=o[d[j]] || {};
296 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
301 * @param {String} classname
302 * @param {String} namespace (optional)
306 factory : function(c, ns)
308 // no xtype, no ns or c.xns - or forced off by c.xns
309 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
312 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313 if (c.constructor == ns[c.xtype]) {// already created...
317 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
318 var ret = new ns[c.xtype](c);
322 c.xns = false; // prevent recursion..
326 * Logs to console if it can.
328 * @param {String|Object} string
333 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
340 * 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.
344 urlEncode : function(o){
350 var ov = o[key], k = Roo.encodeURIComponent(key);
351 var type = typeof ov;
352 if(type == 'undefined'){
354 }else if(type != "function" && type != "object"){
355 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356 }else if(ov instanceof Array){
358 for(var i = 0, len = ov.length; i < len; i++) {
359 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
370 * Safe version of encodeURIComponent
371 * @param {String} data
375 encodeURIComponent : function (data)
378 return encodeURIComponent(data);
379 } catch(e) {} // should be an uri encode error.
381 if (data == '' || data == null){
384 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385 function nibble_to_hex(nibble){
386 var chars = '0123456789ABCDEF';
387 return chars.charAt(nibble);
389 data = data.toString();
391 for(var i=0; i<data.length; i++){
392 var c = data.charCodeAt(i);
393 var bs = new Array();
396 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399 bs[3] = 0x80 | (c & 0x3F);
400 }else if (c > 0x800){
402 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404 bs[2] = 0x80 | (c & 0x3F);
407 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408 bs[1] = 0x80 | (c & 0x3F);
413 for(var j=0; j<bs.length; j++){
415 var hex = nibble_to_hex((b & 0xF0) >>> 4)
416 + nibble_to_hex(b &0x0F);
425 * 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]}.
426 * @param {String} string
427 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428 * @return {Object} A literal with members
430 urlDecode : function(string, overwrite){
431 if(!string || !string.length){
435 var pairs = string.split('&');
436 var pair, name, value;
437 for(var i = 0, len = pairs.length; i < len; i++){
438 pair = pairs[i].split('=');
439 name = decodeURIComponent(pair[0]);
440 value = decodeURIComponent(pair[1]);
441 if(overwrite !== true){
442 if(typeof obj[name] == "undefined"){
444 }else if(typeof obj[name] == "string"){
445 obj[name] = [obj[name]];
446 obj[name].push(value);
448 obj[name].push(value);
458 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459 * passed array is not really an array, your function is called once with it.
460 * The supplied function is called with (Object item, Number index, Array allItems).
461 * @param {Array/NodeList/Mixed} array
462 * @param {Function} fn
463 * @param {Object} scope
465 each : function(array, fn, scope){
466 if(typeof array.length == "undefined" || typeof array == "string"){
469 for(var i = 0, len = array.length; i < len; i++){
470 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
475 combine : function(){
476 var as = arguments, l = as.length, r = [];
477 for(var i = 0; i < l; i++){
479 if(a instanceof Array){
481 }else if(a.length !== undefined && !a.substr){
482 r = r.concat(Array.prototype.slice.call(a, 0));
491 * Escapes the passed string for use in a regular expression
492 * @param {String} str
495 escapeRe : function(s) {
496 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
500 callback : function(cb, scope, args, delay){
501 if(typeof cb == "function"){
503 cb.defer(delay, scope, args || []);
505 cb.apply(scope, args || []);
511 * Return the dom node for the passed string (id), dom node, or Roo.Element
512 * @param {String/HTMLElement/Roo.Element} el
513 * @return HTMLElement
515 getDom : function(el){
519 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
523 * Shorthand for {@link Roo.ComponentMgr#get}
525 * @return Roo.Component
527 getCmp : function(id){
528 return Roo.ComponentMgr.get(id);
531 num : function(v, defaultValue){
532 if(typeof v != 'number'){
538 destroy : function(){
539 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
543 as.removeAllListeners();
547 if(typeof as.purgeListeners == 'function'){
550 if(typeof as.destroy == 'function'){
557 // inpired by a similar function in mootools library
559 * Returns the type of object that is passed in. If the object passed in is null or undefined it
560 * return false otherwise it returns one of the following values:<ul>
561 * <li><b>string</b>: If the object passed is a string</li>
562 * <li><b>number</b>: If the object passed is a number</li>
563 * <li><b>boolean</b>: If the object passed is a boolean value</li>
564 * <li><b>function</b>: If the object passed is a function reference</li>
565 * <li><b>object</b>: If the object passed is an object</li>
566 * <li><b>array</b>: If the object passed is an array</li>
567 * <li><b>regexp</b>: If the object passed is a regular expression</li>
568 * <li><b>element</b>: If the object passed is a DOM Element</li>
569 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572 * @param {Mixed} object
576 if(o === undefined || o === null){
583 if(t == 'object' && o.nodeName) {
585 case 1: return 'element';
586 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
589 if(t == 'object' || t == 'function') {
590 switch(o.constructor) {
591 case Array: return 'array';
592 case RegExp: return 'regexp';
594 if(typeof o.length == 'number' && typeof o.item == 'function') {
602 * Returns true if the passed value is null, undefined or an empty string (optional).
603 * @param {Mixed} value The value to test
604 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
607 isEmpty : function(v, allowBlank){
608 return v === null || v === undefined || (!allowBlank ? v === '' : false);
616 isFirefox : isFirefox,
626 isBorderBox : isBorderBox,
628 isWindows : isWindows,
639 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640 * you may want to set this to true.
643 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
648 * Selects a single element as a Roo Element
649 * This is about as close as you can get to jQuery's $('do crazy stuff')
650 * @param {String} selector The selector/xpath query
651 * @param {Node} root (optional) The start of the query (defaults to document).
652 * @return {Roo.Element}
654 selectNode : function(selector, root)
656 var node = Roo.DomQuery.selectNode(selector,root);
657 return node ? Roo.get(node) : new Roo.Element(false);
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
669 "Roo.bootstrap.dash");
672 * Ext JS Library 1.1.1
673 * Copyright(c) 2006-2007, Ext JS, LLC.
675 * Originally Released Under LGPL - original licence link has changed is not relivant.
678 * <script type="text/javascript">
682 // wrappedn so fnCleanup is not in global scope...
684 function fnCleanUp() {
685 var p = Function.prototype;
686 delete p.createSequence;
688 delete p.createDelegate;
689 delete p.createCallback;
690 delete p.createInterceptor;
692 window.detachEvent("onunload", fnCleanUp);
694 window.attachEvent("onunload", fnCleanUp);
701 * These functions are available on every Function object (any JavaScript function).
703 Roo.apply(Function.prototype, {
705 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707 * Will create a function that is bound to those 2 args.
708 * @return {Function} The new function
710 createCallback : function(/*args...*/){
711 // make args available, in function below
712 var args = arguments;
715 return method.apply(window, args);
720 * Creates a delegate (callback) that sets the scope to obj.
721 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722 * Will create a function that is automatically scoped to this.
723 * @param {Object} obj (optional) The object for which the scope is set
724 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726 * if a number the args are inserted at the specified position
727 * @return {Function} The new function
729 createDelegate : function(obj, args, appendArgs){
732 var callArgs = args || arguments;
733 if(appendArgs === true){
734 callArgs = Array.prototype.slice.call(arguments, 0);
735 callArgs = callArgs.concat(args);
736 }else if(typeof appendArgs == "number"){
737 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
741 return method.apply(obj || window, callArgs);
746 * Calls this function after the number of millseconds specified.
747 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748 * @param {Object} obj (optional) The object for which the scope is set
749 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751 * if a number the args are inserted at the specified position
752 * @return {Number} The timeout id that can be used with clearTimeout
754 defer : function(millis, obj, args, appendArgs){
755 var fn = this.createDelegate(obj, args, appendArgs);
757 return setTimeout(fn, millis);
763 * Create a combined function call sequence of the original function + the passed function.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function
766 * @param {Function} fcn The function to sequence
767 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768 * @return {Function} The new function
770 createSequence : function(fcn, scope){
771 if(typeof fcn != "function"){
776 var retval = method.apply(this || window, arguments);
777 fcn.apply(scope || this || window, arguments);
783 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784 * The resulting function returns the results of the original function.
785 * The passed fcn is called with the parameters of the original function.
787 * @param {Function} fcn The function to call before the original
788 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789 * @return {Function} The new function
791 createInterceptor : function(fcn, scope){
792 if(typeof fcn != "function"){
799 if(fcn.apply(scope || this || window, arguments) === false){
802 return method.apply(this || window, arguments);
808 * Ext JS Library 1.1.1
809 * Copyright(c) 2006-2007, Ext JS, LLC.
811 * Originally Released Under LGPL - original licence link has changed is not relivant.
814 * <script type="text/javascript">
817 Roo.applyIf(String, {
822 * Escapes the passed string for ' and \
823 * @param {String} string The string to escape
824 * @return {String} The escaped string
827 escape : function(string) {
828 return string.replace(/('|\\)/g, "\\$1");
832 * Pads the left side of a string with a specified character. This is especially useful
833 * for normalizing number and date strings. Example usage:
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
838 * @param {String} string The original string
839 * @param {Number} size The total length of the output string
840 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841 * @return {String} The padded string
844 leftPad : function (val, size, ch) {
845 var result = new String(val);
846 if(ch === null || ch === undefined || ch === '') {
849 while (result.length < size) {
850 result = ch + result;
856 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
857 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
863 * @param {String} string The tokenized string to be formatted
864 * @param {String} value1 The value to replace token {0}
865 * @param {String} value2 Etc...
866 * @return {String} The formatted string
869 format : function(format){
870 var args = Array.prototype.slice.call(arguments, 1);
871 return format.replace(/\{(\d+)\}/g, function(m, i){
872 return Roo.util.Format.htmlEncode(args[i]);
878 * Utility function that allows you to easily switch a string between two alternating values. The passed value
879 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
880 * they are already different, the first value passed in is returned. Note that this method returns the new value
881 * but does not change the current string.
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
889 * @param {String} value The value to compare to the current string
890 * @param {String} other The new value to use if the string already equals the first value passed in
891 * @return {String} The new value
894 String.prototype.toggle = function(value, other){
895 return this == value ? other : value;
898 * Ext JS Library 1.1.1
899 * Copyright(c) 2006-2007, Ext JS, LLC.
901 * Originally Released Under LGPL - original licence link has changed is not relivant.
904 * <script type="text/javascript">
910 Roo.applyIf(Number.prototype, {
912 * Checks whether or not the current number is within a desired range. If the number is already within the
913 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914 * exceeded. Note that this method returns the constrained value but does not change the current number.
915 * @param {Number} min The minimum number in the range
916 * @param {Number} max The maximum number in the range
917 * @return {Number} The constrained value if outside the range, otherwise the current value
919 constrain : function(min, max){
920 return Math.min(Math.max(this, min), max);
924 * Ext JS Library 1.1.1
925 * Copyright(c) 2006-2007, Ext JS, LLC.
927 * Originally Released Under LGPL - original licence link has changed is not relivant.
930 * <script type="text/javascript">
935 Roo.applyIf(Array.prototype, {
938 * Checks whether or not the specified object exists in the array.
939 * @param {Object} o The object to check for
940 * @return {Number} The index of o in the array (or -1 if it is not found)
942 indexOf : function(o){
943 for (var i = 0, len = this.length; i < len; i++){
944 if(this[i] == o) return i;
950 * Removes the specified object from the array. If the object is not found nothing happens.
951 * @param {Object} o The object to remove
953 remove : function(o){
954 var index = this.indexOf(o);
956 this.splice(index, 1);
960 * Map (JS 1.6 compatibility)
961 * @param {Function} function to call
965 var len = this.length >>> 0;
966 if (typeof fun != "function")
967 throw new TypeError();
969 var res = new Array(len);
970 var thisp = arguments[1];
971 for (var i = 0; i < len; i++)
974 res[i] = fun.call(thisp, this[i], i, this);
985 * Ext JS Library 1.1.1
986 * Copyright(c) 2006-2007, Ext JS, LLC.
988 * Originally Released Under LGPL - original licence link has changed is not relivant.
991 * <script type="text/javascript">
997 * The date parsing and format syntax is a subset of
998 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
999 * supported will provide results equivalent to their PHP versions.
1001 * Following is the list of all currently supported formats:
1004 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1006 Format Output Description
1007 ------ ---------- --------------------------------------------------------------
1008 d 10 Day of the month, 2 digits with leading zeros
1009 D Wed A textual representation of a day, three letters
1010 j 10 Day of the month without leading zeros
1011 l Wednesday A full textual representation of the day of the week
1012 S th English ordinal day of month suffix, 2 chars (use with j)
1013 w 3 Numeric representation of the day of the week
1014 z 9 The julian date, or day of the year (0-365)
1015 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1016 F January A full textual representation of the month
1017 m 01 Numeric representation of a month, with leading zeros
1018 M Jan Month name abbreviation, three letters
1019 n 1 Numeric representation of a month, without leading zeros
1020 t 31 Number of days in the given month
1021 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1022 Y 2007 A full numeric representation of a year, 4 digits
1023 y 07 A two digit representation of a year
1024 a pm Lowercase Ante meridiem and Post meridiem
1025 A PM Uppercase Ante meridiem and Post meridiem
1026 g 3 12-hour format of an hour without leading zeros
1027 G 15 24-hour format of an hour without leading zeros
1028 h 03 12-hour format of an hour with leading zeros
1029 H 15 24-hour format of an hour with leading zeros
1030 i 05 Minutes with leading zeros
1031 s 01 Seconds, with leading zeros
1032 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1033 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1034 T CST Timezone setting of the machine running the code
1035 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1038 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1040 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1041 document.write(dt.format('Y-m-d')); //2007-01-10
1042 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1043 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
1046 * Here are some standard date/time patterns that you might find helpful. They
1047 * are not part of the source of Date.js, but to use them you can simply copy this
1048 * block of code into any script that is included after Date.js and they will also become
1049 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1052 ISO8601Long:"Y-m-d H:i:s",
1053 ISO8601Short:"Y-m-d",
1055 LongDate: "l, F d, Y",
1056 FullDateTime: "l, F d, Y g:i:s A",
1059 LongTime: "g:i:s A",
1060 SortableDateTime: "Y-m-d\\TH:i:s",
1061 UniversalSortableDateTime: "Y-m-d H:i:sO",
1068 var dt = new Date();
1069 document.write(dt.format(Date.patterns.ShortDate));
1074 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1075 * They generate precompiled functions from date formats instead of parsing and
1076 * processing the pattern every time you format a date. These functions are available
1077 * on every Date object (any javascript function).
1079 * The original article and download are here:
1080 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1087 Returns the number of milliseconds between this date and date
1088 @param {Date} date (optional) Defaults to now
1089 @return {Number} The diff in milliseconds
1090 @member Date getElapsed
1092 Date.prototype.getElapsed = function(date) {
1093 return Math.abs((date || new Date()).getTime()-this.getTime());
1095 // was in date file..
1099 Date.parseFunctions = {count:0};
1101 Date.parseRegexes = [];
1103 Date.formatFunctions = {count:0};
1106 Date.prototype.dateFormat = function(format) {
1107 if (Date.formatFunctions[format] == null) {
1108 Date.createNewFormat(format);
1110 var func = Date.formatFunctions[format];
1111 return this[func]();
1116 * Formats a date given the supplied format string
1117 * @param {String} format The format string
1118 * @return {String} The formatted date
1121 Date.prototype.format = Date.prototype.dateFormat;
1124 Date.createNewFormat = function(format) {
1125 var funcName = "format" + Date.formatFunctions.count++;
1126 Date.formatFunctions[format] = funcName;
1127 var code = "Date.prototype." + funcName + " = function(){return ";
1128 var special = false;
1130 for (var i = 0; i < format.length; ++i) {
1131 ch = format.charAt(i);
1132 if (!special && ch == "\\") {
1137 code += "'" + String.escape(ch) + "' + ";
1140 code += Date.getFormatCode(ch);
1143 /** eval:var:zzzzzzzzzzzzz */
1144 eval(code.substring(0, code.length - 3) + ";}");
1148 Date.getFormatCode = function(character) {
1149 switch (character) {
1151 return "String.leftPad(this.getDate(), 2, '0') + ";
1153 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1155 return "this.getDate() + ";
1157 return "Date.dayNames[this.getDay()] + ";
1159 return "this.getSuffix() + ";
1161 return "this.getDay() + ";
1163 return "this.getDayOfYear() + ";
1165 return "this.getWeekOfYear() + ";
1167 return "Date.monthNames[this.getMonth()] + ";
1169 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1171 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1173 return "(this.getMonth() + 1) + ";
1175 return "this.getDaysInMonth() + ";
1177 return "(this.isLeapYear() ? 1 : 0) + ";
1179 return "this.getFullYear() + ";
1181 return "('' + this.getFullYear()).substring(2, 4) + ";
1183 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1185 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1187 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1189 return "this.getHours() + ";
1191 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1193 return "String.leftPad(this.getHours(), 2, '0') + ";
1195 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1197 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1199 return "this.getGMTOffset() + ";
1201 return "this.getGMTColonOffset() + ";
1203 return "this.getTimezone() + ";
1205 return "(this.getTimezoneOffset() * -60) + ";
1207 return "'" + String.escape(character) + "' + ";
1212 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1213 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1214 * the date format that is not specified will default to the current date value for that part. Time parts can also
1215 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1216 * string or the parse operation will fail.
1219 //dt = Fri May 25 2007 (current date)
1220 var dt = new Date();
1222 //dt = Thu May 25 2006 (today's month/day in 2006)
1223 dt = Date.parseDate("2006", "Y");
1225 //dt = Sun Jan 15 2006 (all date parts specified)
1226 dt = Date.parseDate("2006-1-15", "Y-m-d");
1228 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1229 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1231 * @param {String} input The unparsed date as a string
1232 * @param {String} format The format the date is in
1233 * @return {Date} The parsed date
1236 Date.parseDate = function(input, format) {
1237 if (Date.parseFunctions[format] == null) {
1238 Date.createParser(format);
1240 var func = Date.parseFunctions[format];
1241 return Date[func](input);
1247 Date.createParser = function(format) {
1248 var funcName = "parse" + Date.parseFunctions.count++;
1249 var regexNum = Date.parseRegexes.length;
1250 var currentGroup = 1;
1251 Date.parseFunctions[format] = funcName;
1253 var code = "Date." + funcName + " = function(input){\n"
1254 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1255 + "var d = new Date();\n"
1256 + "y = d.getFullYear();\n"
1257 + "m = d.getMonth();\n"
1258 + "d = d.getDate();\n"
1259 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1260 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1261 + "if (results && results.length > 0) {";
1264 var special = false;
1266 for (var i = 0; i < format.length; ++i) {
1267 ch = format.charAt(i);
1268 if (!special && ch == "\\") {
1273 regex += String.escape(ch);
1276 var obj = Date.formatCodeToRegex(ch, currentGroup);
1277 currentGroup += obj.g;
1279 if (obj.g && obj.c) {
1285 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1286 + "{v = new Date(y, m, d, h, i, s);}\n"
1287 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1288 + "{v = new Date(y, m, d, h, i);}\n"
1289 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1290 + "{v = new Date(y, m, d, h);}\n"
1291 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1292 + "{v = new Date(y, m, d);}\n"
1293 + "else if (y >= 0 && m >= 0)\n"
1294 + "{v = new Date(y, m);}\n"
1295 + "else if (y >= 0)\n"
1296 + "{v = new Date(y);}\n"
1297 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1298 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1299 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1302 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1303 /** eval:var:zzzzzzzzzzzzz */
1308 Date.formatCodeToRegex = function(character, currentGroup) {
1309 switch (character) {
1313 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1316 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1317 s:"(\\d{1,2})"}; // day of month without leading zeroes
1320 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1321 s:"(\\d{2})"}; // day of month with leading zeroes
1325 s:"(?:" + Date.dayNames.join("|") + ")"};
1329 s:"(?:st|nd|rd|th)"};
1344 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1345 s:"(" + Date.monthNames.join("|") + ")"};
1348 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1349 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1352 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1353 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1356 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1357 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1368 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1372 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1373 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1377 c:"if (results[" + currentGroup + "] == 'am') {\n"
1378 + "if (h == 12) { h = 0; }\n"
1379 + "} else { if (h < 12) { h += 12; }}",
1383 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1384 + "if (h == 12) { h = 0; }\n"
1385 + "} else { if (h < 12) { h += 12; }}",
1390 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1391 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1395 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1396 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1399 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1403 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1408 "o = results[", currentGroup, "];\n",
1409 "var sn = o.substring(0,1);\n", // get + / - sign
1410 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1411 "var mn = o.substring(3,5) % 60;\n", // get minutes
1412 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1413 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1415 s:"([+\-]\\d{2,4})"};
1421 "o = results[", currentGroup, "];\n",
1422 "var sn = o.substring(0,1);\n",
1423 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1424 "var mn = o.substring(4,6) % 60;\n",
1425 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1426 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1432 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1435 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1436 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1437 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1441 s:String.escape(character)};
1446 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1447 * @return {String} The abbreviated timezone name (e.g. 'CST')
1449 Date.prototype.getTimezone = function() {
1450 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1454 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1455 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1457 Date.prototype.getGMTOffset = function() {
1458 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1464 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1465 * @return {String} 2-characters representing hours and 2-characters representing minutes
1466 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1468 Date.prototype.getGMTColonOffset = function() {
1469 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1470 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1472 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1476 * Get the numeric day number of the year, adjusted for leap year.
1477 * @return {Number} 0 through 364 (365 in leap years)
1479 Date.prototype.getDayOfYear = function() {
1481 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1482 for (var i = 0; i < this.getMonth(); ++i) {
1483 num += Date.daysInMonth[i];
1485 return num + this.getDate() - 1;
1489 * Get the string representation of the numeric week number of the year
1490 * (equivalent to the format specifier 'W').
1491 * @return {String} '00' through '52'
1493 Date.prototype.getWeekOfYear = function() {
1494 // Skip to Thursday of this week
1495 var now = this.getDayOfYear() + (4 - this.getDay());
1496 // Find the first Thursday of the year
1497 var jan1 = new Date(this.getFullYear(), 0, 1);
1498 var then = (7 - jan1.getDay() + 4);
1499 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1503 * Whether or not the current date is in a leap year.
1504 * @return {Boolean} True if the current date is in a leap year, else false
1506 Date.prototype.isLeapYear = function() {
1507 var year = this.getFullYear();
1508 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1512 * Get the first day of the current month, adjusted for leap year. The returned value
1513 * is the numeric day index within the week (0-6) which can be used in conjunction with
1514 * the {@link #monthNames} array to retrieve the textual day name.
1517 var dt = new Date('1/10/2007');
1518 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1520 * @return {Number} The day number (0-6)
1522 Date.prototype.getFirstDayOfMonth = function() {
1523 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1524 return (day < 0) ? (day + 7) : day;
1528 * Get the last day of the current month, adjusted for leap year. The returned value
1529 * is the numeric day index within the week (0-6) which can be used in conjunction with
1530 * the {@link #monthNames} array to retrieve the textual day name.
1533 var dt = new Date('1/10/2007');
1534 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1536 * @return {Number} The day number (0-6)
1538 Date.prototype.getLastDayOfMonth = function() {
1539 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1540 return (day < 0) ? (day + 7) : day;
1545 * Get the first date of this date's month
1548 Date.prototype.getFirstDateOfMonth = function() {
1549 return new Date(this.getFullYear(), this.getMonth(), 1);
1553 * Get the last date of this date's month
1556 Date.prototype.getLastDateOfMonth = function() {
1557 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1560 * Get the number of days in the current month, adjusted for leap year.
1561 * @return {Number} The number of days in the month
1563 Date.prototype.getDaysInMonth = function() {
1564 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1565 return Date.daysInMonth[this.getMonth()];
1569 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1570 * @return {String} 'st, 'nd', 'rd' or 'th'
1572 Date.prototype.getSuffix = function() {
1573 switch (this.getDate()) {
1590 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1593 * An array of textual month names.
1594 * Override these values for international dates, for example...
1595 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1614 * An array of textual day names.
1615 * Override these values for international dates, for example...
1616 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1632 Date.monthNumbers = {
1647 * Creates and returns a new Date instance with the exact same date value as the called instance.
1648 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1649 * variable will also be changed. When the intention is to create a new variable that will not
1650 * modify the original instance, you should create a clone.
1652 * Example of correctly cloning a date:
1655 var orig = new Date('10/1/2006');
1658 document.write(orig); //returns 'Thu Oct 05 2006'!
1661 var orig = new Date('10/1/2006');
1662 var copy = orig.clone();
1664 document.write(orig); //returns 'Thu Oct 01 2006'
1666 * @return {Date} The new Date instance
1668 Date.prototype.clone = function() {
1669 return new Date(this.getTime());
1673 * Clears any time information from this date
1674 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1675 @return {Date} this or the clone
1677 Date.prototype.clearTime = function(clone){
1679 return this.clone().clearTime();
1684 this.setMilliseconds(0);
1689 // safari setMonth is broken
1691 Date.brokenSetMonth = Date.prototype.setMonth;
1692 Date.prototype.setMonth = function(num){
1694 var n = Math.ceil(-num);
1695 var back_year = Math.ceil(n/12);
1696 var month = (n % 12) ? 12 - n % 12 : 0 ;
1697 this.setFullYear(this.getFullYear() - back_year);
1698 return Date.brokenSetMonth.call(this, month);
1700 return Date.brokenSetMonth.apply(this, arguments);
1705 /** Date interval constant
1709 /** Date interval constant
1713 /** Date interval constant
1717 /** Date interval constant
1721 /** Date interval constant
1725 /** Date interval constant
1729 /** Date interval constant
1735 * Provides a convenient method of performing basic date arithmetic. This method
1736 * does not modify the Date instance being called - it creates and returns
1737 * a new Date instance containing the resulting date value.
1742 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1743 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1745 //Negative values will subtract correctly:
1746 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1747 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1749 //You can even chain several calls together in one line!
1750 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1751 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1754 * @param {String} interval A valid date interval enum value
1755 * @param {Number} value The amount to add to the current date
1756 * @return {Date} The new Date instance
1758 Date.prototype.add = function(interval, value){
1759 var d = this.clone();
1760 if (!interval || value === 0) return d;
1761 switch(interval.toLowerCase()){
1763 d.setMilliseconds(this.getMilliseconds() + value);
1766 d.setSeconds(this.getSeconds() + value);
1769 d.setMinutes(this.getMinutes() + value);
1772 d.setHours(this.getHours() + value);
1775 d.setDate(this.getDate() + value);
1778 var day = this.getDate();
1780 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1783 d.setMonth(this.getMonth() + value);
1786 d.setFullYear(this.getFullYear() + value);
1793 * Ext JS Library 1.1.1
1794 * Copyright(c) 2006-2007, Ext JS, LLC.
1796 * Originally Released Under LGPL - original licence link has changed is not relivant.
1799 * <script type="text/javascript">
1803 * @class Roo.lib.Dom
1806 * Dom utils (from YIU afaik)
1811 * Get the view width
1812 * @param {Boolean} full True will get the full document, otherwise it's the view width
1813 * @return {Number} The width
1816 getViewWidth : function(full) {
1817 return full ? this.getDocumentWidth() : this.getViewportWidth();
1820 * Get the view height
1821 * @param {Boolean} full True will get the full document, otherwise it's the view height
1822 * @return {Number} The height
1824 getViewHeight : function(full) {
1825 return full ? this.getDocumentHeight() : this.getViewportHeight();
1828 getDocumentHeight: function() {
1829 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1830 return Math.max(scrollHeight, this.getViewportHeight());
1833 getDocumentWidth: function() {
1834 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1835 return Math.max(scrollWidth, this.getViewportWidth());
1838 getViewportHeight: function() {
1839 var height = self.innerHeight;
1840 var mode = document.compatMode;
1842 if ((mode || Roo.isIE) && !Roo.isOpera) {
1843 height = (mode == "CSS1Compat") ?
1844 document.documentElement.clientHeight :
1845 document.body.clientHeight;
1851 getViewportWidth: function() {
1852 var width = self.innerWidth;
1853 var mode = document.compatMode;
1855 if (mode || Roo.isIE) {
1856 width = (mode == "CSS1Compat") ?
1857 document.documentElement.clientWidth :
1858 document.body.clientWidth;
1863 isAncestor : function(p, c) {
1870 if (p.contains && !Roo.isSafari) {
1871 return p.contains(c);
1872 } else if (p.compareDocumentPosition) {
1873 return !!(p.compareDocumentPosition(c) & 16);
1875 var parent = c.parentNode;
1880 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1883 parent = parent.parentNode;
1889 getRegion : function(el) {
1890 return Roo.lib.Region.getRegion(el);
1893 getY : function(el) {
1894 return this.getXY(el)[1];
1897 getX : function(el) {
1898 return this.getXY(el)[0];
1901 getXY : function(el) {
1902 var p, pe, b, scroll, bd = document.body;
1903 el = Roo.getDom(el);
1904 var fly = Roo.lib.AnimBase.fly;
1905 if (el.getBoundingClientRect) {
1906 b = el.getBoundingClientRect();
1907 scroll = fly(document).getScroll();
1908 return [b.left + scroll.left, b.top + scroll.top];
1914 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1921 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1928 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1929 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1936 if (p != el && pe.getStyle('overflow') != 'visible') {
1944 if (Roo.isSafari && hasAbsolute) {
1949 if (Roo.isGecko && !hasAbsolute) {
1951 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1952 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1956 while (p && p != bd) {
1957 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1969 setXY : function(el, xy) {
1970 el = Roo.fly(el, '_setXY');
1972 var pts = el.translatePoints(xy);
1973 if (xy[0] !== false) {
1974 el.dom.style.left = pts.left + "px";
1976 if (xy[1] !== false) {
1977 el.dom.style.top = pts.top + "px";
1981 setX : function(el, x) {
1982 this.setXY(el, [x, false]);
1985 setY : function(el, y) {
1986 this.setXY(el, [false, y]);
1990 * Portions of this file are based on pieces of Yahoo User Interface Library
1991 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1992 * YUI licensed under the BSD License:
1993 * http://developer.yahoo.net/yui/license.txt
1994 * <script type="text/javascript">
1998 Roo.lib.Event = function() {
1999 var loadComplete = false;
2001 var unloadListeners = [];
2003 var onAvailStack = [];
2005 var lastError = null;
2018 startInterval: function() {
2019 if (!this._interval) {
2021 var callback = function() {
2022 self._tryPreloadAttach();
2024 this._interval = setInterval(callback, this.POLL_INTERVAL);
2029 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2030 onAvailStack.push({ id: p_id,
2033 override: p_override,
2034 checkReady: false });
2036 retryCount = this.POLL_RETRYS;
2037 this.startInterval();
2041 addListener: function(el, eventName, fn) {
2042 el = Roo.getDom(el);
2047 if ("unload" == eventName) {
2048 unloadListeners[unloadListeners.length] =
2049 [el, eventName, fn];
2053 var wrappedFn = function(e) {
2054 return fn(Roo.lib.Event.getEvent(e));
2057 var li = [el, eventName, fn, wrappedFn];
2059 var index = listeners.length;
2060 listeners[index] = li;
2062 this.doAdd(el, eventName, wrappedFn, false);
2068 removeListener: function(el, eventName, fn) {
2071 el = Roo.getDom(el);
2074 return this.purgeElement(el, false, eventName);
2078 if ("unload" == eventName) {
2080 for (i = 0,len = unloadListeners.length; i < len; i++) {
2081 var li = unloadListeners[i];
2084 li[1] == eventName &&
2086 unloadListeners.splice(i, 1);
2094 var cacheItem = null;
2097 var index = arguments[3];
2099 if ("undefined" == typeof index) {
2100 index = this._getCacheIndex(el, eventName, fn);
2104 cacheItem = listeners[index];
2107 if (!el || !cacheItem) {
2111 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2113 delete listeners[index][this.WFN];
2114 delete listeners[index][this.FN];
2115 listeners.splice(index, 1);
2122 getTarget: function(ev, resolveTextNode) {
2123 ev = ev.browserEvent || ev;
2124 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2125 var t = ev.target || ev.srcElement;
2126 return this.resolveTextNode(t);
2130 resolveTextNode: function(node) {
2131 if (Roo.isSafari && node && 3 == node.nodeType) {
2132 return node.parentNode;
2139 getPageX: function(ev) {
2140 ev = ev.browserEvent || ev;
2141 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2143 if (!x && 0 !== x) {
2144 x = ev.clientX || 0;
2147 x += this.getScroll()[1];
2155 getPageY: function(ev) {
2156 ev = ev.browserEvent || ev;
2157 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 if (!y && 0 !== y) {
2160 y = ev.clientY || 0;
2163 y += this.getScroll()[0];
2172 getXY: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2175 return [this.getPageX(ev), this.getPageY(ev)];
2179 getRelatedTarget: function(ev) {
2180 ev = ev.browserEvent || ev;
2181 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2182 var t = ev.relatedTarget;
2184 if (ev.type == "mouseout") {
2186 } else if (ev.type == "mouseover") {
2191 return this.resolveTextNode(t);
2195 getTime: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2199 var t = new Date().getTime();
2203 this.lastError = ex;
2212 stopEvent: function(ev) {
2213 this.stopPropagation(ev);
2214 this.preventDefault(ev);
2218 stopPropagation: function(ev) {
2219 ev = ev.browserEvent || ev;
2220 if (ev.stopPropagation) {
2221 ev.stopPropagation();
2223 ev.cancelBubble = true;
2228 preventDefault: function(ev) {
2229 ev = ev.browserEvent || ev;
2230 if(ev.preventDefault) {
2231 ev.preventDefault();
2233 ev.returnValue = false;
2238 getEvent: function(e) {
2239 var ev = e || window.event;
2241 var c = this.getEvent.caller;
2243 ev = c.arguments[0];
2244 if (ev && Event == ev.constructor) {
2254 getCharCode: function(ev) {
2255 ev = ev.browserEvent || ev;
2256 return ev.charCode || ev.keyCode || 0;
2260 _getCacheIndex: function(el, eventName, fn) {
2261 for (var i = 0,len = listeners.length; i < len; ++i) {
2262 var li = listeners[i];
2264 li[this.FN] == fn &&
2265 li[this.EL] == el &&
2266 li[this.TYPE] == eventName) {
2278 getEl: function(id) {
2279 return document.getElementById(id);
2283 clearCache: function() {
2287 _load: function(e) {
2288 loadComplete = true;
2289 var EU = Roo.lib.Event;
2293 EU.doRemove(window, "load", EU._load);
2298 _tryPreloadAttach: function() {
2307 var tryAgain = !loadComplete;
2309 tryAgain = (retryCount > 0);
2314 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2315 var item = onAvailStack[i];
2317 var el = this.getEl(item.id);
2320 if (!item.checkReady ||
2323 (document && document.body)) {
2326 if (item.override) {
2327 if (item.override === true) {
2330 scope = item.override;
2333 item.fn.call(scope, item.obj);
2334 onAvailStack[i] = null;
2337 notAvail.push(item);
2342 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2346 this.startInterval();
2348 clearInterval(this._interval);
2349 this._interval = null;
2352 this.locked = false;
2359 purgeElement: function(el, recurse, eventName) {
2360 var elListeners = this.getListeners(el, eventName);
2362 for (var i = 0,len = elListeners.length; i < len; ++i) {
2363 var l = elListeners[i];
2364 this.removeListener(el, l.type, l.fn);
2368 if (recurse && el && el.childNodes) {
2369 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2370 this.purgeElement(el.childNodes[i], recurse, eventName);
2376 getListeners: function(el, eventName) {
2377 var results = [], searchLists;
2379 searchLists = [listeners, unloadListeners];
2380 } else if (eventName == "unload") {
2381 searchLists = [unloadListeners];
2383 searchLists = [listeners];
2386 for (var j = 0; j < searchLists.length; ++j) {
2387 var searchList = searchLists[j];
2388 if (searchList && searchList.length > 0) {
2389 for (var i = 0,len = searchList.length; i < len; ++i) {
2390 var l = searchList[i];
2391 if (l && l[this.EL] === el &&
2392 (!eventName || eventName === l[this.TYPE])) {
2397 adjust: l[this.ADJ_SCOPE],
2405 return (results.length) ? results : null;
2409 _unload: function(e) {
2411 var EU = Roo.lib.Event, i, j, l, len, index;
2413 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2414 l = unloadListeners[i];
2417 if (l[EU.ADJ_SCOPE]) {
2418 if (l[EU.ADJ_SCOPE] === true) {
2421 scope = l[EU.ADJ_SCOPE];
2424 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2425 unloadListeners[i] = null;
2431 unloadListeners = null;
2433 if (listeners && listeners.length > 0) {
2434 j = listeners.length;
2437 l = listeners[index];
2439 EU.removeListener(l[EU.EL], l[EU.TYPE],
2449 EU.doRemove(window, "unload", EU._unload);
2454 getScroll: function() {
2455 var dd = document.documentElement, db = document.body;
2456 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2457 return [dd.scrollTop, dd.scrollLeft];
2459 return [db.scrollTop, db.scrollLeft];
2466 doAdd: function () {
2467 if (window.addEventListener) {
2468 return function(el, eventName, fn, capture) {
2469 el.addEventListener(eventName, fn, (capture));
2471 } else if (window.attachEvent) {
2472 return function(el, eventName, fn, capture) {
2473 el.attachEvent("on" + eventName, fn);
2482 doRemove: function() {
2483 if (window.removeEventListener) {
2484 return function (el, eventName, fn, capture) {
2485 el.removeEventListener(eventName, fn, (capture));
2487 } else if (window.detachEvent) {
2488 return function (el, eventName, fn) {
2489 el.detachEvent("on" + eventName, fn);
2501 var E = Roo.lib.Event;
2502 E.on = E.addListener;
2503 E.un = E.removeListener;
2505 if (document && document.body) {
2508 E.doAdd(window, "load", E._load);
2510 E.doAdd(window, "unload", E._unload);
2511 E._tryPreloadAttach();
2515 * Portions of this file are based on pieces of Yahoo User Interface Library
2516 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2517 * YUI licensed under the BSD License:
2518 * http://developer.yahoo.net/yui/license.txt
2519 * <script type="text/javascript">
2525 * @class Roo.lib.Ajax
2532 request : function(method, uri, cb, data, options) {
2534 var hs = options.headers;
2537 if(hs.hasOwnProperty(h)){
2538 this.initHeader(h, hs[h], false);
2542 if(options.xmlData){
2543 this.initHeader('Content-Type', 'text/xml', false);
2545 data = options.xmlData;
2549 return this.asyncRequest(method, uri, cb, data);
2552 serializeForm : function(form) {
2553 if(typeof form == 'string') {
2554 form = (document.getElementById(form) || document.forms[form]);
2557 var el, name, val, disabled, data = '', hasSubmit = false;
2558 for (var i = 0; i < form.elements.length; i++) {
2559 el = form.elements[i];
2560 disabled = form.elements[i].disabled;
2561 name = form.elements[i].name;
2562 val = form.elements[i].value;
2564 if (!disabled && name){
2568 case 'select-multiple':
2569 for (var j = 0; j < el.options.length; j++) {
2570 if (el.options[j].selected) {
2572 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2575 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2583 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2596 if(hasSubmit == false) {
2597 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2602 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2607 data = data.substr(0, data.length - 1);
2615 useDefaultHeader:true,
2617 defaultPostHeader:'application/x-www-form-urlencoded',
2619 useDefaultXhrHeader:true,
2621 defaultXhrHeader:'XMLHttpRequest',
2623 hasDefaultHeaders:true,
2635 setProgId:function(id)
2637 this.activeX.unshift(id);
2640 setDefaultPostHeader:function(b)
2642 this.useDefaultHeader = b;
2645 setDefaultXhrHeader:function(b)
2647 this.useDefaultXhrHeader = b;
2650 setPollingInterval:function(i)
2652 if (typeof i == 'number' && isFinite(i)) {
2653 this.pollInterval = i;
2657 createXhrObject:function(transactionId)
2663 http = new XMLHttpRequest();
2665 obj = { conn:http, tId:transactionId };
2669 for (var i = 0; i < this.activeX.length; ++i) {
2673 http = new ActiveXObject(this.activeX[i]);
2675 obj = { conn:http, tId:transactionId };
2688 getConnectionObject:function()
2691 var tId = this.transactionId;
2695 o = this.createXhrObject(tId);
2697 this.transactionId++;
2708 asyncRequest:function(method, uri, callback, postData)
2710 var o = this.getConnectionObject();
2716 o.conn.open(method, uri, true);
2718 if (this.useDefaultXhrHeader) {
2719 if (!this.defaultHeaders['X-Requested-With']) {
2720 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2724 if(postData && this.useDefaultHeader){
2725 this.initHeader('Content-Type', this.defaultPostHeader);
2728 if (this.hasDefaultHeaders || this.hasHeaders) {
2732 this.handleReadyState(o, callback);
2733 o.conn.send(postData || null);
2739 handleReadyState:function(o, callback)
2743 if (callback && callback.timeout) {
2745 this.timeout[o.tId] = window.setTimeout(function() {
2746 oConn.abort(o, callback, true);
2747 }, callback.timeout);
2750 this.poll[o.tId] = window.setInterval(
2752 if (o.conn && o.conn.readyState == 4) {
2753 window.clearInterval(oConn.poll[o.tId]);
2754 delete oConn.poll[o.tId];
2756 if(callback && callback.timeout) {
2757 window.clearTimeout(oConn.timeout[o.tId]);
2758 delete oConn.timeout[o.tId];
2761 oConn.handleTransactionResponse(o, callback);
2764 , this.pollInterval);
2767 handleTransactionResponse:function(o, callback, isAbort)
2771 this.releaseObject(o);
2775 var httpStatus, responseObject;
2779 if (o.conn.status !== undefined && o.conn.status != 0) {
2780 httpStatus = o.conn.status;
2792 if (httpStatus >= 200 && httpStatus < 300) {
2793 responseObject = this.createResponseObject(o, callback.argument);
2794 if (callback.success) {
2795 if (!callback.scope) {
2796 callback.success(responseObject);
2801 callback.success.apply(callback.scope, [responseObject]);
2806 switch (httpStatus) {
2814 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2815 if (callback.failure) {
2816 if (!callback.scope) {
2817 callback.failure(responseObject);
2820 callback.failure.apply(callback.scope, [responseObject]);
2825 responseObject = this.createResponseObject(o, callback.argument);
2826 if (callback.failure) {
2827 if (!callback.scope) {
2828 callback.failure(responseObject);
2831 callback.failure.apply(callback.scope, [responseObject]);
2837 this.releaseObject(o);
2838 responseObject = null;
2841 createResponseObject:function(o, callbackArg)
2848 var headerStr = o.conn.getAllResponseHeaders();
2849 var header = headerStr.split('\n');
2850 for (var i = 0; i < header.length; i++) {
2851 var delimitPos = header[i].indexOf(':');
2852 if (delimitPos != -1) {
2853 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2861 obj.status = o.conn.status;
2862 obj.statusText = o.conn.statusText;
2863 obj.getResponseHeader = headerObj;
2864 obj.getAllResponseHeaders = headerStr;
2865 obj.responseText = o.conn.responseText;
2866 obj.responseXML = o.conn.responseXML;
2868 if (typeof callbackArg !== undefined) {
2869 obj.argument = callbackArg;
2875 createExceptionObject:function(tId, callbackArg, isAbort)
2878 var COMM_ERROR = 'communication failure';
2879 var ABORT_CODE = -1;
2880 var ABORT_ERROR = 'transaction aborted';
2886 obj.status = ABORT_CODE;
2887 obj.statusText = ABORT_ERROR;
2890 obj.status = COMM_CODE;
2891 obj.statusText = COMM_ERROR;
2895 obj.argument = callbackArg;
2901 initHeader:function(label, value, isDefault)
2903 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2905 if (headerObj[label] === undefined) {
2906 headerObj[label] = value;
2911 headerObj[label] = value + "," + headerObj[label];
2915 this.hasDefaultHeaders = true;
2918 this.hasHeaders = true;
2923 setHeader:function(o)
2925 if (this.hasDefaultHeaders) {
2926 for (var prop in this.defaultHeaders) {
2927 if (this.defaultHeaders.hasOwnProperty(prop)) {
2928 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2933 if (this.hasHeaders) {
2934 for (var prop in this.headers) {
2935 if (this.headers.hasOwnProperty(prop)) {
2936 o.conn.setRequestHeader(prop, this.headers[prop]);
2940 this.hasHeaders = false;
2944 resetDefaultHeaders:function() {
2945 delete this.defaultHeaders;
2946 this.defaultHeaders = {};
2947 this.hasDefaultHeaders = false;
2950 abort:function(o, callback, isTimeout)
2952 if(this.isCallInProgress(o)) {
2954 window.clearInterval(this.poll[o.tId]);
2955 delete this.poll[o.tId];
2957 delete this.timeout[o.tId];
2960 this.handleTransactionResponse(o, callback, true);
2970 isCallInProgress:function(o)
2973 return o.conn.readyState != 4 && o.conn.readyState != 0;
2982 releaseObject:function(o)
2991 'MSXML2.XMLHTTP.3.0',
2999 * Portions of this file are based on pieces of Yahoo User Interface Library
3000 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3001 * YUI licensed under the BSD License:
3002 * http://developer.yahoo.net/yui/license.txt
3003 * <script type="text/javascript">
3007 Roo.lib.Region = function(t, r, b, l) {
3017 Roo.lib.Region.prototype = {
3018 contains : function(region) {
3019 return ( region.left >= this.left &&
3020 region.right <= this.right &&
3021 region.top >= this.top &&
3022 region.bottom <= this.bottom );
3026 getArea : function() {
3027 return ( (this.bottom - this.top) * (this.right - this.left) );
3030 intersect : function(region) {
3031 var t = Math.max(this.top, region.top);
3032 var r = Math.min(this.right, region.right);
3033 var b = Math.min(this.bottom, region.bottom);
3034 var l = Math.max(this.left, region.left);
3036 if (b >= t && r >= l) {
3037 return new Roo.lib.Region(t, r, b, l);
3042 union : function(region) {
3043 var t = Math.min(this.top, region.top);
3044 var r = Math.max(this.right, region.right);
3045 var b = Math.max(this.bottom, region.bottom);
3046 var l = Math.min(this.left, region.left);
3048 return new Roo.lib.Region(t, r, b, l);
3051 adjust : function(t, l, b, r) {
3060 Roo.lib.Region.getRegion = function(el) {
3061 var p = Roo.lib.Dom.getXY(el);
3064 var r = p[0] + el.offsetWidth;
3065 var b = p[1] + el.offsetHeight;
3068 return new Roo.lib.Region(t, r, b, l);
3071 * Portions of this file are based on pieces of Yahoo User Interface Library
3072 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073 * YUI licensed under the BSD License:
3074 * http://developer.yahoo.net/yui/license.txt
3075 * <script type="text/javascript">
3078 //@@dep Roo.lib.Region
3081 Roo.lib.Point = function(x, y) {
3082 if (x instanceof Array) {
3086 this.x = this.right = this.left = this[0] = x;
3087 this.y = this.top = this.bottom = this[1] = y;
3090 Roo.lib.Point.prototype = new Roo.lib.Region();
3092 * Portions of this file are based on pieces of Yahoo User Interface Library
3093 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094 * YUI licensed under the BSD License:
3095 * http://developer.yahoo.net/yui/license.txt
3096 * <script type="text/javascript">
3103 scroll : function(el, args, duration, easing, cb, scope) {
3104 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3107 motion : function(el, args, duration, easing, cb, scope) {
3108 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3111 color : function(el, args, duration, easing, cb, scope) {
3112 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3115 run : function(el, args, duration, easing, cb, scope, type) {
3116 type = type || Roo.lib.AnimBase;
3117 if (typeof easing == "string") {
3118 easing = Roo.lib.Easing[easing];
3120 var anim = new type(el, args, duration, easing);
3121 anim.animateX(function() {
3122 Roo.callback(cb, scope);
3128 * Portions of this file are based on pieces of Yahoo User Interface Library
3129 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3130 * YUI licensed under the BSD License:
3131 * http://developer.yahoo.net/yui/license.txt
3132 * <script type="text/javascript">
3140 if (!libFlyweight) {
3141 libFlyweight = new Roo.Element.Flyweight();
3143 libFlyweight.dom = el;
3144 return libFlyweight;
3147 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3151 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3153 this.init(el, attributes, duration, method);
3157 Roo.lib.AnimBase.fly = fly;
3161 Roo.lib.AnimBase.prototype = {
3163 toString: function() {
3164 var el = this.getEl();
3165 var id = el.id || el.tagName;
3166 return ("Anim " + id);
3170 noNegatives: /width|height|opacity|padding/i,
3171 offsetAttribute: /^((width|height)|(top|left))$/,
3172 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3173 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3177 doMethod: function(attr, start, end) {
3178 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3182 setAttribute: function(attr, val, unit) {
3183 if (this.patterns.noNegatives.test(attr)) {
3184 val = (val > 0) ? val : 0;
3187 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3191 getAttribute: function(attr) {
3192 var el = this.getEl();
3193 var val = fly(el).getStyle(attr);
3195 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3196 return parseFloat(val);
3199 var a = this.patterns.offsetAttribute.exec(attr) || [];
3200 var pos = !!( a[3] );
3201 var box = !!( a[2] );
3204 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3205 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3214 getDefaultUnit: function(attr) {
3215 if (this.patterns.defaultUnit.test(attr)) {
3222 animateX : function(callback, scope) {
3223 var f = function() {
3224 this.onComplete.removeListener(f);
3225 if (typeof callback == "function") {
3226 callback.call(scope || this, this);
3229 this.onComplete.addListener(f, this);
3234 setRuntimeAttribute: function(attr) {
3237 var attributes = this.attributes;
3239 this.runtimeAttributes[attr] = {};
3241 var isset = function(prop) {
3242 return (typeof prop !== 'undefined');
3245 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3249 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3252 if (isset(attributes[attr]['to'])) {
3253 end = attributes[attr]['to'];
3254 } else if (isset(attributes[attr]['by'])) {
3255 if (start.constructor == Array) {
3257 for (var i = 0, len = start.length; i < len; ++i) {
3258 end[i] = start[i] + attributes[attr]['by'][i];
3261 end = start + attributes[attr]['by'];
3265 this.runtimeAttributes[attr].start = start;
3266 this.runtimeAttributes[attr].end = end;
3269 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3273 init: function(el, attributes, duration, method) {
3275 var isAnimated = false;
3278 var startTime = null;
3281 var actualFrames = 0;
3284 el = Roo.getDom(el);
3287 this.attributes = attributes || {};
3290 this.duration = duration || 1;
3293 this.method = method || Roo.lib.Easing.easeNone;
3296 this.useSeconds = true;
3299 this.currentFrame = 0;
3302 this.totalFrames = Roo.lib.AnimMgr.fps;
3305 this.getEl = function() {
3310 this.isAnimated = function() {
3315 this.getStartTime = function() {
3319 this.runtimeAttributes = {};
3322 this.animate = function() {
3323 if (this.isAnimated()) {
3327 this.currentFrame = 0;
3329 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3331 Roo.lib.AnimMgr.registerElement(this);
3335 this.stop = function(finish) {
3337 this.currentFrame = this.totalFrames;
3338 this._onTween.fire();
3340 Roo.lib.AnimMgr.stop(this);
3343 var onStart = function() {
3344 this.onStart.fire();
3346 this.runtimeAttributes = {};
3347 for (var attr in this.attributes) {
3348 this.setRuntimeAttribute(attr);
3353 startTime = new Date();
3357 var onTween = function() {
3359 duration: new Date() - this.getStartTime(),
3360 currentFrame: this.currentFrame
3363 data.toString = function() {
3365 'duration: ' + data.duration +
3366 ', currentFrame: ' + data.currentFrame
3370 this.onTween.fire(data);
3372 var runtimeAttributes = this.runtimeAttributes;
3374 for (var attr in runtimeAttributes) {
3375 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3381 var onComplete = function() {
3382 var actual_duration = (new Date() - startTime) / 1000 ;
3385 duration: actual_duration,
3386 frames: actualFrames,
3387 fps: actualFrames / actual_duration
3390 data.toString = function() {
3392 'duration: ' + data.duration +
3393 ', frames: ' + data.frames +
3394 ', fps: ' + data.fps
3400 this.onComplete.fire(data);
3404 this._onStart = new Roo.util.Event(this);
3405 this.onStart = new Roo.util.Event(this);
3406 this.onTween = new Roo.util.Event(this);
3407 this._onTween = new Roo.util.Event(this);
3408 this.onComplete = new Roo.util.Event(this);
3409 this._onComplete = new Roo.util.Event(this);
3410 this._onStart.addListener(onStart);
3411 this._onTween.addListener(onTween);
3412 this._onComplete.addListener(onComplete);
3417 * Portions of this file are based on pieces of Yahoo User Interface Library
3418 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3419 * YUI licensed under the BSD License:
3420 * http://developer.yahoo.net/yui/license.txt
3421 * <script type="text/javascript">
3425 Roo.lib.AnimMgr = new function() {
3442 this.registerElement = function(tween) {
3443 queue[queue.length] = tween;
3445 tween._onStart.fire();
3450 this.unRegister = function(tween, index) {
3451 tween._onComplete.fire();
3452 index = index || getIndex(tween);
3454 queue.splice(index, 1);
3458 if (tweenCount <= 0) {
3464 this.start = function() {
3465 if (thread === null) {
3466 thread = setInterval(this.run, this.delay);
3471 this.stop = function(tween) {
3473 clearInterval(thread);
3475 for (var i = 0, len = queue.length; i < len; ++i) {
3476 if (queue[0].isAnimated()) {
3477 this.unRegister(queue[0], 0);
3486 this.unRegister(tween);
3491 this.run = function() {
3492 for (var i = 0, len = queue.length; i < len; ++i) {
3493 var tween = queue[i];
3494 if (!tween || !tween.isAnimated()) {
3498 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3500 tween.currentFrame += 1;
3502 if (tween.useSeconds) {
3503 correctFrame(tween);
3505 tween._onTween.fire();
3508 Roo.lib.AnimMgr.stop(tween, i);
3513 var getIndex = function(anim) {
3514 for (var i = 0, len = queue.length; i < len; ++i) {
3515 if (queue[i] == anim) {
3523 var correctFrame = function(tween) {
3524 var frames = tween.totalFrames;
3525 var frame = tween.currentFrame;
3526 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3527 var elapsed = (new Date() - tween.getStartTime());
3530 if (elapsed < tween.duration * 1000) {
3531 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3533 tweak = frames - (frame + 1);
3535 if (tweak > 0 && isFinite(tweak)) {
3536 if (tween.currentFrame + tweak >= frames) {
3537 tweak = frames - (frame + 1);
3540 tween.currentFrame += tweak;
3546 * Portions of this file are based on pieces of Yahoo User Interface Library
3547 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3548 * YUI licensed under the BSD License:
3549 * http://developer.yahoo.net/yui/license.txt
3550 * <script type="text/javascript">
3553 Roo.lib.Bezier = new function() {
3555 this.getPosition = function(points, t) {
3556 var n = points.length;
3559 for (var i = 0; i < n; ++i) {
3560 tmp[i] = [points[i][0], points[i][1]];
3563 for (var j = 1; j < n; ++j) {
3564 for (i = 0; i < n - j; ++i) {
3565 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3566 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3570 return [ tmp[0][0], tmp[0][1] ];
3574 * Portions of this file are based on pieces of Yahoo User Interface Library
3575 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3576 * YUI licensed under the BSD License:
3577 * http://developer.yahoo.net/yui/license.txt
3578 * <script type="text/javascript">
3583 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3584 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3587 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3589 var fly = Roo.lib.AnimBase.fly;
3591 var superclass = Y.ColorAnim.superclass;
3592 var proto = Y.ColorAnim.prototype;
3594 proto.toString = function() {
3595 var el = this.getEl();
3596 var id = el.id || el.tagName;
3597 return ("ColorAnim " + id);
3600 proto.patterns.color = /color$/i;
3601 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3602 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3603 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3604 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3607 proto.parseColor = function(s) {
3608 if (s.length == 3) {
3612 var c = this.patterns.hex.exec(s);
3613 if (c && c.length == 4) {
3614 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3617 c = this.patterns.rgb.exec(s);
3618 if (c && c.length == 4) {
3619 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3622 c = this.patterns.hex3.exec(s);
3623 if (c && c.length == 4) {
3624 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3629 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3653 proto.getAttribute = function(attr) {
3654 var el = this.getEl();
3655 if (this.patterns.color.test(attr)) {
3656 var val = fly(el).getStyle(attr);
3658 if (this.patterns.transparent.test(val)) {
3659 var parent = el.parentNode;
3660 val = fly(parent).getStyle(attr);
3662 while (parent && this.patterns.transparent.test(val)) {
3663 parent = parent.parentNode;
3664 val = fly(parent).getStyle(attr);
3665 if (parent.tagName.toUpperCase() == 'HTML') {
3671 val = superclass.getAttribute.call(this, attr);
3677 proto.doMethod = function(attr, start, end) {
3680 if (this.patterns.color.test(attr)) {
3682 for (var i = 0, len = start.length; i < len; ++i) {
3683 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3686 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3689 val = superclass.doMethod.call(this, attr, start, end);
3695 proto.setRuntimeAttribute = function(attr) {
3696 superclass.setRuntimeAttribute.call(this, attr);
3698 if (this.patterns.color.test(attr)) {
3699 var attributes = this.attributes;
3700 var start = this.parseColor(this.runtimeAttributes[attr].start);
3701 var end = this.parseColor(this.runtimeAttributes[attr].end);
3703 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3704 end = this.parseColor(attributes[attr].by);
3706 for (var i = 0, len = start.length; i < len; ++i) {
3707 end[i] = start[i] + end[i];
3711 this.runtimeAttributes[attr].start = start;
3712 this.runtimeAttributes[attr].end = end;
3718 * Portions of this file are based on pieces of Yahoo User Interface Library
3719 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3720 * YUI licensed under the BSD License:
3721 * http://developer.yahoo.net/yui/license.txt
3722 * <script type="text/javascript">
3728 easeNone: function (t, b, c, d) {
3729 return c * t / d + b;
3733 easeIn: function (t, b, c, d) {
3734 return c * (t /= d) * t + b;
3738 easeOut: function (t, b, c, d) {
3739 return -c * (t /= d) * (t - 2) + b;
3743 easeBoth: function (t, b, c, d) {
3744 if ((t /= d / 2) < 1) {
3745 return c / 2 * t * t + b;
3748 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3752 easeInStrong: function (t, b, c, d) {
3753 return c * (t /= d) * t * t * t + b;
3757 easeOutStrong: function (t, b, c, d) {
3758 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3762 easeBothStrong: function (t, b, c, d) {
3763 if ((t /= d / 2) < 1) {
3764 return c / 2 * t * t * t * t + b;
3767 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3772 elasticIn: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3795 elasticOut: function (t, b, c, d, a, p) {
3799 if ((t /= d) == 1) {
3806 if (!a || a < Math.abs(c)) {
3811 var s = p / (2 * Math.PI) * Math.asin(c / a);
3814 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3818 elasticBoth: function (t, b, c, d, a, p) {
3823 if ((t /= d / 2) == 2) {
3831 if (!a || a < Math.abs(c)) {
3836 var s = p / (2 * Math.PI) * Math.asin(c / a);
3840 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3841 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3843 return a * Math.pow(2, -10 * (t -= 1)) *
3844 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3849 backIn: function (t, b, c, d, s) {
3850 if (typeof s == 'undefined') {
3853 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3857 backOut: function (t, b, c, d, s) {
3858 if (typeof s == 'undefined') {
3861 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3865 backBoth: function (t, b, c, d, s) {
3866 if (typeof s == 'undefined') {
3870 if ((t /= d / 2 ) < 1) {
3871 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3873 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3877 bounceIn: function (t, b, c, d) {
3878 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3882 bounceOut: function (t, b, c, d) {
3883 if ((t /= d) < (1 / 2.75)) {
3884 return c * (7.5625 * t * t) + b;
3885 } else if (t < (2 / 2.75)) {
3886 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3887 } else if (t < (2.5 / 2.75)) {
3888 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3890 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3894 bounceBoth: function (t, b, c, d) {
3896 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3898 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3901 * Portions of this file are based on pieces of Yahoo User Interface Library
3902 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3903 * YUI licensed under the BSD License:
3904 * http://developer.yahoo.net/yui/license.txt
3905 * <script type="text/javascript">
3909 Roo.lib.Motion = function(el, attributes, duration, method) {
3911 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3915 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3919 var superclass = Y.Motion.superclass;
3920 var proto = Y.Motion.prototype;
3922 proto.toString = function() {
3923 var el = this.getEl();
3924 var id = el.id || el.tagName;
3925 return ("Motion " + id);
3928 proto.patterns.points = /^points$/i;
3930 proto.setAttribute = function(attr, val, unit) {
3931 if (this.patterns.points.test(attr)) {
3932 unit = unit || 'px';
3933 superclass.setAttribute.call(this, 'left', val[0], unit);
3934 superclass.setAttribute.call(this, 'top', val[1], unit);
3936 superclass.setAttribute.call(this, attr, val, unit);
3940 proto.getAttribute = function(attr) {
3941 if (this.patterns.points.test(attr)) {
3943 superclass.getAttribute.call(this, 'left'),
3944 superclass.getAttribute.call(this, 'top')
3947 val = superclass.getAttribute.call(this, attr);
3953 proto.doMethod = function(attr, start, end) {
3956 if (this.patterns.points.test(attr)) {
3957 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3958 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3960 val = superclass.doMethod.call(this, attr, start, end);
3965 proto.setRuntimeAttribute = function(attr) {
3966 if (this.patterns.points.test(attr)) {
3967 var el = this.getEl();
3968 var attributes = this.attributes;
3970 var control = attributes['points']['control'] || [];
3974 if (control.length > 0 && !(control[0] instanceof Array)) {
3975 control = [control];
3978 for (i = 0,len = control.length; i < len; ++i) {
3979 tmp[i] = control[i];
3984 Roo.fly(el).position();
3986 if (isset(attributes['points']['from'])) {
3987 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3990 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3993 start = this.getAttribute('points');
3996 if (isset(attributes['points']['to'])) {
3997 end = translateValues.call(this, attributes['points']['to'], start);
3999 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4000 for (i = 0,len = control.length; i < len; ++i) {
4001 control[i] = translateValues.call(this, control[i], start);
4005 } else if (isset(attributes['points']['by'])) {
4006 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4008 for (i = 0,len = control.length; i < len; ++i) {
4009 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4013 this.runtimeAttributes[attr] = [start];
4015 if (control.length > 0) {
4016 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4019 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4022 superclass.setRuntimeAttribute.call(this, attr);
4026 var translateValues = function(val, start) {
4027 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4028 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4033 var isset = function(prop) {
4034 return (typeof prop !== 'undefined');
4038 * Portions of this file are based on pieces of Yahoo User Interface Library
4039 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4040 * YUI licensed under the BSD License:
4041 * http://developer.yahoo.net/yui/license.txt
4042 * <script type="text/javascript">
4046 Roo.lib.Scroll = function(el, attributes, duration, method) {
4048 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4052 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4056 var superclass = Y.Scroll.superclass;
4057 var proto = Y.Scroll.prototype;
4059 proto.toString = function() {
4060 var el = this.getEl();
4061 var id = el.id || el.tagName;
4062 return ("Scroll " + id);
4065 proto.doMethod = function(attr, start, end) {
4068 if (attr == 'scroll') {
4070 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4071 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4075 val = superclass.doMethod.call(this, attr, start, end);
4080 proto.getAttribute = function(attr) {
4082 var el = this.getEl();
4084 if (attr == 'scroll') {
4085 val = [ el.scrollLeft, el.scrollTop ];
4087 val = superclass.getAttribute.call(this, attr);
4093 proto.setAttribute = function(attr, val, unit) {
4094 var el = this.getEl();
4096 if (attr == 'scroll') {
4097 el.scrollLeft = val[0];
4098 el.scrollTop = val[1];
4100 superclass.setAttribute.call(this, attr, val, unit);
4106 * Ext JS Library 1.1.1
4107 * Copyright(c) 2006-2007, Ext JS, LLC.
4109 * Originally Released Under LGPL - original licence link has changed is not relivant.
4112 * <script type="text/javascript">
4116 // nasty IE9 hack - what a pile of crap that is..
4118 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4119 Range.prototype.createContextualFragment = function (html) {
4120 var doc = window.document;
4121 var container = doc.createElement("div");
4122 container.innerHTML = html;
4123 var frag = doc.createDocumentFragment(), n;
4124 while ((n = container.firstChild)) {
4125 frag.appendChild(n);
4132 * @class Roo.DomHelper
4133 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4134 * 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>.
4137 Roo.DomHelper = function(){
4138 var tempTableEl = null;
4139 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4140 var tableRe = /^table|tbody|tr|td$/i;
4142 // build as innerHTML where available
4144 var createHtml = function(o){
4145 if(typeof o == 'string'){
4154 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4155 if(attr == "style"){
4157 if(typeof s == "function"){
4160 if(typeof s == "string"){
4161 b += ' style="' + s + '"';
4162 }else if(typeof s == "object"){
4165 if(typeof s[key] != "function"){
4166 b += key + ":" + s[key] + ";";
4173 b += ' class="' + o["cls"] + '"';
4174 }else if(attr == "htmlFor"){
4175 b += ' for="' + o["htmlFor"] + '"';
4177 b += " " + attr + '="' + o[attr] + '"';
4181 if(emptyTags.test(o.tag)){
4185 var cn = o.children || o.cn;
4187 //http://bugs.kde.org/show_bug.cgi?id=71506
4188 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4189 for(var i = 0, len = cn.length; i < len; i++) {
4190 b += createHtml(cn[i], b);
4193 b += createHtml(cn, b);
4199 b += "</" + o.tag + ">";
4206 var createDom = function(o, parentNode){
4208 // defininition craeted..
4210 if (o.ns && o.ns != 'html') {
4212 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4213 xmlns[o.ns] = o.xmlns;
4216 if (typeof(xmlns[o.ns]) == 'undefined') {
4217 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4223 if (typeof(o) == 'string') {
4224 return parentNode.appendChild(document.createTextNode(o));
4226 o.tag = o.tag || div;
4227 if (o.ns && Roo.isIE) {
4229 o.tag = o.ns + ':' + o.tag;
4232 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4233 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4236 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4237 attr == "style" || typeof o[attr] == "function") continue;
4239 if(attr=="cls" && Roo.isIE){
4240 el.className = o["cls"];
4242 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4248 Roo.DomHelper.applyStyles(el, o.style);
4249 var cn = o.children || o.cn;
4251 //http://bugs.kde.org/show_bug.cgi?id=71506
4252 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4253 for(var i = 0, len = cn.length; i < len; i++) {
4254 createDom(cn[i], el);
4261 el.innerHTML = o.html;
4264 parentNode.appendChild(el);
4269 var ieTable = function(depth, s, h, e){
4270 tempTableEl.innerHTML = [s, h, e].join('');
4271 var i = -1, el = tempTableEl;
4278 // kill repeat to save bytes
4282 tbe = '</tbody>'+te,
4288 * Nasty code for IE's broken table implementation
4290 var insertIntoTable = function(tag, where, el, html){
4292 tempTableEl = document.createElement('div');
4297 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4300 if(where == 'beforebegin'){
4304 before = el.nextSibling;
4307 node = ieTable(4, trs, html, tre);
4309 else if(tag == 'tr'){
4310 if(where == 'beforebegin'){
4313 node = ieTable(3, tbs, html, tbe);
4314 } else if(where == 'afterend'){
4315 before = el.nextSibling;
4317 node = ieTable(3, tbs, html, tbe);
4318 } else{ // INTO a TR
4319 if(where == 'afterbegin'){
4320 before = el.firstChild;
4322 node = ieTable(4, trs, html, tre);
4324 } else if(tag == 'tbody'){
4325 if(where == 'beforebegin'){
4328 node = ieTable(2, ts, html, te);
4329 } else if(where == 'afterend'){
4330 before = el.nextSibling;
4332 node = ieTable(2, ts, html, te);
4334 if(where == 'afterbegin'){
4335 before = el.firstChild;
4337 node = ieTable(3, tbs, html, tbe);
4340 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4343 if(where == 'afterbegin'){
4344 before = el.firstChild;
4346 node = ieTable(2, ts, html, te);
4348 el.insertBefore(node, before);
4353 /** True to force the use of DOM instead of html fragments @type Boolean */
4357 * Returns the markup for the passed Element(s) config
4358 * @param {Object} o The Dom object spec (and children)
4361 markup : function(o){
4362 return createHtml(o);
4366 * Applies a style specification to an element
4367 * @param {String/HTMLElement} el The element to apply styles to
4368 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4369 * a function which returns such a specification.
4371 applyStyles : function(el, styles){
4374 if(typeof styles == "string"){
4375 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4377 while ((matches = re.exec(styles)) != null){
4378 el.setStyle(matches[1], matches[2]);
4380 }else if (typeof styles == "object"){
4381 for (var style in styles){
4382 el.setStyle(style, styles[style]);
4384 }else if (typeof styles == "function"){
4385 Roo.DomHelper.applyStyles(el, styles.call());
4391 * Inserts an HTML fragment into the Dom
4392 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4393 * @param {HTMLElement} el The context element
4394 * @param {String} html The HTML fragmenet
4395 * @return {HTMLElement} The new node
4397 insertHtml : function(where, el, html){
4398 where = where.toLowerCase();
4399 if(el.insertAdjacentHTML){
4400 if(tableRe.test(el.tagName)){
4402 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4408 el.insertAdjacentHTML('BeforeBegin', html);
4409 return el.previousSibling;
4411 el.insertAdjacentHTML('AfterBegin', html);
4412 return el.firstChild;
4414 el.insertAdjacentHTML('BeforeEnd', html);
4415 return el.lastChild;
4417 el.insertAdjacentHTML('AfterEnd', html);
4418 return el.nextSibling;
4420 throw 'Illegal insertion point -> "' + where + '"';
4422 var range = el.ownerDocument.createRange();
4426 range.setStartBefore(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el);
4429 return el.previousSibling;
4432 range.setStartBefore(el.firstChild);
4433 frag = range.createContextualFragment(html);
4434 el.insertBefore(frag, el.firstChild);
4435 return el.firstChild;
4437 el.innerHTML = html;
4438 return el.firstChild;
4442 range.setStartAfter(el.lastChild);
4443 frag = range.createContextualFragment(html);
4444 el.appendChild(frag);
4445 return el.lastChild;
4447 el.innerHTML = html;
4448 return el.lastChild;
4451 range.setStartAfter(el);
4452 frag = range.createContextualFragment(html);
4453 el.parentNode.insertBefore(frag, el.nextSibling);
4454 return el.nextSibling;
4456 throw 'Illegal insertion point -> "' + where + '"';
4460 * Creates new Dom element(s) and inserts them before el
4461 * @param {String/HTMLElement/Element} el The context element
4462 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464 * @return {HTMLElement/Roo.Element} The new node
4466 insertBefore : function(el, o, returnElement){
4467 return this.doInsert(el, o, returnElement, "beforeBegin");
4471 * Creates new Dom element(s) and inserts them after el
4472 * @param {String/HTMLElement/Element} el The context element
4473 * @param {Object} o The Dom object spec (and children)
4474 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475 * @return {HTMLElement/Roo.Element} The new node
4477 insertAfter : function(el, o, returnElement){
4478 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4482 * Creates new Dom element(s) and inserts them as the first child of el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 insertFirst : function(el, o, returnElement){
4489 return this.doInsert(el, o, returnElement, "afterBegin");
4493 doInsert : function(el, o, returnElement, pos, sibling){
4494 el = Roo.getDom(el);
4496 if(this.useDom || o.ns){
4497 newNode = createDom(o, null);
4498 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4500 var html = createHtml(o);
4501 newNode = this.insertHtml(pos, el, html);
4503 return returnElement ? Roo.get(newNode, true) : newNode;
4507 * Creates new Dom element(s) and appends them to el
4508 * @param {String/HTMLElement/Element} el The context element
4509 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4510 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4511 * @return {HTMLElement/Roo.Element} The new node
4513 append : function(el, o, returnElement){
4514 el = Roo.getDom(el);
4516 if(this.useDom || o.ns){
4517 newNode = createDom(o, null);
4518 el.appendChild(newNode);
4520 var html = createHtml(o);
4521 newNode = this.insertHtml("beforeEnd", el, html);
4523 return returnElement ? Roo.get(newNode, true) : newNode;
4527 * Creates new Dom element(s) and overwrites the contents of el with them
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 overwrite : function(el, o, returnElement){
4534 el = Roo.getDom(el);
4537 while (el.childNodes.length) {
4538 el.removeChild(el.firstChild);
4542 el.innerHTML = createHtml(o);
4545 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4549 * Creates a new Roo.DomHelper.Template from the Dom object spec
4550 * @param {Object} o The Dom object spec (and children)
4551 * @return {Roo.DomHelper.Template} The new template
4553 createTemplate : function(o){
4554 var html = createHtml(o);
4555 return new Roo.Template(html);
4561 * Ext JS Library 1.1.1
4562 * Copyright(c) 2006-2007, Ext JS, LLC.
4564 * Originally Released Under LGPL - original licence link has changed is not relivant.
4567 * <script type="text/javascript">
4571 * @class Roo.Template
4572 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4573 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4576 var t = new Roo.Template({
4577 html : '<div name="{id}">' +
4578 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4580 myformat: function (value, allValues) {
4581 return 'XX' + value;
4584 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4586 * For more information see this blog post with examples:
4587 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4588 - Create Elements using DOM, HTML fragments and Templates</a>.
4590 * @param {Object} cfg - Configuration object.
4592 Roo.Template = function(cfg){
4594 if(cfg instanceof Array){
4596 }else if(arguments.length > 1){
4597 cfg = Array.prototype.join.call(arguments, "");
4601 if (typeof(cfg) == 'object') {
4612 Roo.Template.prototype = {
4615 * @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..
4616 * it should be fixed so that template is observable...
4620 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4624 * Returns an HTML fragment of this template with the specified values applied.
4625 * @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'})
4626 * @return {String} The HTML fragment
4628 applyTemplate : function(values){
4632 return this.compiled(values);
4634 var useF = this.disableFormats !== true;
4635 var fm = Roo.util.Format, tpl = this;
4636 var fn = function(m, name, format, args){
4638 if(format.substr(0, 5) == "this."){
4639 return tpl.call(format.substr(5), values[name], values);
4642 // quoted values are required for strings in compiled templates,
4643 // but for non compiled we need to strip them
4644 // quoted reversed for jsmin
4645 var re = /^\s*['"](.*)["']\s*$/;
4646 args = args.split(',');
4647 for(var i = 0, len = args.length; i < len; i++){
4648 args[i] = args[i].replace(re, "$1");
4650 args = [values[name]].concat(args);
4652 args = [values[name]];
4654 return fm[format].apply(fm, args);
4657 return values[name] !== undefined ? values[name] : "";
4660 return this.html.replace(this.re, fn);
4678 this.loading = true;
4679 this.compiled = false;
4681 var cx = new Roo.data.Connection();
4685 success : function (response) {
4687 _t.html = response.responseText;
4691 failure : function(response) {
4692 Roo.log("Template failed to load from " + _t.url);
4699 * Sets the HTML used as the template and optionally compiles it.
4700 * @param {String} html
4701 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4702 * @return {Roo.Template} this
4704 set : function(html, compile){
4706 this.compiled = null;
4714 * True to disable format functions (defaults to false)
4717 disableFormats : false,
4720 * The regular expression used to match template variables
4724 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4727 * Compiles the template into an internal function, eliminating the RegEx overhead.
4728 * @return {Roo.Template} this
4730 compile : function(){
4731 var fm = Roo.util.Format;
4732 var useF = this.disableFormats !== true;
4733 var sep = Roo.isGecko ? "+" : ",";
4734 var fn = function(m, name, format, args){
4736 args = args ? ',' + args : "";
4737 if(format.substr(0, 5) != "this."){
4738 format = "fm." + format + '(';
4740 format = 'this.call("'+ format.substr(5) + '", ';
4744 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4746 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4749 // branched to use + in gecko and [].join() in others
4751 body = "this.compiled = function(values){ return '" +
4752 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4755 body = ["this.compiled = function(values){ return ['"];
4756 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4757 body.push("'].join('');};");
4758 body = body.join('');
4768 // private function used to call members
4769 call : function(fnName, value, allValues){
4770 return this[fnName](value, allValues);
4774 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4775 * @param {String/HTMLElement/Roo.Element} el The context element
4776 * @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'})
4777 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778 * @return {HTMLElement/Roo.Element} The new node or Element
4780 insertFirst: function(el, values, returnElement){
4781 return this.doInsert('afterBegin', el, values, returnElement);
4785 * Applies the supplied values to the template and inserts the new node(s) before el.
4786 * @param {String/HTMLElement/Roo.Element} el The context element
4787 * @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'})
4788 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789 * @return {HTMLElement/Roo.Element} The new node or Element
4791 insertBefore: function(el, values, returnElement){
4792 return this.doInsert('beforeBegin', el, values, returnElement);
4796 * Applies the supplied values to the template and inserts the new node(s) after el.
4797 * @param {String/HTMLElement/Roo.Element} el The context element
4798 * @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'})
4799 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4800 * @return {HTMLElement/Roo.Element} The new node or Element
4802 insertAfter : function(el, values, returnElement){
4803 return this.doInsert('afterEnd', el, values, returnElement);
4807 * Applies the supplied values to the template and appends the new node(s) to el.
4808 * @param {String/HTMLElement/Roo.Element} el The context element
4809 * @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'})
4810 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811 * @return {HTMLElement/Roo.Element} The new node or Element
4813 append : function(el, values, returnElement){
4814 return this.doInsert('beforeEnd', el, values, returnElement);
4817 doInsert : function(where, el, values, returnEl){
4818 el = Roo.getDom(el);
4819 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4820 return returnEl ? Roo.get(newNode, true) : newNode;
4824 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4825 * @param {String/HTMLElement/Roo.Element} el The context element
4826 * @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'})
4827 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4828 * @return {HTMLElement/Roo.Element} The new node or Element
4830 overwrite : function(el, values, returnElement){
4831 el = Roo.getDom(el);
4832 el.innerHTML = this.applyTemplate(values);
4833 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4837 * Alias for {@link #applyTemplate}
4840 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4843 Roo.DomHelper.Template = Roo.Template;
4846 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4847 * @param {String/HTMLElement} el A DOM element or its id
4848 * @returns {Roo.Template} The created template
4851 Roo.Template.from = function(el){
4852 el = Roo.getDom(el);
4853 return new Roo.Template(el.value || el.innerHTML);
4856 * Ext JS Library 1.1.1
4857 * Copyright(c) 2006-2007, Ext JS, LLC.
4859 * Originally Released Under LGPL - original licence link has changed is not relivant.
4862 * <script type="text/javascript">
4867 * This is code is also distributed under MIT license for use
4868 * with jQuery and prototype JavaScript libraries.
4871 * @class Roo.DomQuery
4872 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).
4874 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>
4877 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.
4879 <h4>Element Selectors:</h4>
4881 <li> <b>*</b> any element</li>
4882 <li> <b>E</b> an element with the tag E</li>
4883 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4884 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4885 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4886 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4888 <h4>Attribute Selectors:</h4>
4889 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4891 <li> <b>E[foo]</b> has an attribute "foo"</li>
4892 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4893 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4894 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4895 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4896 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4897 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4899 <h4>Pseudo Classes:</h4>
4901 <li> <b>E:first-child</b> E is the first child of its parent</li>
4902 <li> <b>E:last-child</b> E is the last child of its parent</li>
4903 <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>
4904 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4905 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4906 <li> <b>E:only-child</b> E is the only child of its parent</li>
4907 <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>
4908 <li> <b>E:first</b> the first E in the resultset</li>
4909 <li> <b>E:last</b> the last E in the resultset</li>
4910 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4911 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4912 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4913 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4914 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4915 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4916 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4917 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4918 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4920 <h4>CSS Value Selectors:</h4>
4922 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4923 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4924 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4925 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4926 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4927 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4931 Roo.DomQuery = function(){
4932 var cache = {}, simpleCache = {}, valueCache = {};
4933 var nonSpace = /\S/;
4934 var trimRe = /^\s+|\s+$/g;
4935 var tplRe = /\{(\d+)\}/g;
4936 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4937 var tagTokenRe = /^(#)?([\w-\*]+)/;
4938 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4940 function child(p, index){
4942 var n = p.firstChild;
4944 if(n.nodeType == 1){
4955 while((n = n.nextSibling) && n.nodeType != 1);
4960 while((n = n.previousSibling) && n.nodeType != 1);
4964 function children(d){
4965 var n = d.firstChild, ni = -1;
4967 var nx = n.nextSibling;
4968 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4978 function byClassName(c, a, v){
4982 var r = [], ri = -1, cn;
4983 for(var i = 0, ci; ci = c[i]; i++){
4984 if((' '+ci.className+' ').indexOf(v) != -1){
4991 function attrValue(n, attr){
4992 if(!n.tagName && typeof n.length != "undefined"){
5001 if(attr == "class" || attr == "className"){
5004 return n.getAttribute(attr) || n[attr];
5008 function getNodes(ns, mode, tagName){
5009 var result = [], ri = -1, cs;
5013 tagName = tagName || "*";
5014 if(typeof ns.getElementsByTagName != "undefined"){
5018 for(var i = 0, ni; ni = ns[i]; i++){
5019 cs = ni.getElementsByTagName(tagName);
5020 for(var j = 0, ci; ci = cs[j]; j++){
5024 }else if(mode == "/" || mode == ">"){
5025 var utag = tagName.toUpperCase();
5026 for(var i = 0, ni, cn; ni = ns[i]; i++){
5027 cn = ni.children || ni.childNodes;
5028 for(var j = 0, cj; cj = cn[j]; j++){
5029 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5034 }else if(mode == "+"){
5035 var utag = tagName.toUpperCase();
5036 for(var i = 0, n; n = ns[i]; i++){
5037 while((n = n.nextSibling) && n.nodeType != 1);
5038 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5042 }else if(mode == "~"){
5043 for(var i = 0, n; n = ns[i]; i++){
5044 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5053 function concat(a, b){
5057 for(var i = 0, l = b.length; i < l; i++){
5063 function byTag(cs, tagName){
5064 if(cs.tagName || cs == document){
5070 var r = [], ri = -1;
5071 tagName = tagName.toLowerCase();
5072 for(var i = 0, ci; ci = cs[i]; i++){
5073 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5080 function byId(cs, attr, id){
5081 if(cs.tagName || cs == document){
5087 var r = [], ri = -1;
5088 for(var i = 0,ci; ci = cs[i]; i++){
5089 if(ci && ci.id == id){
5097 function byAttribute(cs, attr, value, op, custom){
5098 var r = [], ri = -1, st = custom=="{";
5099 var f = Roo.DomQuery.operators[op];
5100 for(var i = 0, ci; ci = cs[i]; i++){
5103 a = Roo.DomQuery.getStyle(ci, attr);
5105 else if(attr == "class" || attr == "className"){
5107 }else if(attr == "for"){
5109 }else if(attr == "href"){
5110 a = ci.getAttribute("href", 2);
5112 a = ci.getAttribute(attr);
5114 if((f && f(a, value)) || (!f && a)){
5121 function byPseudo(cs, name, value){
5122 return Roo.DomQuery.pseudos[name](cs, value);
5125 // This is for IE MSXML which does not support expandos.
5126 // IE runs the same speed using setAttribute, however FF slows way down
5127 // and Safari completely fails so they need to continue to use expandos.
5128 var isIE = window.ActiveXObject ? true : false;
5130 // this eval is stop the compressor from
5131 // renaming the variable to something shorter
5133 /** eval:var:batch */
5138 function nodupIEXml(cs){
5140 cs[0].setAttribute("_nodup", d);
5142 for(var i = 1, len = cs.length; i < len; i++){
5144 if(!c.getAttribute("_nodup") != d){
5145 c.setAttribute("_nodup", d);
5149 for(var i = 0, len = cs.length; i < len; i++){
5150 cs[i].removeAttribute("_nodup");
5159 var len = cs.length, c, i, r = cs, cj, ri = -1;
5160 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5163 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5164 return nodupIEXml(cs);
5168 for(i = 1; c = cs[i]; i++){
5173 for(var j = 0; j < i; j++){
5176 for(j = i+1; cj = cs[j]; j++){
5188 function quickDiffIEXml(c1, c2){
5190 for(var i = 0, len = c1.length; i < len; i++){
5191 c1[i].setAttribute("_qdiff", d);
5194 for(var i = 0, len = c2.length; i < len; i++){
5195 if(c2[i].getAttribute("_qdiff") != d){
5196 r[r.length] = c2[i];
5199 for(var i = 0, len = c1.length; i < len; i++){
5200 c1[i].removeAttribute("_qdiff");
5205 function quickDiff(c1, c2){
5206 var len1 = c1.length;
5210 if(isIE && c1[0].selectSingleNode){
5211 return quickDiffIEXml(c1, c2);
5214 for(var i = 0; i < len1; i++){
5218 for(var i = 0, len = c2.length; i < len; i++){
5219 if(c2[i]._qdiff != d){
5220 r[r.length] = c2[i];
5226 function quickId(ns, mode, root, id){
5228 var d = root.ownerDocument || root;
5229 return d.getElementById(id);
5231 ns = getNodes(ns, mode, "*");
5232 return byId(ns, null, id);
5236 getStyle : function(el, name){
5237 return Roo.fly(el).getStyle(name);
5240 * Compiles a selector/xpath query into a reusable function. The returned function
5241 * takes one parameter "root" (optional), which is the context node from where the query should start.
5242 * @param {String} selector The selector/xpath query
5243 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5244 * @return {Function}
5246 compile : function(path, type){
5247 type = type || "select";
5249 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5250 var q = path, mode, lq;
5251 var tk = Roo.DomQuery.matchers;
5252 var tklen = tk.length;
5255 // accept leading mode switch
5256 var lmode = q.match(modeRe);
5257 if(lmode && lmode[1]){
5258 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5259 q = q.replace(lmode[1], "");
5261 // strip leading slashes
5262 while(path.substr(0, 1)=="/"){
5263 path = path.substr(1);
5266 while(q && lq != q){
5268 var tm = q.match(tagTokenRe);
5269 if(type == "select"){
5272 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5274 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5276 q = q.replace(tm[0], "");
5277 }else if(q.substr(0, 1) != '@'){
5278 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5283 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5285 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5287 q = q.replace(tm[0], "");
5290 while(!(mm = q.match(modeRe))){
5291 var matched = false;
5292 for(var j = 0; j < tklen; j++){
5294 var m = q.match(t.re);
5296 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5299 q = q.replace(m[0], "");
5304 // prevent infinite loop on bad selector
5306 throw 'Error parsing selector, parsing failed at "' + q + '"';
5310 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5311 q = q.replace(mm[1], "");
5314 fn[fn.length] = "return nodup(n);\n}";
5317 * list of variables that need from compression as they are used by eval.
5327 * eval:var:byClassName
5329 * eval:var:byAttribute
5330 * eval:var:attrValue
5338 * Selects a group of elements.
5339 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5340 * @param {Node} root (optional) The start of the query (defaults to document).
5343 select : function(path, root, type){
5344 if(!root || root == document){
5347 if(typeof root == "string"){
5348 root = document.getElementById(root);
5350 var paths = path.split(",");
5352 for(var i = 0, len = paths.length; i < len; i++){
5353 var p = paths[i].replace(trimRe, "");
5355 cache[p] = Roo.DomQuery.compile(p);
5357 throw p + " is not a valid selector";
5360 var result = cache[p](root);
5361 if(result && result != document){
5362 results = results.concat(result);
5365 if(paths.length > 1){
5366 return nodup(results);
5372 * Selects a single element.
5373 * @param {String} selector The selector/xpath query
5374 * @param {Node} root (optional) The start of the query (defaults to document).
5377 selectNode : function(path, root){
5378 return Roo.DomQuery.select(path, root)[0];
5382 * Selects the value of a node, optionally replacing null with the defaultValue.
5383 * @param {String} selector The selector/xpath query
5384 * @param {Node} root (optional) The start of the query (defaults to document).
5385 * @param {String} defaultValue
5387 selectValue : function(path, root, defaultValue){
5388 path = path.replace(trimRe, "");
5389 if(!valueCache[path]){
5390 valueCache[path] = Roo.DomQuery.compile(path, "select");
5392 var n = valueCache[path](root);
5393 n = n[0] ? n[0] : n;
5394 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5395 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5399 * Selects the value of a node, parsing integers and floats.
5400 * @param {String} selector The selector/xpath query
5401 * @param {Node} root (optional) The start of the query (defaults to document).
5402 * @param {Number} defaultValue
5405 selectNumber : function(path, root, defaultValue){
5406 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5407 return parseFloat(v);
5411 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5412 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5413 * @param {String} selector The simple selector to test
5416 is : function(el, ss){
5417 if(typeof el == "string"){
5418 el = document.getElementById(el);
5420 var isArray = (el instanceof Array);
5421 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5422 return isArray ? (result.length == el.length) : (result.length > 0);
5426 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5427 * @param {Array} el An array of elements to filter
5428 * @param {String} selector The simple selector to test
5429 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5430 * the selector instead of the ones that match
5433 filter : function(els, ss, nonMatches){
5434 ss = ss.replace(trimRe, "");
5435 if(!simpleCache[ss]){
5436 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5438 var result = simpleCache[ss](els);
5439 return nonMatches ? quickDiff(result, els) : result;
5443 * Collection of matching regular expressions and code snippets.
5447 select: 'n = byClassName(n, null, " {1} ");'
5449 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5450 select: 'n = byPseudo(n, "{1}", "{2}");'
5452 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5453 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5456 select: 'n = byId(n, null, "{1}");'
5459 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5464 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5465 * 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, > <.
5468 "=" : function(a, v){
5471 "!=" : function(a, v){
5474 "^=" : function(a, v){
5475 return a && a.substr(0, v.length) == v;
5477 "$=" : function(a, v){
5478 return a && a.substr(a.length-v.length) == v;
5480 "*=" : function(a, v){
5481 return a && a.indexOf(v) !== -1;
5483 "%=" : function(a, v){
5484 return (a % v) == 0;
5486 "|=" : function(a, v){
5487 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5489 "~=" : function(a, v){
5490 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5495 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5496 * and the argument (if any) supplied in the selector.
5499 "first-child" : function(c){
5500 var r = [], ri = -1, n;
5501 for(var i = 0, ci; ci = n = c[i]; i++){
5502 while((n = n.previousSibling) && n.nodeType != 1);
5510 "last-child" : function(c){
5511 var r = [], ri = -1, n;
5512 for(var i = 0, ci; ci = n = c[i]; i++){
5513 while((n = n.nextSibling) && n.nodeType != 1);
5521 "nth-child" : function(c, a) {
5522 var r = [], ri = -1;
5523 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5524 var f = (m[1] || 1) - 0, l = m[2] - 0;
5525 for(var i = 0, n; n = c[i]; i++){
5526 var pn = n.parentNode;
5527 if (batch != pn._batch) {
5529 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5530 if(cn.nodeType == 1){
5537 if (l == 0 || n.nodeIndex == l){
5540 } else if ((n.nodeIndex + l) % f == 0){
5548 "only-child" : function(c){
5549 var r = [], ri = -1;;
5550 for(var i = 0, ci; ci = c[i]; i++){
5551 if(!prev(ci) && !next(ci)){
5558 "empty" : function(c){
5559 var r = [], ri = -1;
5560 for(var i = 0, ci; ci = c[i]; i++){
5561 var cns = ci.childNodes, j = 0, cn, empty = true;
5564 if(cn.nodeType == 1 || cn.nodeType == 3){
5576 "contains" : function(c, v){
5577 var r = [], ri = -1;
5578 for(var i = 0, ci; ci = c[i]; i++){
5579 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5586 "nodeValue" : function(c, v){
5587 var r = [], ri = -1;
5588 for(var i = 0, ci; ci = c[i]; i++){
5589 if(ci.firstChild && ci.firstChild.nodeValue == v){
5596 "checked" : function(c){
5597 var r = [], ri = -1;
5598 for(var i = 0, ci; ci = c[i]; i++){
5599 if(ci.checked == true){
5606 "not" : function(c, ss){
5607 return Roo.DomQuery.filter(c, ss, true);
5610 "odd" : function(c){
5611 return this["nth-child"](c, "odd");
5614 "even" : function(c){
5615 return this["nth-child"](c, "even");
5618 "nth" : function(c, a){
5619 return c[a-1] || [];
5622 "first" : function(c){
5626 "last" : function(c){
5627 return c[c.length-1] || [];
5630 "has" : function(c, ss){
5631 var s = Roo.DomQuery.select;
5632 var r = [], ri = -1;
5633 for(var i = 0, ci; ci = c[i]; i++){
5634 if(s(ss, ci).length > 0){
5641 "next" : function(c, ss){
5642 var is = Roo.DomQuery.is;
5643 var r = [], ri = -1;
5644 for(var i = 0, ci; ci = c[i]; i++){
5653 "prev" : function(c, ss){
5654 var is = Roo.DomQuery.is;
5655 var r = [], ri = -1;
5656 for(var i = 0, ci; ci = c[i]; i++){
5669 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5670 * @param {String} path The selector/xpath query
5671 * @param {Node} root (optional) The start of the query (defaults to document).
5676 Roo.query = Roo.DomQuery.select;
5679 * Ext JS Library 1.1.1
5680 * Copyright(c) 2006-2007, Ext JS, LLC.
5682 * Originally Released Under LGPL - original licence link has changed is not relivant.
5685 * <script type="text/javascript">
5689 * @class Roo.util.Observable
5690 * Base class that provides a common interface for publishing events. Subclasses are expected to
5691 * to have a property "events" with all the events defined.<br>
5694 Employee = function(name){
5701 Roo.extend(Employee, Roo.util.Observable);
5703 * @param {Object} config properties to use (incuding events / listeners)
5706 Roo.util.Observable = function(cfg){
5709 this.addEvents(cfg.events || {});
5711 delete cfg.events; // make sure
5714 Roo.apply(this, cfg);
5717 this.on(this.listeners);
5718 delete this.listeners;
5721 Roo.util.Observable.prototype = {
5723 * @cfg {Object} listeners list of events and functions to call for this object,
5727 'click' : function(e) {
5737 * Fires the specified event with the passed parameters (minus the event name).
5738 * @param {String} eventName
5739 * @param {Object...} args Variable number of parameters are passed to handlers
5740 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5742 fireEvent : function(){
5743 var ce = this.events[arguments[0].toLowerCase()];
5744 if(typeof ce == "object"){
5745 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5752 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5755 * Appends an event handler to this component
5756 * @param {String} eventName The type of event to listen for
5757 * @param {Function} handler The method the event invokes
5758 * @param {Object} scope (optional) The scope in which to execute the handler
5759 * function. The handler function's "this" context.
5760 * @param {Object} options (optional) An object containing handler configuration
5761 * properties. This may contain any of the following properties:<ul>
5762 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5763 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5764 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5765 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5766 * by the specified number of milliseconds. If the event fires again within that time, the original
5767 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5770 * <b>Combining Options</b><br>
5771 * Using the options argument, it is possible to combine different types of listeners:<br>
5773 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5775 el.on('click', this.onClick, this, {
5782 * <b>Attaching multiple handlers in 1 call</b><br>
5783 * The method also allows for a single argument to be passed which is a config object containing properties
5784 * which specify multiple handlers.
5793 fn: this.onMouseOver,
5797 fn: this.onMouseOut,
5803 * Or a shorthand syntax which passes the same scope object to all handlers:
5806 'click': this.onClick,
5807 'mouseover': this.onMouseOver,
5808 'mouseout': this.onMouseOut,
5813 addListener : function(eventName, fn, scope, o){
5814 if(typeof eventName == "object"){
5817 if(this.filterOptRe.test(e)){
5820 if(typeof o[e] == "function"){
5822 this.addListener(e, o[e], o.scope, o);
5824 // individual options
5825 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5830 o = (!o || typeof o == "boolean") ? {} : o;
5831 eventName = eventName.toLowerCase();
5832 var ce = this.events[eventName] || true;
5833 if(typeof ce == "boolean"){
5834 ce = new Roo.util.Event(this, eventName);
5835 this.events[eventName] = ce;
5837 ce.addListener(fn, scope, o);
5841 * Removes a listener
5842 * @param {String} eventName The type of event to listen for
5843 * @param {Function} handler The handler to remove
5844 * @param {Object} scope (optional) The scope (this object) for the handler
5846 removeListener : function(eventName, fn, scope){
5847 var ce = this.events[eventName.toLowerCase()];
5848 if(typeof ce == "object"){
5849 ce.removeListener(fn, scope);
5854 * Removes all listeners for this object
5856 purgeListeners : function(){
5857 for(var evt in this.events){
5858 if(typeof this.events[evt] == "object"){
5859 this.events[evt].clearListeners();
5864 relayEvents : function(o, events){
5865 var createHandler = function(ename){
5867 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5870 for(var i = 0, len = events.length; i < len; i++){
5871 var ename = events[i];
5872 if(!this.events[ename]){ this.events[ename] = true; };
5873 o.on(ename, createHandler(ename), this);
5878 * Used to define events on this Observable
5879 * @param {Object} object The object with the events defined
5881 addEvents : function(o){
5885 Roo.applyIf(this.events, o);
5889 * Checks to see if this object has any listeners for a specified event
5890 * @param {String} eventName The name of the event to check for
5891 * @return {Boolean} True if the event is being listened for, else false
5893 hasListener : function(eventName){
5894 var e = this.events[eventName];
5895 return typeof e == "object" && e.listeners.length > 0;
5899 * Appends an event handler to this element (shorthand for addListener)
5900 * @param {String} eventName The type of event to listen for
5901 * @param {Function} handler The method the event invokes
5902 * @param {Object} scope (optional) The scope in which to execute the handler
5903 * function. The handler function's "this" context.
5904 * @param {Object} options (optional)
5907 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5909 * Removes a listener (shorthand for removeListener)
5910 * @param {String} eventName The type of event to listen for
5911 * @param {Function} handler The handler to remove
5912 * @param {Object} scope (optional) The scope (this object) for the handler
5915 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5918 * Starts capture on the specified Observable. All events will be passed
5919 * to the supplied function with the event name + standard signature of the event
5920 * <b>before</b> the event is fired. If the supplied function returns false,
5921 * the event will not fire.
5922 * @param {Observable} o The Observable to capture
5923 * @param {Function} fn The function to call
5924 * @param {Object} scope (optional) The scope (this object) for the fn
5927 Roo.util.Observable.capture = function(o, fn, scope){
5928 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5932 * Removes <b>all</b> added captures from the Observable.
5933 * @param {Observable} o The Observable to release
5936 Roo.util.Observable.releaseCapture = function(o){
5937 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5942 var createBuffered = function(h, o, scope){
5943 var task = new Roo.util.DelayedTask();
5945 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5949 var createSingle = function(h, e, fn, scope){
5951 e.removeListener(fn, scope);
5952 return h.apply(scope, arguments);
5956 var createDelayed = function(h, o, scope){
5958 var args = Array.prototype.slice.call(arguments, 0);
5959 setTimeout(function(){
5960 h.apply(scope, args);
5965 Roo.util.Event = function(obj, name){
5968 this.listeners = [];
5971 Roo.util.Event.prototype = {
5972 addListener : function(fn, scope, options){
5973 var o = options || {};
5974 scope = scope || this.obj;
5975 if(!this.isListening(fn, scope)){
5976 var l = {fn: fn, scope: scope, options: o};
5979 h = createDelayed(h, o, scope);
5982 h = createSingle(h, this, fn, scope);
5985 h = createBuffered(h, o, scope);
5988 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5989 this.listeners.push(l);
5991 this.listeners = this.listeners.slice(0);
5992 this.listeners.push(l);
5997 findListener : function(fn, scope){
5998 scope = scope || this.obj;
5999 var ls = this.listeners;
6000 for(var i = 0, len = ls.length; i < len; i++){
6002 if(l.fn == fn && l.scope == scope){
6009 isListening : function(fn, scope){
6010 return this.findListener(fn, scope) != -1;
6013 removeListener : function(fn, scope){
6015 if((index = this.findListener(fn, scope)) != -1){
6017 this.listeners.splice(index, 1);
6019 this.listeners = this.listeners.slice(0);
6020 this.listeners.splice(index, 1);
6027 clearListeners : function(){
6028 this.listeners = [];
6032 var ls = this.listeners, scope, len = ls.length;
6035 var args = Array.prototype.slice.call(arguments, 0);
6036 for(var i = 0; i < len; i++){
6038 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6039 this.firing = false;
6043 this.firing = false;
6050 * Ext JS Library 1.1.1
6051 * Copyright(c) 2006-2007, Ext JS, LLC.
6053 * Originally Released Under LGPL - original licence link has changed is not relivant.
6056 * <script type="text/javascript">
6060 * @class Roo.EventManager
6061 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6062 * several useful events directly.
6063 * See {@link Roo.EventObject} for more details on normalized event objects.
6066 Roo.EventManager = function(){
6067 var docReadyEvent, docReadyProcId, docReadyState = false;
6068 var resizeEvent, resizeTask, textEvent, textSize;
6069 var E = Roo.lib.Event;
6070 var D = Roo.lib.Dom;
6075 var fireDocReady = function(){
6077 docReadyState = true;
6080 clearInterval(docReadyProcId);
6082 if(Roo.isGecko || Roo.isOpera) {
6083 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6086 var defer = document.getElementById("ie-deferred-loader");
6088 defer.onreadystatechange = null;
6089 defer.parentNode.removeChild(defer);
6093 docReadyEvent.fire();
6094 docReadyEvent.clearListeners();
6099 var initDocReady = function(){
6100 docReadyEvent = new Roo.util.Event();
6101 if(Roo.isGecko || Roo.isOpera) {
6102 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6104 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6105 var defer = document.getElementById("ie-deferred-loader");
6106 defer.onreadystatechange = function(){
6107 if(this.readyState == "complete"){
6111 }else if(Roo.isSafari){
6112 docReadyProcId = setInterval(function(){
6113 var rs = document.readyState;
6114 if(rs == "complete") {
6119 // no matter what, make sure it fires on load
6120 E.on(window, "load", fireDocReady);
6123 var createBuffered = function(h, o){
6124 var task = new Roo.util.DelayedTask(h);
6126 // create new event object impl so new events don't wipe out properties
6127 e = new Roo.EventObjectImpl(e);
6128 task.delay(o.buffer, h, null, [e]);
6132 var createSingle = function(h, el, ename, fn){
6134 Roo.EventManager.removeListener(el, ename, fn);
6139 var createDelayed = function(h, o){
6141 // create new event object impl so new events don't wipe out properties
6142 e = new Roo.EventObjectImpl(e);
6143 setTimeout(function(){
6148 var transitionEndVal = false;
6150 var transitionEnd = function()
6152 if (transitionEndVal) {
6153 return transitionEndVal;
6155 var el = document.createElement('div');
6157 var transEndEventNames = {
6158 WebkitTransition : 'webkitTransitionEnd',
6159 MozTransition : 'transitionend',
6160 OTransition : 'oTransitionEnd otransitionend',
6161 transition : 'transitionend'
6164 for (var name in transEndEventNames) {
6165 if (el.style[name] !== undefined) {
6166 transitionEndVal = transEndEventNames[name];
6167 return transitionEndVal ;
6173 var listen = function(element, ename, opt, fn, scope){
6174 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6175 fn = fn || o.fn; scope = scope || o.scope;
6176 var el = Roo.getDom(element);
6180 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6183 if (ename == 'transitionend') {
6184 ename = transitionEnd();
6186 var h = function(e){
6187 e = Roo.EventObject.setEvent(e);
6190 t = e.getTarget(o.delegate, el);
6197 if(o.stopEvent === true){
6200 if(o.preventDefault === true){
6203 if(o.stopPropagation === true){
6204 e.stopPropagation();
6207 if(o.normalized === false){
6211 fn.call(scope || el, e, t, o);
6214 h = createDelayed(h, o);
6217 h = createSingle(h, el, ename, fn);
6220 h = createBuffered(h, o);
6222 fn._handlers = fn._handlers || [];
6225 fn._handlers.push([Roo.id(el), ename, h]);
6230 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6231 el.addEventListener("DOMMouseScroll", h, false);
6232 E.on(window, 'unload', function(){
6233 el.removeEventListener("DOMMouseScroll", h, false);
6236 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6237 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6242 var stopListening = function(el, ename, fn){
6243 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6245 for(var i = 0, len = hds.length; i < len; i++){
6247 if(h[0] == id && h[1] == ename){
6254 E.un(el, ename, hd);
6255 el = Roo.getDom(el);
6256 if(ename == "mousewheel" && el.addEventListener){
6257 el.removeEventListener("DOMMouseScroll", hd, false);
6259 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6260 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6264 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6271 * @scope Roo.EventManager
6276 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6277 * object with a Roo.EventObject
6278 * @param {Function} fn The method the event invokes
6279 * @param {Object} scope An object that becomes the scope of the handler
6280 * @param {boolean} override If true, the obj passed in becomes
6281 * the execution scope of the listener
6282 * @return {Function} The wrapped function
6285 wrap : function(fn, scope, override){
6287 Roo.EventObject.setEvent(e);
6288 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6293 * Appends an event handler to an element (shorthand for addListener)
6294 * @param {String/HTMLElement} element The html element or id to assign the
6295 * @param {String} eventName The type of event to listen for
6296 * @param {Function} handler The method the event invokes
6297 * @param {Object} scope (optional) The scope in which to execute the handler
6298 * function. The handler function's "this" context.
6299 * @param {Object} options (optional) An object containing handler configuration
6300 * properties. This may contain any of the following properties:<ul>
6301 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6302 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6303 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6304 * <li>preventDefault {Boolean} True to prevent the default action</li>
6305 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6306 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6307 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6308 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6309 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6310 * by the specified number of milliseconds. If the event fires again within that time, the original
6311 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6314 * <b>Combining Options</b><br>
6315 * Using the options argument, it is possible to combine different types of listeners:<br>
6317 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6319 el.on('click', this.onClick, this, {
6326 * <b>Attaching multiple handlers in 1 call</b><br>
6327 * The method also allows for a single argument to be passed which is a config object containing properties
6328 * which specify multiple handlers.
6338 fn: this.onMouseOver
6347 * Or a shorthand syntax:<br>
6350 'click' : this.onClick,
6351 'mouseover' : this.onMouseOver,
6352 'mouseout' : this.onMouseOut
6356 addListener : function(element, eventName, fn, scope, options){
6357 if(typeof eventName == "object"){
6363 if(typeof o[e] == "function"){
6365 listen(element, e, o, o[e], o.scope);
6367 // individual options
6368 listen(element, e, o[e]);
6373 return listen(element, eventName, options, fn, scope);
6377 * Removes an event handler
6379 * @param {String/HTMLElement} element The id or html element to remove the
6381 * @param {String} eventName The type of event
6382 * @param {Function} fn
6383 * @return {Boolean} True if a listener was actually removed
6385 removeListener : function(element, eventName, fn){
6386 return stopListening(element, eventName, fn);
6390 * Fires when the document is ready (before onload and before images are loaded). Can be
6391 * accessed shorthanded Roo.onReady().
6392 * @param {Function} fn The method the event invokes
6393 * @param {Object} scope An object that becomes the scope of the handler
6394 * @param {boolean} options
6396 onDocumentReady : function(fn, scope, options){
6397 if(docReadyState){ // if it already fired
6398 docReadyEvent.addListener(fn, scope, options);
6399 docReadyEvent.fire();
6400 docReadyEvent.clearListeners();
6406 docReadyEvent.addListener(fn, scope, options);
6410 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6411 * @param {Function} fn The method the event invokes
6412 * @param {Object} scope An object that becomes the scope of the handler
6413 * @param {boolean} options
6415 onWindowResize : function(fn, scope, options){
6417 resizeEvent = new Roo.util.Event();
6418 resizeTask = new Roo.util.DelayedTask(function(){
6419 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6421 E.on(window, "resize", function(){
6423 resizeTask.delay(50);
6425 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6429 resizeEvent.addListener(fn, scope, options);
6433 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6434 * @param {Function} fn The method the event invokes
6435 * @param {Object} scope An object that becomes the scope of the handler
6436 * @param {boolean} options
6438 onTextResize : function(fn, scope, options){
6440 textEvent = new Roo.util.Event();
6441 var textEl = new Roo.Element(document.createElement('div'));
6442 textEl.dom.className = 'x-text-resize';
6443 textEl.dom.innerHTML = 'X';
6444 textEl.appendTo(document.body);
6445 textSize = textEl.dom.offsetHeight;
6446 setInterval(function(){
6447 if(textEl.dom.offsetHeight != textSize){
6448 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6450 }, this.textResizeInterval);
6452 textEvent.addListener(fn, scope, options);
6456 * Removes the passed window resize listener.
6457 * @param {Function} fn The method the event invokes
6458 * @param {Object} scope The scope of handler
6460 removeResizeListener : function(fn, scope){
6462 resizeEvent.removeListener(fn, scope);
6467 fireResize : function(){
6469 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6473 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6477 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6479 textResizeInterval : 50
6484 * @scopeAlias pub=Roo.EventManager
6488 * Appends an event handler to an element (shorthand for addListener)
6489 * @param {String/HTMLElement} element The html element or id to assign the
6490 * @param {String} eventName The type of event to listen for
6491 * @param {Function} handler The method the event invokes
6492 * @param {Object} scope (optional) The scope in which to execute the handler
6493 * function. The handler function's "this" context.
6494 * @param {Object} options (optional) An object containing handler configuration
6495 * properties. This may contain any of the following properties:<ul>
6496 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6497 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6498 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6499 * <li>preventDefault {Boolean} True to prevent the default action</li>
6500 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6501 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6502 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6503 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6504 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6505 * by the specified number of milliseconds. If the event fires again within that time, the original
6506 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6509 * <b>Combining Options</b><br>
6510 * Using the options argument, it is possible to combine different types of listeners:<br>
6512 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6514 el.on('click', this.onClick, this, {
6521 * <b>Attaching multiple handlers in 1 call</b><br>
6522 * The method also allows for a single argument to be passed which is a config object containing properties
6523 * which specify multiple handlers.
6533 fn: this.onMouseOver
6542 * Or a shorthand syntax:<br>
6545 'click' : this.onClick,
6546 'mouseover' : this.onMouseOver,
6547 'mouseout' : this.onMouseOut
6551 pub.on = pub.addListener;
6552 pub.un = pub.removeListener;
6554 pub.stoppedMouseDownEvent = new Roo.util.Event();
6558 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6559 * @param {Function} fn The method the event invokes
6560 * @param {Object} scope An object that becomes the scope of the handler
6561 * @param {boolean} override If true, the obj passed in becomes
6562 * the execution scope of the listener
6566 Roo.onReady = Roo.EventManager.onDocumentReady;
6568 Roo.onReady(function(){
6569 var bd = Roo.get(document.body);
6574 : Roo.isGecko ? "roo-gecko"
6575 : Roo.isOpera ? "roo-opera"
6576 : Roo.isSafari ? "roo-safari" : ""];
6579 cls.push("roo-mac");
6582 cls.push("roo-linux");
6585 cls.push("roo-ios");
6588 cls.push("roo-touch");
6590 if(Roo.isBorderBox){
6591 cls.push('roo-border-box');
6593 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6594 var p = bd.dom.parentNode;
6596 p.className += ' roo-strict';
6599 bd.addClass(cls.join(' '));
6603 * @class Roo.EventObject
6604 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6605 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6608 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6610 var target = e.getTarget();
6613 var myDiv = Roo.get("myDiv");
6614 myDiv.on("click", handleClick);
6616 Roo.EventManager.on("myDiv", 'click', handleClick);
6617 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6621 Roo.EventObject = function(){
6623 var E = Roo.lib.Event;
6625 // safari keypress events for special keys return bad keycodes
6628 63235 : 39, // right
6631 63276 : 33, // page up
6632 63277 : 34, // page down
6633 63272 : 46, // delete
6638 // normalize button clicks
6639 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6640 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6642 Roo.EventObjectImpl = function(e){
6644 this.setEvent(e.browserEvent || e);
6647 Roo.EventObjectImpl.prototype = {
6649 * Used to fix doc tools.
6650 * @scope Roo.EventObject.prototype
6656 /** The normal browser event */
6657 browserEvent : null,
6658 /** The button pressed in a mouse event */
6660 /** True if the shift key was down during the event */
6662 /** True if the control key was down during the event */
6664 /** True if the alt key was down during the event */
6723 setEvent : function(e){
6724 if(e == this || (e && e.browserEvent)){ // already wrapped
6727 this.browserEvent = e;
6729 // normalize buttons
6730 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6731 if(e.type == 'click' && this.button == -1){
6735 this.shiftKey = e.shiftKey;
6736 // mac metaKey behaves like ctrlKey
6737 this.ctrlKey = e.ctrlKey || e.metaKey;
6738 this.altKey = e.altKey;
6739 // in getKey these will be normalized for the mac
6740 this.keyCode = e.keyCode;
6741 // keyup warnings on firefox.
6742 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6743 // cache the target for the delayed and or buffered events
6744 this.target = E.getTarget(e);
6746 this.xy = E.getXY(e);
6749 this.shiftKey = false;
6750 this.ctrlKey = false;
6751 this.altKey = false;
6761 * Stop the event (preventDefault and stopPropagation)
6763 stopEvent : function(){
6764 if(this.browserEvent){
6765 if(this.browserEvent.type == 'mousedown'){
6766 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6768 E.stopEvent(this.browserEvent);
6773 * Prevents the browsers default handling of the event.
6775 preventDefault : function(){
6776 if(this.browserEvent){
6777 E.preventDefault(this.browserEvent);
6782 isNavKeyPress : function(){
6783 var k = this.keyCode;
6784 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6785 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6788 isSpecialKey : function(){
6789 var k = this.keyCode;
6790 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6791 (k == 16) || (k == 17) ||
6792 (k >= 18 && k <= 20) ||
6793 (k >= 33 && k <= 35) ||
6794 (k >= 36 && k <= 39) ||
6795 (k >= 44 && k <= 45);
6798 * Cancels bubbling of the event.
6800 stopPropagation : function(){
6801 if(this.browserEvent){
6802 if(this.type == 'mousedown'){
6803 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6805 E.stopPropagation(this.browserEvent);
6810 * Gets the key code for the event.
6813 getCharCode : function(){
6814 return this.charCode || this.keyCode;
6818 * Returns a normalized keyCode for the event.
6819 * @return {Number} The key code
6821 getKey : function(){
6822 var k = this.keyCode || this.charCode;
6823 return Roo.isSafari ? (safariKeys[k] || k) : k;
6827 * Gets the x coordinate of the event.
6830 getPageX : function(){
6835 * Gets the y coordinate of the event.
6838 getPageY : function(){
6843 * Gets the time of the event.
6846 getTime : function(){
6847 if(this.browserEvent){
6848 return E.getTime(this.browserEvent);
6854 * Gets the page coordinates of the event.
6855 * @return {Array} The xy values like [x, y]
6862 * Gets the target for the event.
6863 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6864 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6865 search as a number or element (defaults to 10 || document.body)
6866 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6867 * @return {HTMLelement}
6869 getTarget : function(selector, maxDepth, returnEl){
6870 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6873 * Gets the related target.
6874 * @return {HTMLElement}
6876 getRelatedTarget : function(){
6877 if(this.browserEvent){
6878 return E.getRelatedTarget(this.browserEvent);
6884 * Normalizes mouse wheel delta across browsers
6885 * @return {Number} The delta
6887 getWheelDelta : function(){
6888 var e = this.browserEvent;
6890 if(e.wheelDelta){ /* IE/Opera. */
6891 delta = e.wheelDelta/120;
6892 }else if(e.detail){ /* Mozilla case. */
6893 delta = -e.detail/3;
6899 * Returns true if the control, meta, shift or alt key was pressed during this event.
6902 hasModifier : function(){
6903 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6907 * Returns true if the target of this event equals el or is a child of el
6908 * @param {String/HTMLElement/Element} el
6909 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6912 within : function(el, related){
6913 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6914 return t && Roo.fly(el).contains(t);
6917 getPoint : function(){
6918 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6922 return new Roo.EventObjectImpl();
6927 * Ext JS Library 1.1.1
6928 * Copyright(c) 2006-2007, Ext JS, LLC.
6930 * Originally Released Under LGPL - original licence link has changed is not relivant.
6933 * <script type="text/javascript">
6937 // was in Composite Element!??!?!
6940 var D = Roo.lib.Dom;
6941 var E = Roo.lib.Event;
6942 var A = Roo.lib.Anim;
6944 // local style camelizing for speed
6946 var camelRe = /(-[a-z])/gi;
6947 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6948 var view = document.defaultView;
6951 * @class Roo.Element
6952 * Represents an Element in the DOM.<br><br>
6955 var el = Roo.get("my-div");
6958 var el = getEl("my-div");
6960 // or with a DOM element
6961 var el = Roo.get(myDivElement);
6963 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6964 * each call instead of constructing a new one.<br><br>
6965 * <b>Animations</b><br />
6966 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6967 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6969 Option Default Description
6970 --------- -------- ---------------------------------------------
6971 duration .35 The duration of the animation in seconds
6972 easing easeOut The YUI easing method
6973 callback none A function to execute when the anim completes
6974 scope this The scope (this) of the callback function
6976 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6977 * manipulate the animation. Here's an example:
6979 var el = Roo.get("my-div");
6984 // default animation
6985 el.setWidth(100, true);
6987 // animation with some options set
6994 // using the "anim" property to get the Anim object
7000 el.setWidth(100, opt);
7002 if(opt.anim.isAnimated()){
7006 * <b> Composite (Collections of) Elements</b><br />
7007 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7008 * @constructor Create a new Element directly.
7009 * @param {String/HTMLElement} element
7010 * @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).
7012 Roo.Element = function(element, forceNew){
7013 var dom = typeof element == "string" ?
7014 document.getElementById(element) : element;
7015 if(!dom){ // invalid id/element
7019 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7020 return Roo.Element.cache[id];
7030 * The DOM element ID
7033 this.id = id || Roo.id(dom);
7036 var El = Roo.Element;
7040 * The element's default display mode (defaults to "")
7043 originalDisplay : "",
7047 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7053 * Sets the element's visibility mode. When setVisible() is called it
7054 * will use this to determine whether to set the visibility or the display property.
7055 * @param visMode Element.VISIBILITY or Element.DISPLAY
7056 * @return {Roo.Element} this
7058 setVisibilityMode : function(visMode){
7059 this.visibilityMode = visMode;
7063 * Convenience method for setVisibilityMode(Element.DISPLAY)
7064 * @param {String} display (optional) What to set display to when visible
7065 * @return {Roo.Element} this
7067 enableDisplayMode : function(display){
7068 this.setVisibilityMode(El.DISPLAY);
7069 if(typeof display != "undefined") this.originalDisplay = display;
7074 * 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)
7075 * @param {String} selector The simple selector to test
7076 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7077 search as a number or element (defaults to 10 || document.body)
7078 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7079 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7081 findParent : function(simpleSelector, maxDepth, returnEl){
7082 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7083 maxDepth = maxDepth || 50;
7084 if(typeof maxDepth != "number"){
7085 stopEl = Roo.getDom(maxDepth);
7088 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7089 if(dq.is(p, simpleSelector)){
7090 return returnEl ? Roo.get(p) : p;
7100 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7101 * @param {String} selector The simple selector to test
7102 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7103 search as a number or element (defaults to 10 || document.body)
7104 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7105 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7107 findParentNode : function(simpleSelector, maxDepth, returnEl){
7108 var p = Roo.fly(this.dom.parentNode, '_internal');
7109 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7113 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7114 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7115 * @param {String} selector The simple selector to test
7116 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7117 search as a number or element (defaults to 10 || document.body)
7118 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7120 up : function(simpleSelector, maxDepth){
7121 return this.findParentNode(simpleSelector, maxDepth, true);
7127 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7128 * @param {String} selector The simple selector to test
7129 * @return {Boolean} True if this element matches the selector, else false
7131 is : function(simpleSelector){
7132 return Roo.DomQuery.is(this.dom, simpleSelector);
7136 * Perform animation on this element.
7137 * @param {Object} args The YUI animation control args
7138 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7139 * @param {Function} onComplete (optional) Function to call when animation completes
7140 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7141 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7142 * @return {Roo.Element} this
7144 animate : function(args, duration, onComplete, easing, animType){
7145 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7150 * @private Internal animation call
7152 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7153 animType = animType || 'run';
7155 var anim = Roo.lib.Anim[animType](
7157 (opt.duration || defaultDur) || .35,
7158 (opt.easing || defaultEase) || 'easeOut',
7160 Roo.callback(cb, this);
7161 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7169 // private legacy anim prep
7170 preanim : function(a, i){
7171 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7175 * Removes worthless text nodes
7176 * @param {Boolean} forceReclean (optional) By default the element
7177 * keeps track if it has been cleaned already so
7178 * you can call this over and over. However, if you update the element and
7179 * need to force a reclean, you can pass true.
7181 clean : function(forceReclean){
7182 if(this.isCleaned && forceReclean !== true){
7186 var d = this.dom, n = d.firstChild, ni = -1;
7188 var nx = n.nextSibling;
7189 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7196 this.isCleaned = true;
7201 calcOffsetsTo : function(el){
7204 var restorePos = false;
7205 if(el.getStyle('position') == 'static'){
7206 el.position('relative');
7211 while(op && op != d && op.tagName != 'HTML'){
7214 op = op.offsetParent;
7217 el.position('static');
7223 * Scrolls this element into view within the passed container.
7224 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7225 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7226 * @return {Roo.Element} this
7228 scrollIntoView : function(container, hscroll){
7229 var c = Roo.getDom(container) || document.body;
7232 var o = this.calcOffsetsTo(c),
7235 b = t+el.offsetHeight,
7236 r = l+el.offsetWidth;
7238 var ch = c.clientHeight;
7239 var ct = parseInt(c.scrollTop, 10);
7240 var cl = parseInt(c.scrollLeft, 10);
7242 var cr = cl + c.clientWidth;
7250 if(hscroll !== false){
7254 c.scrollLeft = r-c.clientWidth;
7261 scrollChildIntoView : function(child, hscroll){
7262 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7266 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7267 * the new height may not be available immediately.
7268 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7269 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7270 * @param {Function} onComplete (optional) Function to call when animation completes
7271 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7272 * @return {Roo.Element} this
7274 autoHeight : function(animate, duration, onComplete, easing){
7275 var oldHeight = this.getHeight();
7277 this.setHeight(1); // force clipping
7278 setTimeout(function(){
7279 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7281 this.setHeight(height);
7283 if(typeof onComplete == "function"){
7287 this.setHeight(oldHeight); // restore original height
7288 this.setHeight(height, animate, duration, function(){
7290 if(typeof onComplete == "function") onComplete();
7291 }.createDelegate(this), easing);
7293 }.createDelegate(this), 0);
7298 * Returns true if this element is an ancestor of the passed element
7299 * @param {HTMLElement/String} el The element to check
7300 * @return {Boolean} True if this element is an ancestor of el, else false
7302 contains : function(el){
7303 if(!el){return false;}
7304 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7308 * Checks whether the element is currently visible using both visibility and display properties.
7309 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7310 * @return {Boolean} True if the element is currently visible, else false
7312 isVisible : function(deep) {
7313 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7314 if(deep !== true || !vis){
7317 var p = this.dom.parentNode;
7318 while(p && p.tagName.toLowerCase() != "body"){
7319 if(!Roo.fly(p, '_isVisible').isVisible()){
7328 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7329 * @param {String} selector The CSS selector
7330 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7331 * @return {CompositeElement/CompositeElementLite} The composite element
7333 select : function(selector, unique){
7334 return El.select(selector, unique, this.dom);
7338 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7339 * @param {String} selector The CSS selector
7340 * @return {Array} An array of the matched nodes
7342 query : function(selector, unique){
7343 return Roo.DomQuery.select(selector, this.dom);
7347 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7348 * @param {String} selector The CSS selector
7349 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7350 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7352 child : function(selector, returnDom){
7353 var n = Roo.DomQuery.selectNode(selector, this.dom);
7354 return returnDom ? n : Roo.get(n);
7358 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7359 * @param {String} selector The CSS selector
7360 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7361 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7363 down : function(selector, returnDom){
7364 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7365 return returnDom ? n : Roo.get(n);
7369 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7370 * @param {String} group The group the DD object is member of
7371 * @param {Object} config The DD config object
7372 * @param {Object} overrides An object containing methods to override/implement on the DD object
7373 * @return {Roo.dd.DD} The DD object
7375 initDD : function(group, config, overrides){
7376 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7377 return Roo.apply(dd, overrides);
7381 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7382 * @param {String} group The group the DDProxy object is member of
7383 * @param {Object} config The DDProxy config object
7384 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7385 * @return {Roo.dd.DDProxy} The DDProxy object
7387 initDDProxy : function(group, config, overrides){
7388 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7389 return Roo.apply(dd, overrides);
7393 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7394 * @param {String} group The group the DDTarget object is member of
7395 * @param {Object} config The DDTarget config object
7396 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7397 * @return {Roo.dd.DDTarget} The DDTarget object
7399 initDDTarget : function(group, config, overrides){
7400 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7401 return Roo.apply(dd, overrides);
7405 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7406 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7407 * @param {Boolean} visible Whether the element is visible
7408 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7409 * @return {Roo.Element} this
7411 setVisible : function(visible, animate){
7413 if(this.visibilityMode == El.DISPLAY){
7414 this.setDisplayed(visible);
7417 this.dom.style.visibility = visible ? "visible" : "hidden";
7420 // closure for composites
7422 var visMode = this.visibilityMode;
7424 this.setOpacity(.01);
7425 this.setVisible(true);
7427 this.anim({opacity: { to: (visible?1:0) }},
7428 this.preanim(arguments, 1),
7429 null, .35, 'easeIn', function(){
7431 if(visMode == El.DISPLAY){
7432 dom.style.display = "none";
7434 dom.style.visibility = "hidden";
7436 Roo.get(dom).setOpacity(1);
7444 * Returns true if display is not "none"
7447 isDisplayed : function() {
7448 return this.getStyle("display") != "none";
7452 * Toggles the element's visibility or display, depending on visibility mode.
7453 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7454 * @return {Roo.Element} this
7456 toggle : function(animate){
7457 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7462 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7463 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7464 * @return {Roo.Element} this
7466 setDisplayed : function(value) {
7467 if(typeof value == "boolean"){
7468 value = value ? this.originalDisplay : "none";
7470 this.setStyle("display", value);
7475 * Tries to focus the element. Any exceptions are caught and ignored.
7476 * @return {Roo.Element} this
7478 focus : function() {
7486 * Tries to blur the element. Any exceptions are caught and ignored.
7487 * @return {Roo.Element} this
7497 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7498 * @param {String/Array} className The CSS class to add, or an array of classes
7499 * @return {Roo.Element} this
7501 addClass : function(className){
7502 if(className instanceof Array){
7503 for(var i = 0, len = className.length; i < len; i++) {
7504 this.addClass(className[i]);
7507 if(className && !this.hasClass(className)){
7508 this.dom.className = this.dom.className + " " + className;
7515 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7516 * @param {String/Array} className The CSS class to add, or an array of classes
7517 * @return {Roo.Element} this
7519 radioClass : function(className){
7520 var siblings = this.dom.parentNode.childNodes;
7521 for(var i = 0; i < siblings.length; i++) {
7522 var s = siblings[i];
7523 if(s.nodeType == 1){
7524 Roo.get(s).removeClass(className);
7527 this.addClass(className);
7532 * Removes one or more CSS classes from the element.
7533 * @param {String/Array} className The CSS class to remove, or an array of classes
7534 * @return {Roo.Element} this
7536 removeClass : function(className){
7537 if(!className || !this.dom.className){
7540 if(className instanceof Array){
7541 for(var i = 0, len = className.length; i < len; i++) {
7542 this.removeClass(className[i]);
7545 if(this.hasClass(className)){
7546 var re = this.classReCache[className];
7548 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7549 this.classReCache[className] = re;
7551 this.dom.className =
7552 this.dom.className.replace(re, " ");
7562 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7563 * @param {String} className The CSS class to toggle
7564 * @return {Roo.Element} this
7566 toggleClass : function(className){
7567 if(this.hasClass(className)){
7568 this.removeClass(className);
7570 this.addClass(className);
7576 * Checks if the specified CSS class exists on this element's DOM node.
7577 * @param {String} className The CSS class to check for
7578 * @return {Boolean} True if the class exists, else false
7580 hasClass : function(className){
7581 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7585 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7586 * @param {String} oldClassName The CSS class to replace
7587 * @param {String} newClassName The replacement CSS class
7588 * @return {Roo.Element} this
7590 replaceClass : function(oldClassName, newClassName){
7591 this.removeClass(oldClassName);
7592 this.addClass(newClassName);
7597 * Returns an object with properties matching the styles requested.
7598 * For example, el.getStyles('color', 'font-size', 'width') might return
7599 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7600 * @param {String} style1 A style name
7601 * @param {String} style2 A style name
7602 * @param {String} etc.
7603 * @return {Object} The style object
7605 getStyles : function(){
7606 var a = arguments, len = a.length, r = {};
7607 for(var i = 0; i < len; i++){
7608 r[a[i]] = this.getStyle(a[i]);
7614 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7615 * @param {String} property The style property whose value is returned.
7616 * @return {String} The current value of the style property for this element.
7618 getStyle : function(){
7619 return view && view.getComputedStyle ?
7621 var el = this.dom, v, cs, camel;
7622 if(prop == 'float'){
7625 if(el.style && (v = el.style[prop])){
7628 if(cs = view.getComputedStyle(el, "")){
7629 if(!(camel = propCache[prop])){
7630 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7637 var el = this.dom, v, cs, camel;
7638 if(prop == 'opacity'){
7639 if(typeof el.style.filter == 'string'){
7640 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7642 var fv = parseFloat(m[1]);
7644 return fv ? fv / 100 : 0;
7649 }else if(prop == 'float'){
7650 prop = "styleFloat";
7652 if(!(camel = propCache[prop])){
7653 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7655 if(v = el.style[camel]){
7658 if(cs = el.currentStyle){
7666 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7667 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7668 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7669 * @return {Roo.Element} this
7671 setStyle : function(prop, value){
7672 if(typeof prop == "string"){
7674 if (prop == 'float') {
7675 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7680 if(!(camel = propCache[prop])){
7681 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7684 if(camel == 'opacity') {
7685 this.setOpacity(value);
7687 this.dom.style[camel] = value;
7690 for(var style in prop){
7691 if(typeof prop[style] != "function"){
7692 this.setStyle(style, prop[style]);
7700 * More flexible version of {@link #setStyle} for setting style properties.
7701 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7702 * a function which returns such a specification.
7703 * @return {Roo.Element} this
7705 applyStyles : function(style){
7706 Roo.DomHelper.applyStyles(this.dom, style);
7711 * 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).
7712 * @return {Number} The X position of the element
7715 return D.getX(this.dom);
7719 * 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).
7720 * @return {Number} The Y position of the element
7723 return D.getY(this.dom);
7727 * 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).
7728 * @return {Array} The XY position of the element
7731 return D.getXY(this.dom);
7735 * 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).
7736 * @param {Number} The X position of the element
7737 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7738 * @return {Roo.Element} this
7740 setX : function(x, animate){
7742 D.setX(this.dom, x);
7744 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7750 * 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).
7751 * @param {Number} The Y position of the element
7752 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7753 * @return {Roo.Element} this
7755 setY : function(y, animate){
7757 D.setY(this.dom, y);
7759 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7765 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7766 * @param {String} left The left CSS property value
7767 * @return {Roo.Element} this
7769 setLeft : function(left){
7770 this.setStyle("left", this.addUnits(left));
7775 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7776 * @param {String} top The top CSS property value
7777 * @return {Roo.Element} this
7779 setTop : function(top){
7780 this.setStyle("top", this.addUnits(top));
7785 * Sets the element's CSS right style.
7786 * @param {String} right The right CSS property value
7787 * @return {Roo.Element} this
7789 setRight : function(right){
7790 this.setStyle("right", this.addUnits(right));
7795 * Sets the element's CSS bottom style.
7796 * @param {String} bottom The bottom CSS property value
7797 * @return {Roo.Element} this
7799 setBottom : function(bottom){
7800 this.setStyle("bottom", this.addUnits(bottom));
7805 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7806 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7807 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7808 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7809 * @return {Roo.Element} this
7811 setXY : function(pos, animate){
7813 D.setXY(this.dom, pos);
7815 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7821 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7822 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7823 * @param {Number} x X value for new position (coordinates are page-based)
7824 * @param {Number} y Y value for new position (coordinates are page-based)
7825 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7826 * @return {Roo.Element} this
7828 setLocation : function(x, y, animate){
7829 this.setXY([x, y], this.preanim(arguments, 2));
7834 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7835 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7836 * @param {Number} x X value for new position (coordinates are page-based)
7837 * @param {Number} y Y value for new position (coordinates are page-based)
7838 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7839 * @return {Roo.Element} this
7841 moveTo : function(x, y, animate){
7842 this.setXY([x, y], this.preanim(arguments, 2));
7847 * Returns the region of the given element.
7848 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7849 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7851 getRegion : function(){
7852 return D.getRegion(this.dom);
7856 * Returns the offset height of the element
7857 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7858 * @return {Number} The element's height
7860 getHeight : function(contentHeight){
7861 var h = this.dom.offsetHeight || 0;
7862 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7866 * Returns the offset width of the element
7867 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7868 * @return {Number} The element's width
7870 getWidth : function(contentWidth){
7871 var w = this.dom.offsetWidth || 0;
7872 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7876 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7877 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7878 * if a height has not been set using CSS.
7881 getComputedHeight : function(){
7882 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7884 h = parseInt(this.getStyle('height'), 10) || 0;
7885 if(!this.isBorderBox()){
7886 h += this.getFrameWidth('tb');
7893 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7894 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7895 * if a width has not been set using CSS.
7898 getComputedWidth : function(){
7899 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7901 w = parseInt(this.getStyle('width'), 10) || 0;
7902 if(!this.isBorderBox()){
7903 w += this.getFrameWidth('lr');
7910 * Returns the size of the element.
7911 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7912 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7914 getSize : function(contentSize){
7915 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7919 * Returns the width and height of the viewport.
7920 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7922 getViewSize : function(){
7923 var d = this.dom, doc = document, aw = 0, ah = 0;
7924 if(d == doc || d == doc.body){
7925 return {width : D.getViewWidth(), height: D.getViewHeight()};
7928 width : d.clientWidth,
7929 height: d.clientHeight
7935 * Returns the value of the "value" attribute
7936 * @param {Boolean} asNumber true to parse the value as a number
7937 * @return {String/Number}
7939 getValue : function(asNumber){
7940 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7944 adjustWidth : function(width){
7945 if(typeof width == "number"){
7946 if(this.autoBoxAdjust && !this.isBorderBox()){
7947 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7957 adjustHeight : function(height){
7958 if(typeof height == "number"){
7959 if(this.autoBoxAdjust && !this.isBorderBox()){
7960 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7970 * Set the width of the element
7971 * @param {Number} width The new width
7972 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7973 * @return {Roo.Element} this
7975 setWidth : function(width, animate){
7976 width = this.adjustWidth(width);
7978 this.dom.style.width = this.addUnits(width);
7980 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7986 * Set the height of the element
7987 * @param {Number} height The new height
7988 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7989 * @return {Roo.Element} this
7991 setHeight : function(height, animate){
7992 height = this.adjustHeight(height);
7994 this.dom.style.height = this.addUnits(height);
7996 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8002 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8003 * @param {Number} width The new width
8004 * @param {Number} height The new height
8005 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8006 * @return {Roo.Element} this
8008 setSize : function(width, height, animate){
8009 if(typeof width == "object"){ // in case of object from getSize()
8010 height = width.height; width = width.width;
8012 width = this.adjustWidth(width); height = this.adjustHeight(height);
8014 this.dom.style.width = this.addUnits(width);
8015 this.dom.style.height = this.addUnits(height);
8017 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8023 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8024 * @param {Number} x X value for new position (coordinates are page-based)
8025 * @param {Number} y Y value for new position (coordinates are page-based)
8026 * @param {Number} width The new width
8027 * @param {Number} height The new height
8028 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8029 * @return {Roo.Element} this
8031 setBounds : function(x, y, width, height, animate){
8033 this.setSize(width, height);
8034 this.setLocation(x, y);
8036 width = this.adjustWidth(width); height = this.adjustHeight(height);
8037 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8038 this.preanim(arguments, 4), 'motion');
8044 * 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.
8045 * @param {Roo.lib.Region} region The region to fill
8046 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8047 * @return {Roo.Element} this
8049 setRegion : function(region, animate){
8050 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8055 * Appends an event handler
8057 * @param {String} eventName The type of event to append
8058 * @param {Function} fn The method the event invokes
8059 * @param {Object} scope (optional) The scope (this object) of the fn
8060 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8062 addListener : function(eventName, fn, scope, options){
8064 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8069 * Removes an event handler from this element
8070 * @param {String} eventName the type of event to remove
8071 * @param {Function} fn the method the event invokes
8072 * @return {Roo.Element} this
8074 removeListener : function(eventName, fn){
8075 Roo.EventManager.removeListener(this.dom, eventName, fn);
8080 * Removes all previous added listeners from this element
8081 * @return {Roo.Element} this
8083 removeAllListeners : function(){
8084 E.purgeElement(this.dom);
8088 relayEvent : function(eventName, observable){
8089 this.on(eventName, function(e){
8090 observable.fireEvent(eventName, e);
8095 * Set the opacity of the element
8096 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8097 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8098 * @return {Roo.Element} this
8100 setOpacity : function(opacity, animate){
8102 var s = this.dom.style;
8105 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8106 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8108 s.opacity = opacity;
8111 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8117 * Gets the left X coordinate
8118 * @param {Boolean} local True to get the local css position instead of page coordinate
8121 getLeft : function(local){
8125 return parseInt(this.getStyle("left"), 10) || 0;
8130 * Gets the right X coordinate of the element (element X position + element width)
8131 * @param {Boolean} local True to get the local css position instead of page coordinate
8134 getRight : function(local){
8136 return this.getX() + this.getWidth();
8138 return (this.getLeft(true) + this.getWidth()) || 0;
8143 * Gets the top Y coordinate
8144 * @param {Boolean} local True to get the local css position instead of page coordinate
8147 getTop : function(local) {
8151 return parseInt(this.getStyle("top"), 10) || 0;
8156 * Gets the bottom Y coordinate of the element (element Y position + element height)
8157 * @param {Boolean} local True to get the local css position instead of page coordinate
8160 getBottom : function(local){
8162 return this.getY() + this.getHeight();
8164 return (this.getTop(true) + this.getHeight()) || 0;
8169 * Initializes positioning on this element. If a desired position is not passed, it will make the
8170 * the element positioned relative IF it is not already positioned.
8171 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8172 * @param {Number} zIndex (optional) The zIndex to apply
8173 * @param {Number} x (optional) Set the page X position
8174 * @param {Number} y (optional) Set the page Y position
8176 position : function(pos, zIndex, x, y){
8178 if(this.getStyle('position') == 'static'){
8179 this.setStyle('position', 'relative');
8182 this.setStyle("position", pos);
8185 this.setStyle("z-index", zIndex);
8187 if(x !== undefined && y !== undefined){
8189 }else if(x !== undefined){
8191 }else if(y !== undefined){
8197 * Clear positioning back to the default when the document was loaded
8198 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8199 * @return {Roo.Element} this
8201 clearPositioning : function(value){
8209 "position" : "static"
8215 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8216 * snapshot before performing an update and then restoring the element.
8219 getPositioning : function(){
8220 var l = this.getStyle("left");
8221 var t = this.getStyle("top");
8223 "position" : this.getStyle("position"),
8225 "right" : l ? "" : this.getStyle("right"),
8227 "bottom" : t ? "" : this.getStyle("bottom"),
8228 "z-index" : this.getStyle("z-index")
8233 * Gets the width of the border(s) for the specified side(s)
8234 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8235 * passing lr would get the border (l)eft width + the border (r)ight width.
8236 * @return {Number} The width of the sides passed added together
8238 getBorderWidth : function(side){
8239 return this.addStyles(side, El.borders);
8243 * Gets the width of the padding(s) for the specified side(s)
8244 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8245 * passing lr would get the padding (l)eft + the padding (r)ight.
8246 * @return {Number} The padding of the sides passed added together
8248 getPadding : function(side){
8249 return this.addStyles(side, El.paddings);
8253 * Set positioning with an object returned by getPositioning().
8254 * @param {Object} posCfg
8255 * @return {Roo.Element} this
8257 setPositioning : function(pc){
8258 this.applyStyles(pc);
8259 if(pc.right == "auto"){
8260 this.dom.style.right = "";
8262 if(pc.bottom == "auto"){
8263 this.dom.style.bottom = "";
8269 fixDisplay : function(){
8270 if(this.getStyle("display") == "none"){
8271 this.setStyle("visibility", "hidden");
8272 this.setStyle("display", this.originalDisplay); // first try reverting to default
8273 if(this.getStyle("display") == "none"){ // if that fails, default to block
8274 this.setStyle("display", "block");
8280 * Quick set left and top adding default units
8281 * @param {String} left The left CSS property value
8282 * @param {String} top The top CSS property value
8283 * @return {Roo.Element} this
8285 setLeftTop : function(left, top){
8286 this.dom.style.left = this.addUnits(left);
8287 this.dom.style.top = this.addUnits(top);
8292 * Move this element relative to its current position.
8293 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8294 * @param {Number} distance How far to move the element in pixels
8295 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8296 * @return {Roo.Element} this
8298 move : function(direction, distance, animate){
8299 var xy = this.getXY();
8300 direction = direction.toLowerCase();
8304 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8308 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8313 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8318 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8325 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8326 * @return {Roo.Element} this
8329 if(!this.isClipped){
8330 this.isClipped = true;
8331 this.originalClip = {
8332 "o": this.getStyle("overflow"),
8333 "x": this.getStyle("overflow-x"),
8334 "y": this.getStyle("overflow-y")
8336 this.setStyle("overflow", "hidden");
8337 this.setStyle("overflow-x", "hidden");
8338 this.setStyle("overflow-y", "hidden");
8344 * Return clipping (overflow) to original clipping before clip() was called
8345 * @return {Roo.Element} this
8347 unclip : function(){
8349 this.isClipped = false;
8350 var o = this.originalClip;
8351 if(o.o){this.setStyle("overflow", o.o);}
8352 if(o.x){this.setStyle("overflow-x", o.x);}
8353 if(o.y){this.setStyle("overflow-y", o.y);}
8360 * Gets the x,y coordinates specified by the anchor position on the element.
8361 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8362 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8363 * {width: (target width), height: (target height)} (defaults to the element's current size)
8364 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8365 * @return {Array} [x, y] An array containing the element's x and y coordinates
8367 getAnchorXY : function(anchor, local, s){
8368 //Passing a different size is useful for pre-calculating anchors,
8369 //especially for anchored animations that change the el size.
8371 var w, h, vp = false;
8374 if(d == document.body || d == document){
8376 w = D.getViewWidth(); h = D.getViewHeight();
8378 w = this.getWidth(); h = this.getHeight();
8381 w = s.width; h = s.height;
8383 var x = 0, y = 0, r = Math.round;
8384 switch((anchor || "tl").toLowerCase()){
8426 var sc = this.getScroll();
8427 return [x + sc.left, y + sc.top];
8429 //Add the element's offset xy
8430 var o = this.getXY();
8431 return [x+o[0], y+o[1]];
8435 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8436 * supported position values.
8437 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8438 * @param {String} position The position to align to.
8439 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8440 * @return {Array} [x, y]
8442 getAlignToXY : function(el, p, o){
8446 throw "Element.alignTo with an element that doesn't exist";
8448 var c = false; //constrain to viewport
8449 var p1 = "", p2 = "";
8456 }else if(p.indexOf("-") == -1){
8459 p = p.toLowerCase();
8460 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8462 throw "Element.alignTo with an invalid alignment " + p;
8464 p1 = m[1]; p2 = m[2]; c = !!m[3];
8466 //Subtract the aligned el's internal xy from the target's offset xy
8467 //plus custom offset to get the aligned el's new offset xy
8468 var a1 = this.getAnchorXY(p1, true);
8469 var a2 = el.getAnchorXY(p2, false);
8470 var x = a2[0] - a1[0] + o[0];
8471 var y = a2[1] - a1[1] + o[1];
8473 //constrain the aligned el to viewport if necessary
8474 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8475 // 5px of margin for ie
8476 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8478 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8479 //perpendicular to the vp border, allow the aligned el to slide on that border,
8480 //otherwise swap the aligned el to the opposite border of the target.
8481 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8482 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8483 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8484 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8487 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8488 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8490 if((x+w) > dw + scrollX){
8491 x = swapX ? r.left-w : dw+scrollX-w;
8494 x = swapX ? r.right : scrollX;
8496 if((y+h) > dh + scrollY){
8497 y = swapY ? r.top-h : dh+scrollY-h;
8500 y = swapY ? r.bottom : scrollY;
8507 getConstrainToXY : function(){
8508 var os = {top:0, left:0, bottom:0, right: 0};
8510 return function(el, local, offsets, proposedXY){
8512 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8514 var vw, vh, vx = 0, vy = 0;
8515 if(el.dom == document.body || el.dom == document){
8516 vw = Roo.lib.Dom.getViewWidth();
8517 vh = Roo.lib.Dom.getViewHeight();
8519 vw = el.dom.clientWidth;
8520 vh = el.dom.clientHeight;
8522 var vxy = el.getXY();
8528 var s = el.getScroll();
8530 vx += offsets.left + s.left;
8531 vy += offsets.top + s.top;
8533 vw -= offsets.right;
8534 vh -= offsets.bottom;
8539 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8540 var x = xy[0], y = xy[1];
8541 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8543 // only move it if it needs it
8546 // first validate right/bottom
8555 // then make sure top/left isn't negative
8564 return moved ? [x, y] : false;
8569 adjustForConstraints : function(xy, parent, offsets){
8570 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8574 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8575 * document it aligns it to the viewport.
8576 * The position parameter is optional, and can be specified in any one of the following formats:
8578 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8579 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8580 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8581 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8582 * <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
8583 * element's anchor point, and the second value is used as the target's anchor point.</li>
8585 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8586 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8587 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8588 * that specified in order to enforce the viewport constraints.
8589 * Following are all of the supported anchor positions:
8592 ----- -----------------------------
8593 tl The top left corner (default)
8594 t The center of the top edge
8595 tr The top right corner
8596 l The center of the left edge
8597 c In the center of the element
8598 r The center of the right edge
8599 bl The bottom left corner
8600 b The center of the bottom edge
8601 br The bottom right corner
8605 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8606 el.alignTo("other-el");
8608 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8609 el.alignTo("other-el", "tr?");
8611 // align the bottom right corner of el with the center left edge of other-el
8612 el.alignTo("other-el", "br-l?");
8614 // align the center of el with the bottom left corner of other-el and
8615 // adjust the x position by -6 pixels (and the y position by 0)
8616 el.alignTo("other-el", "c-bl", [-6, 0]);
8618 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8619 * @param {String} position The position to align to.
8620 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8621 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8622 * @return {Roo.Element} this
8624 alignTo : function(element, position, offsets, animate){
8625 var xy = this.getAlignToXY(element, position, offsets);
8626 this.setXY(xy, this.preanim(arguments, 3));
8631 * Anchors an element to another element and realigns it when the window is resized.
8632 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8633 * @param {String} position The position to align to.
8634 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8635 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8636 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8637 * is a number, it is used as the buffer delay (defaults to 50ms).
8638 * @param {Function} callback The function to call after the animation finishes
8639 * @return {Roo.Element} this
8641 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8642 var action = function(){
8643 this.alignTo(el, alignment, offsets, animate);
8644 Roo.callback(callback, this);
8646 Roo.EventManager.onWindowResize(action, this);
8647 var tm = typeof monitorScroll;
8648 if(tm != 'undefined'){
8649 Roo.EventManager.on(window, 'scroll', action, this,
8650 {buffer: tm == 'number' ? monitorScroll : 50});
8652 action.call(this); // align immediately
8656 * Clears any opacity settings from this element. Required in some cases for IE.
8657 * @return {Roo.Element} this
8659 clearOpacity : function(){
8660 if (window.ActiveXObject) {
8661 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8662 this.dom.style.filter = "";
8665 this.dom.style.opacity = "";
8666 this.dom.style["-moz-opacity"] = "";
8667 this.dom.style["-khtml-opacity"] = "";
8673 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8674 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8675 * @return {Roo.Element} this
8677 hide : function(animate){
8678 this.setVisible(false, this.preanim(arguments, 0));
8683 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8684 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8685 * @return {Roo.Element} this
8687 show : function(animate){
8688 this.setVisible(true, this.preanim(arguments, 0));
8693 * @private Test if size has a unit, otherwise appends the default
8695 addUnits : function(size){
8696 return Roo.Element.addUnits(size, this.defaultUnit);
8700 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8701 * @return {Roo.Element} this
8703 beginMeasure : function(){
8705 if(el.offsetWidth || el.offsetHeight){
8706 return this; // offsets work already
8709 var p = this.dom, b = document.body; // start with this element
8710 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8711 var pe = Roo.get(p);
8712 if(pe.getStyle('display') == 'none'){
8713 changed.push({el: p, visibility: pe.getStyle("visibility")});
8714 p.style.visibility = "hidden";
8715 p.style.display = "block";
8719 this._measureChanged = changed;
8725 * Restores displays to before beginMeasure was called
8726 * @return {Roo.Element} this
8728 endMeasure : function(){
8729 var changed = this._measureChanged;
8731 for(var i = 0, len = changed.length; i < len; i++) {
8733 r.el.style.visibility = r.visibility;
8734 r.el.style.display = "none";
8736 this._measureChanged = null;
8742 * Update the innerHTML of this element, optionally searching for and processing scripts
8743 * @param {String} html The new HTML
8744 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8745 * @param {Function} callback For async script loading you can be noticed when the update completes
8746 * @return {Roo.Element} this
8748 update : function(html, loadScripts, callback){
8749 if(typeof html == "undefined"){
8752 if(loadScripts !== true){
8753 this.dom.innerHTML = html;
8754 if(typeof callback == "function"){
8762 html += '<span id="' + id + '"></span>';
8764 E.onAvailable(id, function(){
8765 var hd = document.getElementsByTagName("head")[0];
8766 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8767 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8768 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8771 while(match = re.exec(html)){
8772 var attrs = match[1];
8773 var srcMatch = attrs ? attrs.match(srcRe) : false;
8774 if(srcMatch && srcMatch[2]){
8775 var s = document.createElement("script");
8776 s.src = srcMatch[2];
8777 var typeMatch = attrs.match(typeRe);
8778 if(typeMatch && typeMatch[2]){
8779 s.type = typeMatch[2];
8782 }else if(match[2] && match[2].length > 0){
8783 if(window.execScript) {
8784 window.execScript(match[2]);
8792 window.eval(match[2]);
8796 var el = document.getElementById(id);
8797 if(el){el.parentNode.removeChild(el);}
8798 if(typeof callback == "function"){
8802 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8807 * Direct access to the UpdateManager update() method (takes the same parameters).
8808 * @param {String/Function} url The url for this request or a function to call to get the url
8809 * @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}
8810 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8811 * @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.
8812 * @return {Roo.Element} this
8815 var um = this.getUpdateManager();
8816 um.update.apply(um, arguments);
8821 * Gets this element's UpdateManager
8822 * @return {Roo.UpdateManager} The UpdateManager
8824 getUpdateManager : function(){
8825 if(!this.updateManager){
8826 this.updateManager = new Roo.UpdateManager(this);
8828 return this.updateManager;
8832 * Disables text selection for this element (normalized across browsers)
8833 * @return {Roo.Element} this
8835 unselectable : function(){
8836 this.dom.unselectable = "on";
8837 this.swallowEvent("selectstart", true);
8838 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8839 this.addClass("x-unselectable");
8844 * Calculates the x, y to center this element on the screen
8845 * @return {Array} The x, y values [x, y]
8847 getCenterXY : function(){
8848 return this.getAlignToXY(document, 'c-c');
8852 * Centers the Element in either the viewport, or another Element.
8853 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8855 center : function(centerIn){
8856 this.alignTo(centerIn || document, 'c-c');
8861 * Tests various css rules/browsers to determine if this element uses a border box
8864 isBorderBox : function(){
8865 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8869 * Return a box {x, y, width, height} that can be used to set another elements
8870 * size/location to match this element.
8871 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8872 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8873 * @return {Object} box An object in the format {x, y, width, height}
8875 getBox : function(contentBox, local){
8880 var left = parseInt(this.getStyle("left"), 10) || 0;
8881 var top = parseInt(this.getStyle("top"), 10) || 0;
8884 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8886 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8888 var l = this.getBorderWidth("l")+this.getPadding("l");
8889 var r = this.getBorderWidth("r")+this.getPadding("r");
8890 var t = this.getBorderWidth("t")+this.getPadding("t");
8891 var b = this.getBorderWidth("b")+this.getPadding("b");
8892 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)};
8894 bx.right = bx.x + bx.width;
8895 bx.bottom = bx.y + bx.height;
8900 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8901 for more information about the sides.
8902 * @param {String} sides
8905 getFrameWidth : function(sides, onlyContentBox){
8906 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8910 * 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.
8911 * @param {Object} box The box to fill {x, y, width, height}
8912 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8913 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8914 * @return {Roo.Element} this
8916 setBox : function(box, adjust, animate){
8917 var w = box.width, h = box.height;
8918 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8919 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8920 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8922 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8927 * Forces the browser to repaint this element
8928 * @return {Roo.Element} this
8930 repaint : function(){
8932 this.addClass("x-repaint");
8933 setTimeout(function(){
8934 Roo.get(dom).removeClass("x-repaint");
8940 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8941 * then it returns the calculated width of the sides (see getPadding)
8942 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8943 * @return {Object/Number}
8945 getMargins : function(side){
8948 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8949 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8950 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8951 right: parseInt(this.getStyle("margin-right"), 10) || 0
8954 return this.addStyles(side, El.margins);
8959 addStyles : function(sides, styles){
8961 for(var i = 0, len = sides.length; i < len; i++){
8962 v = this.getStyle(styles[sides.charAt(i)]);
8964 w = parseInt(v, 10);
8972 * Creates a proxy element of this element
8973 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8974 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8975 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8976 * @return {Roo.Element} The new proxy element
8978 createProxy : function(config, renderTo, matchBox){
8980 renderTo = Roo.getDom(renderTo);
8982 renderTo = document.body;
8984 config = typeof config == "object" ?
8985 config : {tag : "div", cls: config};
8986 var proxy = Roo.DomHelper.append(renderTo, config, true);
8988 proxy.setBox(this.getBox());
8994 * Puts a mask over this element to disable user interaction. Requires core.css.
8995 * This method can only be applied to elements which accept child nodes.
8996 * @param {String} msg (optional) A message to display in the mask
8997 * @param {String} msgCls (optional) A css class to apply to the msg element
8998 * @return {Element} The mask element
9000 mask : function(msg, msgCls)
9002 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9003 this.setStyle("position", "relative");
9006 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9008 this.addClass("x-masked");
9009 this._mask.setDisplayed(true);
9014 while (dom && dom.style) {
9015 if (!isNaN(parseInt(dom.style.zIndex))) {
9016 z = Math.max(z, parseInt(dom.style.zIndex));
9018 dom = dom.parentNode;
9020 // if we are masking the body - then it hides everything..
9021 if (this.dom == document.body) {
9023 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9024 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9027 if(typeof msg == 'string'){
9029 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9031 var mm = this._maskMsg;
9032 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9033 if (mm.dom.firstChild) { // weird IE issue?
9034 mm.dom.firstChild.innerHTML = msg;
9036 mm.setDisplayed(true);
9038 mm.setStyle('z-index', z + 102);
9040 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9041 this._mask.setHeight(this.getHeight());
9043 this._mask.setStyle('z-index', z + 100);
9049 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9050 * it is cached for reuse.
9052 unmask : function(removeEl){
9054 if(removeEl === true){
9055 this._mask.remove();
9058 this._maskMsg.remove();
9059 delete this._maskMsg;
9062 this._mask.setDisplayed(false);
9064 this._maskMsg.setDisplayed(false);
9068 this.removeClass("x-masked");
9072 * Returns true if this element is masked
9075 isMasked : function(){
9076 return this._mask && this._mask.isVisible();
9080 * Creates an iframe shim for this element to keep selects and other windowed objects from
9082 * @return {Roo.Element} The new shim element
9084 createShim : function(){
9085 var el = document.createElement('iframe');
9086 el.frameBorder = 'no';
9087 el.className = 'roo-shim';
9088 if(Roo.isIE && Roo.isSecure){
9089 el.src = Roo.SSL_SECURE_URL;
9091 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9092 shim.autoBoxAdjust = false;
9097 * Removes this element from the DOM and deletes it from the cache
9099 remove : function(){
9100 if(this.dom.parentNode){
9101 this.dom.parentNode.removeChild(this.dom);
9103 delete El.cache[this.dom.id];
9107 * Sets up event handlers to add and remove a css class when the mouse is over this element
9108 * @param {String} className
9109 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9110 * mouseout events for children elements
9111 * @return {Roo.Element} this
9113 addClassOnOver : function(className, preventFlicker){
9114 this.on("mouseover", function(){
9115 Roo.fly(this, '_internal').addClass(className);
9117 var removeFn = function(e){
9118 if(preventFlicker !== true || !e.within(this, true)){
9119 Roo.fly(this, '_internal').removeClass(className);
9122 this.on("mouseout", removeFn, this.dom);
9127 * Sets up event handlers to add and remove a css class when this element has the focus
9128 * @param {String} className
9129 * @return {Roo.Element} this
9131 addClassOnFocus : function(className){
9132 this.on("focus", function(){
9133 Roo.fly(this, '_internal').addClass(className);
9135 this.on("blur", function(){
9136 Roo.fly(this, '_internal').removeClass(className);
9141 * 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)
9142 * @param {String} className
9143 * @return {Roo.Element} this
9145 addClassOnClick : function(className){
9147 this.on("mousedown", function(){
9148 Roo.fly(dom, '_internal').addClass(className);
9149 var d = Roo.get(document);
9150 var fn = function(){
9151 Roo.fly(dom, '_internal').removeClass(className);
9152 d.removeListener("mouseup", fn);
9154 d.on("mouseup", fn);
9160 * Stops the specified event from bubbling and optionally prevents the default action
9161 * @param {String} eventName
9162 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9163 * @return {Roo.Element} this
9165 swallowEvent : function(eventName, preventDefault){
9166 var fn = function(e){
9167 e.stopPropagation();
9172 if(eventName instanceof Array){
9173 for(var i = 0, len = eventName.length; i < len; i++){
9174 this.on(eventName[i], fn);
9178 this.on(eventName, fn);
9185 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9188 * Sizes this element to its parent element's dimensions performing
9189 * neccessary box adjustments.
9190 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9191 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9192 * @return {Roo.Element} this
9194 fitToParent : function(monitorResize, targetParent) {
9195 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9196 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9197 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9200 var p = Roo.get(targetParent || this.dom.parentNode);
9201 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9202 if (monitorResize === true) {
9203 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9204 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9210 * Gets the next sibling, skipping text nodes
9211 * @return {HTMLElement} The next sibling or null
9213 getNextSibling : function(){
9214 var n = this.dom.nextSibling;
9215 while(n && n.nodeType != 1){
9222 * Gets the previous sibling, skipping text nodes
9223 * @return {HTMLElement} The previous sibling or null
9225 getPrevSibling : function(){
9226 var n = this.dom.previousSibling;
9227 while(n && n.nodeType != 1){
9228 n = n.previousSibling;
9235 * Appends the passed element(s) to this element
9236 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9237 * @return {Roo.Element} this
9239 appendChild: function(el){
9246 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9247 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9248 * automatically generated with the specified attributes.
9249 * @param {HTMLElement} insertBefore (optional) a child element of this element
9250 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9251 * @return {Roo.Element} The new child element
9253 createChild: function(config, insertBefore, returnDom){
9254 config = config || {tag:'div'};
9256 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9258 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9262 * Appends this element to the passed element
9263 * @param {String/HTMLElement/Element} el The new parent element
9264 * @return {Roo.Element} this
9266 appendTo: function(el){
9267 el = Roo.getDom(el);
9268 el.appendChild(this.dom);
9273 * Inserts this element before the passed element in the DOM
9274 * @param {String/HTMLElement/Element} el The element to insert before
9275 * @return {Roo.Element} this
9277 insertBefore: function(el){
9278 el = Roo.getDom(el);
9279 el.parentNode.insertBefore(this.dom, el);
9284 * Inserts this element after the passed element in the DOM
9285 * @param {String/HTMLElement/Element} el The element to insert after
9286 * @return {Roo.Element} this
9288 insertAfter: function(el){
9289 el = Roo.getDom(el);
9290 el.parentNode.insertBefore(this.dom, el.nextSibling);
9295 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9296 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9297 * @return {Roo.Element} The new child
9299 insertFirst: function(el, returnDom){
9301 if(typeof el == 'object' && !el.nodeType){ // dh config
9302 return this.createChild(el, this.dom.firstChild, returnDom);
9304 el = Roo.getDom(el);
9305 this.dom.insertBefore(el, this.dom.firstChild);
9306 return !returnDom ? Roo.get(el) : el;
9311 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9312 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9313 * @param {String} where (optional) 'before' or 'after' defaults to before
9314 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9315 * @return {Roo.Element} the inserted Element
9317 insertSibling: function(el, where, returnDom){
9318 where = where ? where.toLowerCase() : 'before';
9320 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9322 if(typeof el == 'object' && !el.nodeType){ // dh config
9323 if(where == 'after' && !this.dom.nextSibling){
9324 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9326 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9330 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9331 where == 'before' ? this.dom : this.dom.nextSibling);
9340 * Creates and wraps this element with another element
9341 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9342 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9343 * @return {HTMLElement/Element} The newly created wrapper element
9345 wrap: function(config, returnDom){
9347 config = {tag: "div"};
9349 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9350 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9355 * Replaces the passed element with this element
9356 * @param {String/HTMLElement/Element} el The element to replace
9357 * @return {Roo.Element} this
9359 replace: function(el){
9361 this.insertBefore(el);
9367 * Inserts an html fragment into this element
9368 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9369 * @param {String} html The HTML fragment
9370 * @param {Boolean} returnEl True to return an Roo.Element
9371 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9373 insertHtml : function(where, html, returnEl){
9374 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9375 return returnEl ? Roo.get(el) : el;
9379 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9380 * @param {Object} o The object with the attributes
9381 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9382 * @return {Roo.Element} this
9384 set : function(o, useSet){
9386 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9388 if(attr == "style" || typeof o[attr] == "function") continue;
9390 el.className = o["cls"];
9392 if(useSet) el.setAttribute(attr, o[attr]);
9393 else el[attr] = o[attr];
9397 Roo.DomHelper.applyStyles(el, o.style);
9403 * Convenience method for constructing a KeyMap
9404 * @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:
9405 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9406 * @param {Function} fn The function to call
9407 * @param {Object} scope (optional) The scope of the function
9408 * @return {Roo.KeyMap} The KeyMap created
9410 addKeyListener : function(key, fn, scope){
9412 if(typeof key != "object" || key instanceof Array){
9428 return new Roo.KeyMap(this, config);
9432 * Creates a KeyMap for this element
9433 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9434 * @return {Roo.KeyMap} The KeyMap created
9436 addKeyMap : function(config){
9437 return new Roo.KeyMap(this, config);
9441 * Returns true if this element is scrollable.
9444 isScrollable : function(){
9446 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9450 * 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().
9451 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9452 * @param {Number} value The new scroll value
9453 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9454 * @return {Element} this
9457 scrollTo : function(side, value, animate){
9458 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9460 this.dom[prop] = value;
9462 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9463 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9469 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9470 * within this element's scrollable range.
9471 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9472 * @param {Number} distance How far to scroll the element in pixels
9473 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9474 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9475 * was scrolled as far as it could go.
9477 scroll : function(direction, distance, animate){
9478 if(!this.isScrollable()){
9482 var l = el.scrollLeft, t = el.scrollTop;
9483 var w = el.scrollWidth, h = el.scrollHeight;
9484 var cw = el.clientWidth, ch = el.clientHeight;
9485 direction = direction.toLowerCase();
9486 var scrolled = false;
9487 var a = this.preanim(arguments, 2);
9492 var v = Math.min(l + distance, w-cw);
9493 this.scrollTo("left", v, a);
9500 var v = Math.max(l - distance, 0);
9501 this.scrollTo("left", v, a);
9509 var v = Math.max(t - distance, 0);
9510 this.scrollTo("top", v, a);
9518 var v = Math.min(t + distance, h-ch);
9519 this.scrollTo("top", v, a);
9528 * Translates the passed page coordinates into left/top css values for this element
9529 * @param {Number/Array} x The page x or an array containing [x, y]
9530 * @param {Number} y The page y
9531 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9533 translatePoints : function(x, y){
9534 if(typeof x == 'object' || x instanceof Array){
9537 var p = this.getStyle('position');
9538 var o = this.getXY();
9540 var l = parseInt(this.getStyle('left'), 10);
9541 var t = parseInt(this.getStyle('top'), 10);
9544 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9547 t = (p == "relative") ? 0 : this.dom.offsetTop;
9550 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9554 * Returns the current scroll position of the element.
9555 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9557 getScroll : function(){
9558 var d = this.dom, doc = document;
9559 if(d == doc || d == doc.body){
9560 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9561 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9562 return {left: l, top: t};
9564 return {left: d.scrollLeft, top: d.scrollTop};
9569 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9570 * are convert to standard 6 digit hex color.
9571 * @param {String} attr The css attribute
9572 * @param {String} defaultValue The default value to use when a valid color isn't found
9573 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9576 getColor : function(attr, defaultValue, prefix){
9577 var v = this.getStyle(attr);
9578 if(!v || v == "transparent" || v == "inherit") {
9579 return defaultValue;
9581 var color = typeof prefix == "undefined" ? "#" : prefix;
9582 if(v.substr(0, 4) == "rgb("){
9583 var rvs = v.slice(4, v.length -1).split(",");
9584 for(var i = 0; i < 3; i++){
9585 var h = parseInt(rvs[i]).toString(16);
9592 if(v.substr(0, 1) == "#"){
9594 for(var i = 1; i < 4; i++){
9595 var c = v.charAt(i);
9598 }else if(v.length == 7){
9599 color += v.substr(1);
9603 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9607 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9608 * gradient background, rounded corners and a 4-way shadow.
9609 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9610 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9611 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9612 * @return {Roo.Element} this
9614 boxWrap : function(cls){
9615 cls = cls || 'x-box';
9616 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9617 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9622 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9623 * @param {String} namespace The namespace in which to look for the attribute
9624 * @param {String} name The attribute name
9625 * @return {String} The attribute value
9627 getAttributeNS : Roo.isIE ? function(ns, name){
9629 var type = typeof d[ns+":"+name];
9630 if(type != 'undefined' && type != 'unknown'){
9631 return d[ns+":"+name];
9634 } : function(ns, name){
9636 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9641 * Sets or Returns the value the dom attribute value
9642 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9643 * @param {String} value (optional) The value to set the attribute to
9644 * @return {String} The attribute value
9646 attr : function(name){
9647 if (arguments.length > 1) {
9648 this.dom.setAttribute(name, arguments[1]);
9649 return arguments[1];
9651 if (typeof(name) == 'object') {
9652 for(var i in name) {
9653 this.attr(i, name[i]);
9659 if (!this.dom.hasAttribute(name)) {
9662 return this.dom.getAttribute(name);
9669 var ep = El.prototype;
9672 * Appends an event handler (Shorthand for addListener)
9673 * @param {String} eventName The type of event to append
9674 * @param {Function} fn The method the event invokes
9675 * @param {Object} scope (optional) The scope (this object) of the fn
9676 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9679 ep.on = ep.addListener;
9681 ep.mon = ep.addListener;
9684 * Removes an event handler from this element (shorthand for removeListener)
9685 * @param {String} eventName the type of event to remove
9686 * @param {Function} fn the method the event invokes
9687 * @return {Roo.Element} this
9690 ep.un = ep.removeListener;
9693 * true to automatically adjust width and height settings for box-model issues (default to true)
9695 ep.autoBoxAdjust = true;
9698 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9701 El.addUnits = function(v, defaultUnit){
9702 if(v === "" || v == "auto"){
9705 if(v === undefined){
9708 if(typeof v == "number" || !El.unitPattern.test(v)){
9709 return v + (defaultUnit || 'px');
9714 // special markup used throughout Roo when box wrapping elements
9715 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>';
9717 * Visibility mode constant - Use visibility to hide element
9723 * Visibility mode constant - Use display to hide element
9729 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9730 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9731 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9743 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9744 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9745 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9746 * @return {Element} The Element object
9749 El.get = function(el){
9751 if(!el){ return null; }
9752 if(typeof el == "string"){ // element id
9753 if(!(elm = document.getElementById(el))){
9756 if(ex = El.cache[el]){
9759 ex = El.cache[el] = new El(elm);
9762 }else if(el.tagName){ // dom element
9766 if(ex = El.cache[id]){
9769 ex = El.cache[id] = new El(el);
9772 }else if(el instanceof El){
9774 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9775 // catch case where it hasn't been appended
9776 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9779 }else if(el.isComposite){
9781 }else if(el instanceof Array){
9782 return El.select(el);
9783 }else if(el == document){
9784 // create a bogus element object representing the document object
9786 var f = function(){};
9787 f.prototype = El.prototype;
9789 docEl.dom = document;
9797 El.uncache = function(el){
9798 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9800 delete El.cache[a[i].id || a[i]];
9806 // Garbage collection - uncache elements/purge listeners on orphaned elements
9807 // so we don't hold a reference and cause the browser to retain them
9808 El.garbageCollect = function(){
9809 if(!Roo.enableGarbageCollector){
9810 clearInterval(El.collectorThread);
9813 for(var eid in El.cache){
9814 var el = El.cache[eid], d = el.dom;
9815 // -------------------------------------------------------
9816 // Determining what is garbage:
9817 // -------------------------------------------------------
9819 // dom node is null, definitely garbage
9820 // -------------------------------------------------------
9822 // no parentNode == direct orphan, definitely garbage
9823 // -------------------------------------------------------
9824 // !d.offsetParent && !document.getElementById(eid)
9825 // display none elements have no offsetParent so we will
9826 // also try to look it up by it's id. However, check
9827 // offsetParent first so we don't do unneeded lookups.
9828 // This enables collection of elements that are not orphans
9829 // directly, but somewhere up the line they have an orphan
9831 // -------------------------------------------------------
9832 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9833 delete El.cache[eid];
9834 if(d && Roo.enableListenerCollection){
9840 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9844 El.Flyweight = function(dom){
9847 El.Flyweight.prototype = El.prototype;
9849 El._flyweights = {};
9851 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9852 * the dom node can be overwritten by other code.
9853 * @param {String/HTMLElement} el The dom node or id
9854 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9855 * prevent conflicts (e.g. internally Roo uses "_internal")
9857 * @return {Element} The shared Element object
9859 El.fly = function(el, named){
9860 named = named || '_global';
9861 el = Roo.getDom(el);
9865 if(!El._flyweights[named]){
9866 El._flyweights[named] = new El.Flyweight();
9868 El._flyweights[named].dom = el;
9869 return El._flyweights[named];
9873 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9874 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9875 * Shorthand of {@link Roo.Element#get}
9876 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9877 * @return {Element} The Element object
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 * Shorthand of {@link Roo.Element#fly}
9886 * @param {String/HTMLElement} el The dom node or id
9887 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9888 * prevent conflicts (e.g. internally Roo uses "_internal")
9890 * @return {Element} The shared Element object
9896 // speedy lookup for elements never to box adjust
9897 var noBoxAdjust = Roo.isStrict ? {
9900 input:1, select:1, textarea:1
9902 if(Roo.isIE || Roo.isGecko){
9903 noBoxAdjust['button'] = 1;
9907 Roo.EventManager.on(window, 'unload', function(){
9909 delete El._flyweights;
9917 Roo.Element.selectorFunction = Roo.DomQuery.select;
9920 Roo.Element.select = function(selector, unique, root){
9922 if(typeof selector == "string"){
9923 els = Roo.Element.selectorFunction(selector, root);
9924 }else if(selector.length !== undefined){
9927 throw "Invalid selector";
9929 if(unique === true){
9930 return new Roo.CompositeElement(els);
9932 return new Roo.CompositeElementLite(els);
9936 * Selects elements based on the passed CSS selector to enable working on them as 1.
9937 * @param {String/Array} selector The CSS selector or an array of elements
9938 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9939 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9940 * @return {CompositeElementLite/CompositeElement}
9944 Roo.select = Roo.Element.select;
9961 * Ext JS Library 1.1.1
9962 * Copyright(c) 2006-2007, Ext JS, LLC.
9964 * Originally Released Under LGPL - original licence link has changed is not relivant.
9967 * <script type="text/javascript">
9972 //Notifies Element that fx methods are available
9973 Roo.enableFx = true;
9977 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9978 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9979 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9980 * Element effects to work.</p><br/>
9982 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9983 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9984 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9985 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9986 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9987 * expected results and should be done with care.</p><br/>
9989 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9990 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9993 ----- -----------------------------
9994 tl The top left corner
9995 t The center of the top edge
9996 tr The top right corner
9997 l The center of the left edge
9998 r The center of the right edge
9999 bl The bottom left corner
10000 b The center of the bottom edge
10001 br The bottom right corner
10003 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10004 * below are common options that can be passed to any Fx method.</b>
10005 * @cfg {Function} callback A function called when the effect is finished
10006 * @cfg {Object} scope The scope of the effect function
10007 * @cfg {String} easing A valid Easing value for the effect
10008 * @cfg {String} afterCls A css class to apply after the effect
10009 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10010 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10011 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10012 * effects that end with the element being visually hidden, ignored otherwise)
10013 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10014 * a function which returns such a specification that will be applied to the Element after the effect finishes
10015 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10016 * @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
10017 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10021 * Slides the element into view. An anchor point can be optionally passed to set the point of
10022 * origin for the slide effect. This function automatically handles wrapping the element with
10023 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10026 // default: slide the element in from the top
10029 // custom: slide the element in from the right with a 2-second duration
10030 el.slideIn('r', { duration: 2 });
10032 // common config options shown with default values
10038 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10039 * @param {Object} options (optional) Object literal with any of the Fx config options
10040 * @return {Roo.Element} The Element
10042 slideIn : function(anchor, o){
10043 var el = this.getFxEl();
10046 el.queueFx(o, function(){
10048 anchor = anchor || "t";
10050 // fix display to visibility
10053 // restore values after effect
10054 var r = this.getFxRestore();
10055 var b = this.getBox();
10056 // fixed size for slide
10060 var wrap = this.fxWrap(r.pos, o, "hidden");
10062 var st = this.dom.style;
10063 st.visibility = "visible";
10064 st.position = "absolute";
10066 // clear out temp styles after slide and unwrap
10067 var after = function(){
10068 el.fxUnwrap(wrap, r.pos, o);
10069 st.width = r.width;
10070 st.height = r.height;
10073 // time to calc the positions
10074 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10076 switch(anchor.toLowerCase()){
10078 wrap.setSize(b.width, 0);
10079 st.left = st.bottom = "0";
10083 wrap.setSize(0, b.height);
10084 st.right = st.top = "0";
10088 wrap.setSize(0, b.height);
10089 wrap.setX(b.right);
10090 st.left = st.top = "0";
10091 a = {width: bw, points: pt};
10094 wrap.setSize(b.width, 0);
10095 wrap.setY(b.bottom);
10096 st.left = st.top = "0";
10097 a = {height: bh, points: pt};
10100 wrap.setSize(0, 0);
10101 st.right = st.bottom = "0";
10102 a = {width: bw, height: bh};
10105 wrap.setSize(0, 0);
10106 wrap.setY(b.y+b.height);
10107 st.right = st.top = "0";
10108 a = {width: bw, height: bh, points: pt};
10111 wrap.setSize(0, 0);
10112 wrap.setXY([b.right, b.bottom]);
10113 st.left = st.top = "0";
10114 a = {width: bw, height: bh, points: pt};
10117 wrap.setSize(0, 0);
10118 wrap.setX(b.x+b.width);
10119 st.left = st.bottom = "0";
10120 a = {width: bw, height: bh, points: pt};
10123 this.dom.style.visibility = "visible";
10126 arguments.callee.anim = wrap.fxanim(a,
10136 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10137 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10138 * 'hidden') but block elements will still take up space in the document. The element must be removed
10139 * from the DOM using the 'remove' config option if desired. This function automatically handles
10140 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10143 // default: slide the element out to the top
10146 // custom: slide the element out to the right with a 2-second duration
10147 el.slideOut('r', { duration: 2 });
10149 // common config options shown with default values
10157 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10158 * @param {Object} options (optional) Object literal with any of the Fx config options
10159 * @return {Roo.Element} The Element
10161 slideOut : function(anchor, o){
10162 var el = this.getFxEl();
10165 el.queueFx(o, function(){
10167 anchor = anchor || "t";
10169 // restore values after effect
10170 var r = this.getFxRestore();
10172 var b = this.getBox();
10173 // fixed size for slide
10177 var wrap = this.fxWrap(r.pos, o, "visible");
10179 var st = this.dom.style;
10180 st.visibility = "visible";
10181 st.position = "absolute";
10185 var after = function(){
10187 el.setDisplayed(false);
10192 el.fxUnwrap(wrap, r.pos, o);
10194 st.width = r.width;
10195 st.height = r.height;
10200 var a, zero = {to: 0};
10201 switch(anchor.toLowerCase()){
10203 st.left = st.bottom = "0";
10204 a = {height: zero};
10207 st.right = st.top = "0";
10211 st.left = st.top = "0";
10212 a = {width: zero, points: {to:[b.right, b.y]}};
10215 st.left = st.top = "0";
10216 a = {height: zero, points: {to:[b.x, b.bottom]}};
10219 st.right = st.bottom = "0";
10220 a = {width: zero, height: zero};
10223 st.right = st.top = "0";
10224 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10227 st.left = st.top = "0";
10228 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10231 st.left = st.bottom = "0";
10232 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10236 arguments.callee.anim = wrap.fxanim(a,
10246 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10247 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10248 * The element must be removed from the DOM using the 'remove' config option if desired.
10254 // common config options shown with default values
10262 * @param {Object} options (optional) Object literal with any of the Fx config options
10263 * @return {Roo.Element} The Element
10265 puff : function(o){
10266 var el = this.getFxEl();
10269 el.queueFx(o, function(){
10270 this.clearOpacity();
10273 // restore values after effect
10274 var r = this.getFxRestore();
10275 var st = this.dom.style;
10277 var after = function(){
10279 el.setDisplayed(false);
10286 el.setPositioning(r.pos);
10287 st.width = r.width;
10288 st.height = r.height;
10293 var width = this.getWidth();
10294 var height = this.getHeight();
10296 arguments.callee.anim = this.fxanim({
10297 width : {to: this.adjustWidth(width * 2)},
10298 height : {to: this.adjustHeight(height * 2)},
10299 points : {by: [-(width * .5), -(height * .5)]},
10301 fontSize: {to:200, unit: "%"}
10312 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10313 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10314 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10320 // all config options shown with default values
10328 * @param {Object} options (optional) Object literal with any of the Fx config options
10329 * @return {Roo.Element} The Element
10331 switchOff : function(o){
10332 var el = this.getFxEl();
10335 el.queueFx(o, function(){
10336 this.clearOpacity();
10339 // restore values after effect
10340 var r = this.getFxRestore();
10341 var st = this.dom.style;
10343 var after = function(){
10345 el.setDisplayed(false);
10351 el.setPositioning(r.pos);
10352 st.width = r.width;
10353 st.height = r.height;
10358 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10359 this.clearOpacity();
10363 points:{by:[0, this.getHeight() * .5]}
10364 }, o, 'motion', 0.3, 'easeIn', after);
10365 }).defer(100, this);
10372 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10373 * changed using the "attr" config option) and then fading back to the original color. If no original
10374 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10377 // default: highlight background to yellow
10380 // custom: highlight foreground text to blue for 2 seconds
10381 el.highlight("0000ff", { attr: 'color', duration: 2 });
10383 // common config options shown with default values
10384 el.highlight("ffff9c", {
10385 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10386 endColor: (current color) or "ffffff",
10391 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10392 * @param {Object} options (optional) Object literal with any of the Fx config options
10393 * @return {Roo.Element} The Element
10395 highlight : function(color, o){
10396 var el = this.getFxEl();
10399 el.queueFx(o, function(){
10400 color = color || "ffff9c";
10401 attr = o.attr || "backgroundColor";
10403 this.clearOpacity();
10406 var origColor = this.getColor(attr);
10407 var restoreColor = this.dom.style[attr];
10408 endColor = (o.endColor || origColor) || "ffffff";
10410 var after = function(){
10411 el.dom.style[attr] = restoreColor;
10416 a[attr] = {from: color, to: endColor};
10417 arguments.callee.anim = this.fxanim(a,
10427 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10430 // default: a single light blue ripple
10433 // custom: 3 red ripples lasting 3 seconds total
10434 el.frame("ff0000", 3, { duration: 3 });
10436 // common config options shown with default values
10437 el.frame("C3DAF9", 1, {
10438 duration: 1 //duration of entire animation (not each individual ripple)
10439 // Note: Easing is not configurable and will be ignored if included
10442 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10443 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10444 * @param {Object} options (optional) Object literal with any of the Fx config options
10445 * @return {Roo.Element} The Element
10447 frame : function(color, count, o){
10448 var el = this.getFxEl();
10451 el.queueFx(o, function(){
10452 color = color || "#C3DAF9";
10453 if(color.length == 6){
10454 color = "#" + color;
10456 count = count || 1;
10457 duration = o.duration || 1;
10460 var b = this.getBox();
10461 var animFn = function(){
10462 var proxy = this.createProxy({
10465 visbility:"hidden",
10466 position:"absolute",
10467 "z-index":"35000", // yee haw
10468 border:"0px solid " + color
10471 var scale = Roo.isBorderBox ? 2 : 1;
10473 top:{from:b.y, to:b.y - 20},
10474 left:{from:b.x, to:b.x - 20},
10475 borderWidth:{from:0, to:10},
10476 opacity:{from:1, to:0},
10477 height:{from:b.height, to:(b.height + (20*scale))},
10478 width:{from:b.width, to:(b.width + (20*scale))}
10479 }, duration, function(){
10483 animFn.defer((duration/2)*1000, this);
10494 * Creates a pause before any subsequent queued effects begin. If there are
10495 * no effects queued after the pause it will have no effect.
10500 * @param {Number} seconds The length of time to pause (in seconds)
10501 * @return {Roo.Element} The Element
10503 pause : function(seconds){
10504 var el = this.getFxEl();
10507 el.queueFx(o, function(){
10508 setTimeout(function(){
10510 }, seconds * 1000);
10516 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10517 * using the "endOpacity" config option.
10520 // default: fade in from opacity 0 to 100%
10523 // custom: fade in from opacity 0 to 75% over 2 seconds
10524 el.fadeIn({ endOpacity: .75, duration: 2});
10526 // common config options shown with default values
10528 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10533 * @param {Object} options (optional) Object literal with any of the Fx config options
10534 * @return {Roo.Element} The Element
10536 fadeIn : function(o){
10537 var el = this.getFxEl();
10539 el.queueFx(o, function(){
10540 this.setOpacity(0);
10542 this.dom.style.visibility = 'visible';
10543 var to = o.endOpacity || 1;
10544 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10545 o, null, .5, "easeOut", function(){
10547 this.clearOpacity();
10556 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10557 * using the "endOpacity" config option.
10560 // default: fade out from the element's current opacity to 0
10563 // custom: fade out from the element's current opacity to 25% over 2 seconds
10564 el.fadeOut({ endOpacity: .25, duration: 2});
10566 // common config options shown with default values
10568 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10575 * @param {Object} options (optional) Object literal with any of the Fx config options
10576 * @return {Roo.Element} The Element
10578 fadeOut : function(o){
10579 var el = this.getFxEl();
10581 el.queueFx(o, function(){
10582 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10583 o, null, .5, "easeOut", function(){
10584 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10585 this.dom.style.display = "none";
10587 this.dom.style.visibility = "hidden";
10589 this.clearOpacity();
10597 * Animates the transition of an element's dimensions from a starting height/width
10598 * to an ending height/width.
10601 // change height and width to 100x100 pixels
10602 el.scale(100, 100);
10604 // common config options shown with default values. The height and width will default to
10605 // the element's existing values if passed as null.
10608 [element's height], {
10613 * @param {Number} width The new width (pass undefined to keep the original width)
10614 * @param {Number} height The new height (pass undefined to keep the original height)
10615 * @param {Object} options (optional) Object literal with any of the Fx config options
10616 * @return {Roo.Element} The Element
10618 scale : function(w, h, o){
10619 this.shift(Roo.apply({}, o, {
10627 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10628 * Any of these properties not specified in the config object will not be changed. This effect
10629 * requires that at least one new dimension, position or opacity setting must be passed in on
10630 * the config object in order for the function to have any effect.
10633 // slide the element horizontally to x position 200 while changing the height and opacity
10634 el.shift({ x: 200, height: 50, opacity: .8 });
10636 // common config options shown with default values.
10638 width: [element's width],
10639 height: [element's height],
10640 x: [element's x position],
10641 y: [element's y position],
10642 opacity: [element's opacity],
10647 * @param {Object} options Object literal with any of the Fx config options
10648 * @return {Roo.Element} The Element
10650 shift : function(o){
10651 var el = this.getFxEl();
10653 el.queueFx(o, function(){
10654 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10655 if(w !== undefined){
10656 a.width = {to: this.adjustWidth(w)};
10658 if(h !== undefined){
10659 a.height = {to: this.adjustHeight(h)};
10661 if(x !== undefined || y !== undefined){
10663 x !== undefined ? x : this.getX(),
10664 y !== undefined ? y : this.getY()
10667 if(op !== undefined){
10668 a.opacity = {to: op};
10670 if(o.xy !== undefined){
10671 a.points = {to: o.xy};
10673 arguments.callee.anim = this.fxanim(a,
10674 o, 'motion', .35, "easeOut", function(){
10682 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10683 * ending point of the effect.
10686 // default: slide the element downward while fading out
10689 // custom: slide the element out to the right with a 2-second duration
10690 el.ghost('r', { duration: 2 });
10692 // common config options shown with default values
10700 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10701 * @param {Object} options (optional) Object literal with any of the Fx config options
10702 * @return {Roo.Element} The Element
10704 ghost : function(anchor, o){
10705 var el = this.getFxEl();
10708 el.queueFx(o, function(){
10709 anchor = anchor || "b";
10711 // restore values after effect
10712 var r = this.getFxRestore();
10713 var w = this.getWidth(),
10714 h = this.getHeight();
10716 var st = this.dom.style;
10718 var after = function(){
10720 el.setDisplayed(false);
10726 el.setPositioning(r.pos);
10727 st.width = r.width;
10728 st.height = r.height;
10733 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10734 switch(anchor.toLowerCase()){
10761 arguments.callee.anim = this.fxanim(a,
10771 * Ensures that all effects queued after syncFx is called on the element are
10772 * run concurrently. This is the opposite of {@link #sequenceFx}.
10773 * @return {Roo.Element} The Element
10775 syncFx : function(){
10776 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10785 * Ensures that all effects queued after sequenceFx is called on the element are
10786 * run in sequence. This is the opposite of {@link #syncFx}.
10787 * @return {Roo.Element} The Element
10789 sequenceFx : function(){
10790 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10792 concurrent : false,
10799 nextFx : function(){
10800 var ef = this.fxQueue[0];
10807 * Returns true if the element has any effects actively running or queued, else returns false.
10808 * @return {Boolean} True if element has active effects, else false
10810 hasActiveFx : function(){
10811 return this.fxQueue && this.fxQueue[0];
10815 * Stops any running effects and clears the element's internal effects queue if it contains
10816 * any additional effects that haven't started yet.
10817 * @return {Roo.Element} The Element
10819 stopFx : function(){
10820 if(this.hasActiveFx()){
10821 var cur = this.fxQueue[0];
10822 if(cur && cur.anim && cur.anim.isAnimated()){
10823 this.fxQueue = [cur]; // clear out others
10824 cur.anim.stop(true);
10831 beforeFx : function(o){
10832 if(this.hasActiveFx() && !o.concurrent){
10843 * Returns true if the element is currently blocking so that no other effect can be queued
10844 * until this effect is finished, else returns false if blocking is not set. This is commonly
10845 * used to ensure that an effect initiated by a user action runs to completion prior to the
10846 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10847 * @return {Boolean} True if blocking, else false
10849 hasFxBlock : function(){
10850 var q = this.fxQueue;
10851 return q && q[0] && q[0].block;
10855 queueFx : function(o, fn){
10859 if(!this.hasFxBlock()){
10860 Roo.applyIf(o, this.fxDefaults);
10862 var run = this.beforeFx(o);
10863 fn.block = o.block;
10864 this.fxQueue.push(fn);
10876 fxWrap : function(pos, o, vis){
10878 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10881 wrapXY = this.getXY();
10883 var div = document.createElement("div");
10884 div.style.visibility = vis;
10885 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10886 wrap.setPositioning(pos);
10887 if(wrap.getStyle("position") == "static"){
10888 wrap.position("relative");
10890 this.clearPositioning('auto');
10892 wrap.dom.appendChild(this.dom);
10894 wrap.setXY(wrapXY);
10901 fxUnwrap : function(wrap, pos, o){
10902 this.clearPositioning();
10903 this.setPositioning(pos);
10905 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10911 getFxRestore : function(){
10912 var st = this.dom.style;
10913 return {pos: this.getPositioning(), width: st.width, height : st.height};
10917 afterFx : function(o){
10919 this.applyStyles(o.afterStyle);
10922 this.addClass(o.afterCls);
10924 if(o.remove === true){
10927 Roo.callback(o.callback, o.scope, [this]);
10929 this.fxQueue.shift();
10935 getFxEl : function(){ // support for composite element fx
10936 return Roo.get(this.dom);
10940 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10941 animType = animType || 'run';
10943 var anim = Roo.lib.Anim[animType](
10945 (opt.duration || defaultDur) || .35,
10946 (opt.easing || defaultEase) || 'easeOut',
10948 Roo.callback(cb, this);
10957 // backwords compat
10958 Roo.Fx.resize = Roo.Fx.scale;
10960 //When included, Roo.Fx is automatically applied to Element so that all basic
10961 //effects are available directly via the Element API
10962 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10964 * Ext JS Library 1.1.1
10965 * Copyright(c) 2006-2007, Ext JS, LLC.
10967 * Originally Released Under LGPL - original licence link has changed is not relivant.
10970 * <script type="text/javascript">
10975 * @class Roo.CompositeElement
10976 * Standard composite class. Creates a Roo.Element for every element in the collection.
10978 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10979 * actions will be performed on all the elements in this collection.</b>
10981 * All methods return <i>this</i> and can be chained.
10983 var els = Roo.select("#some-el div.some-class", true);
10984 // or select directly from an existing element
10985 var el = Roo.get('some-el');
10986 el.select('div.some-class', true);
10988 els.setWidth(100); // all elements become 100 width
10989 els.hide(true); // all elements fade out and hide
10991 els.setWidth(100).hide(true);
10994 Roo.CompositeElement = function(els){
10995 this.elements = [];
10996 this.addElements(els);
10998 Roo.CompositeElement.prototype = {
11000 addElements : function(els){
11001 if(!els) return this;
11002 if(typeof els == "string"){
11003 els = Roo.Element.selectorFunction(els);
11005 var yels = this.elements;
11006 var index = yels.length-1;
11007 for(var i = 0, len = els.length; i < len; i++) {
11008 yels[++index] = Roo.get(els[i]);
11014 * Clears this composite and adds the elements returned by the passed selector.
11015 * @param {String/Array} els A string CSS selector, an array of elements or an element
11016 * @return {CompositeElement} this
11018 fill : function(els){
11019 this.elements = [];
11025 * Filters this composite to only elements that match the passed selector.
11026 * @param {String} selector A string CSS selector
11027 * @param {Boolean} inverse return inverse filter (not matches)
11028 * @return {CompositeElement} this
11030 filter : function(selector, inverse){
11032 inverse = inverse || false;
11033 this.each(function(el){
11034 var match = inverse ? !el.is(selector) : el.is(selector);
11036 els[els.length] = el.dom;
11043 invoke : function(fn, args){
11044 var els = this.elements;
11045 for(var i = 0, len = els.length; i < len; i++) {
11046 Roo.Element.prototype[fn].apply(els[i], args);
11051 * Adds elements to this composite.
11052 * @param {String/Array} els A string CSS selector, an array of elements or an element
11053 * @return {CompositeElement} this
11055 add : function(els){
11056 if(typeof els == "string"){
11057 this.addElements(Roo.Element.selectorFunction(els));
11058 }else if(els.length !== undefined){
11059 this.addElements(els);
11061 this.addElements([els]);
11066 * Calls the passed function passing (el, this, index) for each element in this composite.
11067 * @param {Function} fn The function to call
11068 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11069 * @return {CompositeElement} this
11071 each : function(fn, scope){
11072 var els = this.elements;
11073 for(var i = 0, len = els.length; i < len; i++){
11074 if(fn.call(scope || els[i], els[i], this, i) === false) {
11082 * Returns the Element object at the specified index
11083 * @param {Number} index
11084 * @return {Roo.Element}
11086 item : function(index){
11087 return this.elements[index] || null;
11091 * Returns the first Element
11092 * @return {Roo.Element}
11094 first : function(){
11095 return this.item(0);
11099 * Returns the last Element
11100 * @return {Roo.Element}
11103 return this.item(this.elements.length-1);
11107 * Returns the number of elements in this composite
11110 getCount : function(){
11111 return this.elements.length;
11115 * Returns true if this composite contains the passed element
11118 contains : function(el){
11119 return this.indexOf(el) !== -1;
11123 * Returns true if this composite contains the passed element
11126 indexOf : function(el){
11127 return this.elements.indexOf(Roo.get(el));
11132 * Removes the specified element(s).
11133 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11134 * or an array of any of those.
11135 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11136 * @return {CompositeElement} this
11138 removeElement : function(el, removeDom){
11139 if(el instanceof Array){
11140 for(var i = 0, len = el.length; i < len; i++){
11141 this.removeElement(el[i]);
11145 var index = typeof el == 'number' ? el : this.indexOf(el);
11148 var d = this.elements[index];
11152 d.parentNode.removeChild(d);
11155 this.elements.splice(index, 1);
11161 * Replaces the specified element with the passed element.
11162 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11164 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11165 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11166 * @return {CompositeElement} this
11168 replaceElement : function(el, replacement, domReplace){
11169 var index = typeof el == 'number' ? el : this.indexOf(el);
11172 this.elements[index].replaceWith(replacement);
11174 this.elements.splice(index, 1, Roo.get(replacement))
11181 * Removes all elements.
11183 clear : function(){
11184 this.elements = [];
11188 Roo.CompositeElement.createCall = function(proto, fnName){
11189 if(!proto[fnName]){
11190 proto[fnName] = function(){
11191 return this.invoke(fnName, arguments);
11195 for(var fnName in Roo.Element.prototype){
11196 if(typeof Roo.Element.prototype[fnName] == "function"){
11197 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11203 * Ext JS Library 1.1.1
11204 * Copyright(c) 2006-2007, Ext JS, LLC.
11206 * Originally Released Under LGPL - original licence link has changed is not relivant.
11209 * <script type="text/javascript">
11213 * @class Roo.CompositeElementLite
11214 * @extends Roo.CompositeElement
11215 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11217 var els = Roo.select("#some-el div.some-class");
11218 // or select directly from an existing element
11219 var el = Roo.get('some-el');
11220 el.select('div.some-class');
11222 els.setWidth(100); // all elements become 100 width
11223 els.hide(true); // all elements fade out and hide
11225 els.setWidth(100).hide(true);
11226 </code></pre><br><br>
11227 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11228 * actions will be performed on all the elements in this collection.</b>
11230 Roo.CompositeElementLite = function(els){
11231 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11232 this.el = new Roo.Element.Flyweight();
11234 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11235 addElements : function(els){
11237 if(els instanceof Array){
11238 this.elements = this.elements.concat(els);
11240 var yels = this.elements;
11241 var index = yels.length-1;
11242 for(var i = 0, len = els.length; i < len; i++) {
11243 yels[++index] = els[i];
11249 invoke : function(fn, args){
11250 var els = this.elements;
11252 for(var i = 0, len = els.length; i < len; i++) {
11254 Roo.Element.prototype[fn].apply(el, args);
11259 * Returns a flyweight Element of the dom element object at the specified index
11260 * @param {Number} index
11261 * @return {Roo.Element}
11263 item : function(index){
11264 if(!this.elements[index]){
11267 this.el.dom = this.elements[index];
11271 // fixes scope with flyweight
11272 addListener : function(eventName, handler, scope, opt){
11273 var els = this.elements;
11274 for(var i = 0, len = els.length; i < len; i++) {
11275 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11281 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11282 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11283 * a reference to the dom node, use el.dom.</b>
11284 * @param {Function} fn The function to call
11285 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11286 * @return {CompositeElement} this
11288 each : function(fn, scope){
11289 var els = this.elements;
11291 for(var i = 0, len = els.length; i < len; i++){
11293 if(fn.call(scope || el, el, this, i) === false){
11300 indexOf : function(el){
11301 return this.elements.indexOf(Roo.getDom(el));
11304 replaceElement : function(el, replacement, domReplace){
11305 var index = typeof el == 'number' ? el : this.indexOf(el);
11307 replacement = Roo.getDom(replacement);
11309 var d = this.elements[index];
11310 d.parentNode.insertBefore(replacement, d);
11311 d.parentNode.removeChild(d);
11313 this.elements.splice(index, 1, replacement);
11318 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11322 * Ext JS Library 1.1.1
11323 * Copyright(c) 2006-2007, Ext JS, LLC.
11325 * Originally Released Under LGPL - original licence link has changed is not relivant.
11328 * <script type="text/javascript">
11334 * @class Roo.data.Connection
11335 * @extends Roo.util.Observable
11336 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11337 * either to a configured URL, or to a URL specified at request time.<br><br>
11339 * Requests made by this class are asynchronous, and will return immediately. No data from
11340 * the server will be available to the statement immediately following the {@link #request} call.
11341 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11343 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11344 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11345 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11346 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11347 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11348 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11349 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11350 * standard DOM methods.
11352 * @param {Object} config a configuration object.
11354 Roo.data.Connection = function(config){
11355 Roo.apply(this, config);
11358 * @event beforerequest
11359 * Fires before a network request is made to retrieve a data object.
11360 * @param {Connection} conn This Connection object.
11361 * @param {Object} options The options config object passed to the {@link #request} method.
11363 "beforerequest" : true,
11365 * @event requestcomplete
11366 * Fires if the request was successfully completed.
11367 * @param {Connection} conn This Connection object.
11368 * @param {Object} response The XHR object containing the response data.
11369 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11370 * @param {Object} options The options config object passed to the {@link #request} method.
11372 "requestcomplete" : true,
11374 * @event requestexception
11375 * Fires if an error HTTP status was returned from the server.
11376 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11377 * @param {Connection} conn This Connection object.
11378 * @param {Object} response The XHR object containing the response data.
11379 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11380 * @param {Object} options The options config object passed to the {@link #request} method.
11382 "requestexception" : true
11384 Roo.data.Connection.superclass.constructor.call(this);
11387 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11389 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11392 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11393 * extra parameters to each request made by this object. (defaults to undefined)
11396 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11397 * to each request made by this object. (defaults to undefined)
11400 * @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)
11403 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11407 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11413 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11416 disableCaching: true,
11419 * Sends an HTTP request to a remote server.
11420 * @param {Object} options An object which may contain the following properties:<ul>
11421 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11422 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11423 * request, a url encoded string or a function to call to get either.</li>
11424 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11425 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11426 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11427 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11428 * <li>options {Object} The parameter to the request call.</li>
11429 * <li>success {Boolean} True if the request succeeded.</li>
11430 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11432 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11433 * The callback is passed the following parameters:<ul>
11434 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11435 * <li>options {Object} The parameter to the request call.</li>
11437 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11438 * The callback is passed the following parameters:<ul>
11439 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11440 * <li>options {Object} The parameter to the request call.</li>
11442 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11443 * for the callback function. Defaults to the browser window.</li>
11444 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11445 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11446 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11447 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11448 * params for the post data. Any params will be appended to the URL.</li>
11449 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11451 * @return {Number} transactionId
11453 request : function(o){
11454 if(this.fireEvent("beforerequest", this, o) !== false){
11457 if(typeof p == "function"){
11458 p = p.call(o.scope||window, o);
11460 if(typeof p == "object"){
11461 p = Roo.urlEncode(o.params);
11463 if(this.extraParams){
11464 var extras = Roo.urlEncode(this.extraParams);
11465 p = p ? (p + '&' + extras) : extras;
11468 var url = o.url || this.url;
11469 if(typeof url == 'function'){
11470 url = url.call(o.scope||window, o);
11474 var form = Roo.getDom(o.form);
11475 url = url || form.action;
11477 var enctype = form.getAttribute("enctype");
11478 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11479 return this.doFormUpload(o, p, url);
11481 var f = Roo.lib.Ajax.serializeForm(form);
11482 p = p ? (p + '&' + f) : f;
11485 var hs = o.headers;
11486 if(this.defaultHeaders){
11487 hs = Roo.apply(hs || {}, this.defaultHeaders);
11494 success: this.handleResponse,
11495 failure: this.handleFailure,
11497 argument: {options: o},
11498 timeout : o.timeout || this.timeout
11501 var method = o.method||this.method||(p ? "POST" : "GET");
11503 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11504 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11507 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11511 }else if(this.autoAbort !== false){
11515 if((method == 'GET' && p) || o.xmlData){
11516 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11519 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11520 return this.transId;
11522 Roo.callback(o.callback, o.scope, [o, null, null]);
11528 * Determine whether this object has a request outstanding.
11529 * @param {Number} transactionId (Optional) defaults to the last transaction
11530 * @return {Boolean} True if there is an outstanding request.
11532 isLoading : function(transId){
11534 return Roo.lib.Ajax.isCallInProgress(transId);
11536 return this.transId ? true : false;
11541 * Aborts any outstanding request.
11542 * @param {Number} transactionId (Optional) defaults to the last transaction
11544 abort : function(transId){
11545 if(transId || this.isLoading()){
11546 Roo.lib.Ajax.abort(transId || this.transId);
11551 handleResponse : function(response){
11552 this.transId = false;
11553 var options = response.argument.options;
11554 response.argument = options ? options.argument : null;
11555 this.fireEvent("requestcomplete", this, response, options);
11556 Roo.callback(options.success, options.scope, [response, options]);
11557 Roo.callback(options.callback, options.scope, [options, true, response]);
11561 handleFailure : function(response, e){
11562 this.transId = false;
11563 var options = response.argument.options;
11564 response.argument = options ? options.argument : null;
11565 this.fireEvent("requestexception", this, response, options, e);
11566 Roo.callback(options.failure, options.scope, [response, options]);
11567 Roo.callback(options.callback, options.scope, [options, false, response]);
11571 doFormUpload : function(o, ps, url){
11573 var frame = document.createElement('iframe');
11576 frame.className = 'x-hidden';
11578 frame.src = Roo.SSL_SECURE_URL;
11580 document.body.appendChild(frame);
11583 document.frames[id].name = id;
11586 var form = Roo.getDom(o.form);
11588 form.method = 'POST';
11589 form.enctype = form.encoding = 'multipart/form-data';
11595 if(ps){ // add dynamic params
11597 ps = Roo.urlDecode(ps, false);
11599 if(ps.hasOwnProperty(k)){
11600 hd = document.createElement('input');
11601 hd.type = 'hidden';
11604 form.appendChild(hd);
11611 var r = { // bogus response object
11616 r.argument = o ? o.argument : null;
11621 doc = frame.contentWindow.document;
11623 doc = (frame.contentDocument || window.frames[id].document);
11625 if(doc && doc.body){
11626 r.responseText = doc.body.innerHTML;
11628 if(doc && doc.XMLDocument){
11629 r.responseXML = doc.XMLDocument;
11631 r.responseXML = doc;
11638 Roo.EventManager.removeListener(frame, 'load', cb, this);
11640 this.fireEvent("requestcomplete", this, r, o);
11641 Roo.callback(o.success, o.scope, [r, o]);
11642 Roo.callback(o.callback, o.scope, [o, true, r]);
11644 setTimeout(function(){document.body.removeChild(frame);}, 100);
11647 Roo.EventManager.on(frame, 'load', cb, this);
11650 if(hiddens){ // remove dynamic params
11651 for(var i = 0, len = hiddens.length; i < len; i++){
11652 form.removeChild(hiddens[i]);
11659 * Ext JS Library 1.1.1
11660 * Copyright(c) 2006-2007, Ext JS, LLC.
11662 * Originally Released Under LGPL - original licence link has changed is not relivant.
11665 * <script type="text/javascript">
11669 * Global Ajax request class.
11672 * @extends Roo.data.Connection
11675 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11676 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11677 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11678 * @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)
11679 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11680 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11681 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11683 Roo.Ajax = new Roo.data.Connection({
11692 * Serialize the passed form into a url encoded string
11694 * @param {String/HTMLElement} form
11697 serializeForm : function(form){
11698 return Roo.lib.Ajax.serializeForm(form);
11702 * Ext JS Library 1.1.1
11703 * Copyright(c) 2006-2007, Ext JS, LLC.
11705 * Originally Released Under LGPL - original licence link has changed is not relivant.
11708 * <script type="text/javascript">
11713 * @class Roo.UpdateManager
11714 * @extends Roo.util.Observable
11715 * Provides AJAX-style update for Element object.<br><br>
11718 * // Get it from a Roo.Element object
11719 * var el = Roo.get("foo");
11720 * var mgr = el.getUpdateManager();
11721 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11723 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11725 * // or directly (returns the same UpdateManager instance)
11726 * var mgr = new Roo.UpdateManager("myElementId");
11727 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11728 * mgr.on("update", myFcnNeedsToKnow);
11730 // short handed call directly from the element object
11731 Roo.get("foo").load({
11735 text: "Loading Foo..."
11739 * Create new UpdateManager directly.
11740 * @param {String/HTMLElement/Roo.Element} el The element to update
11741 * @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).
11743 Roo.UpdateManager = function(el, forceNew){
11745 if(!forceNew && el.updateManager){
11746 return el.updateManager;
11749 * The Element object
11750 * @type Roo.Element
11754 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11757 this.defaultUrl = null;
11761 * @event beforeupdate
11762 * Fired before an update is made, return false from your handler and the update is cancelled.
11763 * @param {Roo.Element} el
11764 * @param {String/Object/Function} url
11765 * @param {String/Object} params
11767 "beforeupdate": true,
11770 * Fired after successful update is made.
11771 * @param {Roo.Element} el
11772 * @param {Object} oResponseObject The response Object
11777 * Fired on update failure.
11778 * @param {Roo.Element} el
11779 * @param {Object} oResponseObject The response Object
11783 var d = Roo.UpdateManager.defaults;
11785 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11788 this.sslBlankUrl = d.sslBlankUrl;
11790 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11793 this.disableCaching = d.disableCaching;
11795 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11798 this.indicatorText = d.indicatorText;
11800 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11803 this.showLoadIndicator = d.showLoadIndicator;
11805 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11808 this.timeout = d.timeout;
11811 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11814 this.loadScripts = d.loadScripts;
11817 * Transaction object of current executing transaction
11819 this.transaction = null;
11824 this.autoRefreshProcId = null;
11826 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11829 this.refreshDelegate = this.refresh.createDelegate(this);
11831 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11834 this.updateDelegate = this.update.createDelegate(this);
11836 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11839 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11843 this.successDelegate = this.processSuccess.createDelegate(this);
11847 this.failureDelegate = this.processFailure.createDelegate(this);
11849 if(!this.renderer){
11851 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11853 this.renderer = new Roo.UpdateManager.BasicRenderer();
11856 Roo.UpdateManager.superclass.constructor.call(this);
11859 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11861 * Get the Element this UpdateManager is bound to
11862 * @return {Roo.Element} The element
11864 getEl : function(){
11868 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11869 * @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:
11872 url: "your-url.php",<br/>
11873 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11874 callback: yourFunction,<br/>
11875 scope: yourObject, //(optional scope) <br/>
11876 discardUrl: false, <br/>
11877 nocache: false,<br/>
11878 text: "Loading...",<br/>
11880 scripts: false<br/>
11883 * The only required property is url. The optional properties nocache, text and scripts
11884 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11885 * @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}
11886 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11887 * @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.
11889 update : function(url, params, callback, discardUrl){
11890 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11891 var method = this.method,
11893 if(typeof url == "object"){ // must be config object
11896 params = params || cfg.params;
11897 callback = callback || cfg.callback;
11898 discardUrl = discardUrl || cfg.discardUrl;
11899 if(callback && cfg.scope){
11900 callback = callback.createDelegate(cfg.scope);
11902 if(typeof cfg.method != "undefined"){method = cfg.method;};
11903 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11904 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11905 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11906 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11908 this.showLoading();
11910 this.defaultUrl = url;
11912 if(typeof url == "function"){
11913 url = url.call(this);
11916 method = method || (params ? "POST" : "GET");
11917 if(method == "GET"){
11918 url = this.prepareUrl(url);
11921 var o = Roo.apply(cfg ||{}, {
11924 success: this.successDelegate,
11925 failure: this.failureDelegate,
11926 callback: undefined,
11927 timeout: (this.timeout*1000),
11928 argument: {"url": url, "form": null, "callback": callback, "params": params}
11930 Roo.log("updated manager called with timeout of " + o.timeout);
11931 this.transaction = Roo.Ajax.request(o);
11936 * 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.
11937 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11938 * @param {String/HTMLElement} form The form Id or form element
11939 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11940 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11941 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11943 formUpdate : function(form, url, reset, callback){
11944 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11945 if(typeof url == "function"){
11946 url = url.call(this);
11948 form = Roo.getDom(form);
11949 this.transaction = Roo.Ajax.request({
11952 success: this.successDelegate,
11953 failure: this.failureDelegate,
11954 timeout: (this.timeout*1000),
11955 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11957 this.showLoading.defer(1, this);
11962 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11963 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11965 refresh : function(callback){
11966 if(this.defaultUrl == null){
11969 this.update(this.defaultUrl, null, callback, true);
11973 * Set this element to auto refresh.
11974 * @param {Number} interval How often to update (in seconds).
11975 * @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)
11976 * @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}
11977 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11978 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11980 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11982 this.update(url || this.defaultUrl, params, callback, true);
11984 if(this.autoRefreshProcId){
11985 clearInterval(this.autoRefreshProcId);
11987 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11991 * Stop auto refresh on this element.
11993 stopAutoRefresh : function(){
11994 if(this.autoRefreshProcId){
11995 clearInterval(this.autoRefreshProcId);
11996 delete this.autoRefreshProcId;
12000 isAutoRefreshing : function(){
12001 return this.autoRefreshProcId ? true : false;
12004 * Called to update the element to "Loading" state. Override to perform custom action.
12006 showLoading : function(){
12007 if(this.showLoadIndicator){
12008 this.el.update(this.indicatorText);
12013 * Adds unique parameter to query string if disableCaching = true
12016 prepareUrl : function(url){
12017 if(this.disableCaching){
12018 var append = "_dc=" + (new Date().getTime());
12019 if(url.indexOf("?") !== -1){
12020 url += "&" + append;
12022 url += "?" + append;
12031 processSuccess : function(response){
12032 this.transaction = null;
12033 if(response.argument.form && response.argument.reset){
12034 try{ // put in try/catch since some older FF releases had problems with this
12035 response.argument.form.reset();
12038 if(this.loadScripts){
12039 this.renderer.render(this.el, response, this,
12040 this.updateComplete.createDelegate(this, [response]));
12042 this.renderer.render(this.el, response, this);
12043 this.updateComplete(response);
12047 updateComplete : function(response){
12048 this.fireEvent("update", this.el, response);
12049 if(typeof response.argument.callback == "function"){
12050 response.argument.callback(this.el, true, response);
12057 processFailure : function(response){
12058 this.transaction = null;
12059 this.fireEvent("failure", this.el, response);
12060 if(typeof response.argument.callback == "function"){
12061 response.argument.callback(this.el, false, response);
12066 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12067 * @param {Object} renderer The object implementing the render() method
12069 setRenderer : function(renderer){
12070 this.renderer = renderer;
12073 getRenderer : function(){
12074 return this.renderer;
12078 * Set the defaultUrl used for updates
12079 * @param {String/Function} defaultUrl The url or a function to call to get the url
12081 setDefaultUrl : function(defaultUrl){
12082 this.defaultUrl = defaultUrl;
12086 * Aborts the executing transaction
12088 abort : function(){
12089 if(this.transaction){
12090 Roo.Ajax.abort(this.transaction);
12095 * Returns true if an update is in progress
12096 * @return {Boolean}
12098 isUpdating : function(){
12099 if(this.transaction){
12100 return Roo.Ajax.isLoading(this.transaction);
12107 * @class Roo.UpdateManager.defaults
12108 * @static (not really - but it helps the doc tool)
12109 * The defaults collection enables customizing the default properties of UpdateManager
12111 Roo.UpdateManager.defaults = {
12113 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12119 * True to process scripts by default (Defaults to false).
12122 loadScripts : false,
12125 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12128 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12130 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12133 disableCaching : false,
12135 * Whether to show indicatorText when loading (Defaults to true).
12138 showLoadIndicator : true,
12140 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12143 indicatorText : '<div class="loading-indicator">Loading...</div>'
12147 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12149 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12150 * @param {String/HTMLElement/Roo.Element} el The element to update
12151 * @param {String} url The url
12152 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12153 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12156 * @member Roo.UpdateManager
12158 Roo.UpdateManager.updateElement = function(el, url, params, options){
12159 var um = Roo.get(el, true).getUpdateManager();
12160 Roo.apply(um, options);
12161 um.update(url, params, options ? options.callback : null);
12163 // alias for backwards compat
12164 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12166 * @class Roo.UpdateManager.BasicRenderer
12167 * Default Content renderer. Updates the elements innerHTML with the responseText.
12169 Roo.UpdateManager.BasicRenderer = function(){};
12171 Roo.UpdateManager.BasicRenderer.prototype = {
12173 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12174 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12175 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12176 * @param {Roo.Element} el The element being rendered
12177 * @param {Object} response The YUI Connect response object
12178 * @param {UpdateManager} updateManager The calling update manager
12179 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12181 render : function(el, response, updateManager, callback){
12182 el.update(response.responseText, updateManager.loadScripts, callback);
12188 * (c)) Alan Knowles
12194 * @class Roo.DomTemplate
12195 * @extends Roo.Template
12196 * An effort at a dom based template engine..
12198 * Similar to XTemplate, except it uses dom parsing to create the template..
12200 * Supported features:
12205 {a_variable} - output encoded.
12206 {a_variable.format:("Y-m-d")} - call a method on the variable
12207 {a_variable:raw} - unencoded output
12208 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12209 {a_variable:this.method_on_template(...)} - call a method on the template object.
12214 <div roo-for="a_variable or condition.."></div>
12215 <div roo-if="a_variable or condition"></div>
12216 <div roo-exec="some javascript"></div>
12217 <div roo-name="named_template"></div>
12222 Roo.DomTemplate = function()
12224 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12231 Roo.extend(Roo.DomTemplate, Roo.Template, {
12233 * id counter for sub templates.
12237 * flag to indicate if dom parser is inside a pre,
12238 * it will strip whitespace if not.
12243 * The various sub templates
12251 * basic tag replacing syntax
12254 * // you can fake an object call by doing this
12258 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12259 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12261 iterChild : function (node, method) {
12263 var oldPre = this.inPre;
12264 if (node.tagName == 'PRE') {
12267 for( var i = 0; i < node.childNodes.length; i++) {
12268 method.call(this, node.childNodes[i]);
12270 this.inPre = oldPre;
12276 * compile the template
12278 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12281 compile: function()
12285 // covert the html into DOM...
12289 doc = document.implementation.createHTMLDocument("");
12290 doc.documentElement.innerHTML = this.html ;
12291 div = doc.documentElement;
12293 // old IE... - nasty -- it causes all sorts of issues.. with
12294 // images getting pulled from server..
12295 div = document.createElement('div');
12296 div.innerHTML = this.html;
12298 //doc.documentElement.innerHTML = htmlBody
12304 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12306 var tpls = this.tpls;
12308 // create a top level template from the snippet..
12310 //Roo.log(div.innerHTML);
12317 body : div.innerHTML,
12330 Roo.each(tpls, function(tp){
12331 this.compileTpl(tp);
12332 this.tpls[tp.id] = tp;
12335 this.master = tpls[0];
12341 compileNode : function(node, istop) {
12346 // skip anything not a tag..
12347 if (node.nodeType != 1) {
12348 if (node.nodeType == 3 && !this.inPre) {
12349 // reduce white space..
12350 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12373 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12374 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12375 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12376 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12382 // just itterate children..
12383 this.iterChild(node,this.compileNode);
12386 tpl.uid = this.id++;
12387 tpl.value = node.getAttribute('roo-' + tpl.attr);
12388 node.removeAttribute('roo-'+ tpl.attr);
12389 if (tpl.attr != 'name') {
12390 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12391 node.parentNode.replaceChild(placeholder, node);
12394 var placeholder = document.createElement('span');
12395 placeholder.className = 'roo-tpl-' + tpl.value;
12396 node.parentNode.replaceChild(placeholder, node);
12399 // parent now sees '{domtplXXXX}
12400 this.iterChild(node,this.compileNode);
12402 // we should now have node body...
12403 var div = document.createElement('div');
12404 div.appendChild(node);
12406 // this has the unfortunate side effect of converting tagged attributes
12407 // eg. href="{...}" into %7C...%7D
12408 // this has been fixed by searching for those combo's although it's a bit hacky..
12411 tpl.body = div.innerHTML;
12418 switch (tpl.value) {
12419 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12420 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12421 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12426 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12430 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12434 tpl.id = tpl.value; // replace non characters???
12440 this.tpls.push(tpl);
12450 * Compile a segment of the template into a 'sub-template'
12456 compileTpl : function(tpl)
12458 var fm = Roo.util.Format;
12459 var useF = this.disableFormats !== true;
12461 var sep = Roo.isGecko ? "+\n" : ",\n";
12463 var undef = function(str) {
12464 Roo.debug && Roo.log("Property not found :" + str);
12468 //Roo.log(tpl.body);
12472 var fn = function(m, lbrace, name, format, args)
12475 //Roo.log(arguments);
12476 args = args ? args.replace(/\\'/g,"'") : args;
12477 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12478 if (typeof(format) == 'undefined') {
12479 format = 'htmlEncode';
12481 if (format == 'raw' ) {
12485 if(name.substr(0, 6) == 'domtpl'){
12486 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12489 // build an array of options to determine if value is undefined..
12491 // basically get 'xxxx.yyyy' then do
12492 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12493 // (function () { Roo.log("Property not found"); return ''; })() :
12498 Roo.each(name.split('.'), function(st) {
12499 lookfor += (lookfor.length ? '.': '') + st;
12500 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12503 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12506 if(format && useF){
12508 args = args ? ',' + args : "";
12510 if(format.substr(0, 5) != "this."){
12511 format = "fm." + format + '(';
12513 format = 'this.call("'+ format.substr(5) + '", ';
12517 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12520 if (args && args.length) {
12521 // called with xxyx.yuu:(test,test)
12523 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12525 // raw.. - :raw modifier..
12526 return "'"+ sep + udef_st + name + ")"+sep+"'";
12530 // branched to use + in gecko and [].join() in others
12532 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12533 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12536 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12537 body.push(tpl.body.replace(/(\r\n|\n)/g,
12538 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12539 body.push("'].join('');};};");
12540 body = body.join('');
12543 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12545 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12552 * same as applyTemplate, except it's done to one of the subTemplates
12553 * when using named templates, you can do:
12555 * var str = pl.applySubTemplate('your-name', values);
12558 * @param {Number} id of the template
12559 * @param {Object} values to apply to template
12560 * @param {Object} parent (normaly the instance of this object)
12562 applySubTemplate : function(id, values, parent)
12566 var t = this.tpls[id];
12570 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12571 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12575 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12582 if(t.execCall && t.execCall.call(this, values, parent)){
12586 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12592 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12593 parent = t.target ? values : parent;
12594 if(t.forCall && vs instanceof Array){
12596 for(var i = 0, len = vs.length; i < len; i++){
12598 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12600 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12602 //Roo.log(t.compiled);
12606 return buf.join('');
12609 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12614 return t.compiled.call(this, vs, parent);
12616 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12618 //Roo.log(t.compiled);
12626 applyTemplate : function(values){
12627 return this.master.compiled.call(this, values, {});
12628 //var s = this.subs;
12631 apply : function(){
12632 return this.applyTemplate.apply(this, arguments);
12637 Roo.DomTemplate.from = function(el){
12638 el = Roo.getDom(el);
12639 return new Roo.Domtemplate(el.value || el.innerHTML);
12642 * Ext JS Library 1.1.1
12643 * Copyright(c) 2006-2007, Ext JS, LLC.
12645 * Originally Released Under LGPL - original licence link has changed is not relivant.
12648 * <script type="text/javascript">
12652 * @class Roo.util.DelayedTask
12653 * Provides a convenient method of performing setTimeout where a new
12654 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12655 * You can use this class to buffer
12656 * the keypress events for a certain number of milliseconds, and perform only if they stop
12657 * for that amount of time.
12658 * @constructor The parameters to this constructor serve as defaults and are not required.
12659 * @param {Function} fn (optional) The default function to timeout
12660 * @param {Object} scope (optional) The default scope of that timeout
12661 * @param {Array} args (optional) The default Array of arguments
12663 Roo.util.DelayedTask = function(fn, scope, args){
12664 var id = null, d, t;
12666 var call = function(){
12667 var now = new Date().getTime();
12671 fn.apply(scope, args || []);
12675 * Cancels any pending timeout and queues a new one
12676 * @param {Number} delay The milliseconds to delay
12677 * @param {Function} newFn (optional) Overrides function passed to constructor
12678 * @param {Object} newScope (optional) Overrides scope passed to constructor
12679 * @param {Array} newArgs (optional) Overrides args passed to constructor
12681 this.delay = function(delay, newFn, newScope, newArgs){
12682 if(id && delay != d){
12686 t = new Date().getTime();
12688 scope = newScope || scope;
12689 args = newArgs || args;
12691 id = setInterval(call, d);
12696 * Cancel the last queued timeout
12698 this.cancel = function(){
12706 * Ext JS Library 1.1.1
12707 * Copyright(c) 2006-2007, Ext JS, LLC.
12709 * Originally Released Under LGPL - original licence link has changed is not relivant.
12712 * <script type="text/javascript">
12716 Roo.util.TaskRunner = function(interval){
12717 interval = interval || 10;
12718 var tasks = [], removeQueue = [];
12720 var running = false;
12722 var stopThread = function(){
12728 var startThread = function(){
12731 id = setInterval(runTasks, interval);
12735 var removeTask = function(task){
12736 removeQueue.push(task);
12742 var runTasks = function(){
12743 if(removeQueue.length > 0){
12744 for(var i = 0, len = removeQueue.length; i < len; i++){
12745 tasks.remove(removeQueue[i]);
12748 if(tasks.length < 1){
12753 var now = new Date().getTime();
12754 for(var i = 0, len = tasks.length; i < len; ++i){
12756 var itime = now - t.taskRunTime;
12757 if(t.interval <= itime){
12758 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12759 t.taskRunTime = now;
12760 if(rt === false || t.taskRunCount === t.repeat){
12765 if(t.duration && t.duration <= (now - t.taskStartTime)){
12772 * Queues a new task.
12773 * @param {Object} task
12775 this.start = function(task){
12777 task.taskStartTime = new Date().getTime();
12778 task.taskRunTime = 0;
12779 task.taskRunCount = 0;
12784 this.stop = function(task){
12789 this.stopAll = function(){
12791 for(var i = 0, len = tasks.length; i < len; i++){
12792 if(tasks[i].onStop){
12801 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12803 * Ext JS Library 1.1.1
12804 * Copyright(c) 2006-2007, Ext JS, LLC.
12806 * Originally Released Under LGPL - original licence link has changed is not relivant.
12809 * <script type="text/javascript">
12814 * @class Roo.util.MixedCollection
12815 * @extends Roo.util.Observable
12816 * A Collection class that maintains both numeric indexes and keys and exposes events.
12818 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12819 * collection (defaults to false)
12820 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12821 * and return the key value for that item. This is used when available to look up the key on items that
12822 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12823 * equivalent to providing an implementation for the {@link #getKey} method.
12825 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12833 * Fires when the collection is cleared.
12838 * Fires when an item is added to the collection.
12839 * @param {Number} index The index at which the item was added.
12840 * @param {Object} o The item added.
12841 * @param {String} key The key associated with the added item.
12846 * Fires when an item is replaced in the collection.
12847 * @param {String} key he key associated with the new added.
12848 * @param {Object} old The item being replaced.
12849 * @param {Object} new The new item.
12854 * Fires when an item is removed from the collection.
12855 * @param {Object} o The item being removed.
12856 * @param {String} key (optional) The key associated with the removed item.
12861 this.allowFunctions = allowFunctions === true;
12863 this.getKey = keyFn;
12865 Roo.util.MixedCollection.superclass.constructor.call(this);
12868 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12869 allowFunctions : false,
12872 * Adds an item to the collection.
12873 * @param {String} key The key to associate with the item
12874 * @param {Object} o The item to add.
12875 * @return {Object} The item added.
12877 add : function(key, o){
12878 if(arguments.length == 1){
12880 key = this.getKey(o);
12882 if(typeof key == "undefined" || key === null){
12884 this.items.push(o);
12885 this.keys.push(null);
12887 var old = this.map[key];
12889 return this.replace(key, o);
12892 this.items.push(o);
12894 this.keys.push(key);
12896 this.fireEvent("add", this.length-1, o, key);
12901 * MixedCollection has a generic way to fetch keys if you implement getKey.
12904 var mc = new Roo.util.MixedCollection();
12905 mc.add(someEl.dom.id, someEl);
12906 mc.add(otherEl.dom.id, otherEl);
12910 var mc = new Roo.util.MixedCollection();
12911 mc.getKey = function(el){
12917 // or via the constructor
12918 var mc = new Roo.util.MixedCollection(false, function(el){
12924 * @param o {Object} The item for which to find the key.
12925 * @return {Object} The key for the passed item.
12927 getKey : function(o){
12932 * Replaces an item in the collection.
12933 * @param {String} key The key associated with the item to replace, or the item to replace.
12934 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12935 * @return {Object} The new item.
12937 replace : function(key, o){
12938 if(arguments.length == 1){
12940 key = this.getKey(o);
12942 var old = this.item(key);
12943 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12944 return this.add(key, o);
12946 var index = this.indexOfKey(key);
12947 this.items[index] = o;
12949 this.fireEvent("replace", key, old, o);
12954 * Adds all elements of an Array or an Object to the collection.
12955 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12956 * an Array of values, each of which are added to the collection.
12958 addAll : function(objs){
12959 if(arguments.length > 1 || objs instanceof Array){
12960 var args = arguments.length > 1 ? arguments : objs;
12961 for(var i = 0, len = args.length; i < len; i++){
12965 for(var key in objs){
12966 if(this.allowFunctions || typeof objs[key] != "function"){
12967 this.add(key, objs[key]);
12974 * Executes the specified function once for every item in the collection, passing each
12975 * item as the first and only parameter. returning false from the function will stop the iteration.
12976 * @param {Function} fn The function to execute for each item.
12977 * @param {Object} scope (optional) The scope in which to execute the function.
12979 each : function(fn, scope){
12980 var items = [].concat(this.items); // each safe for removal
12981 for(var i = 0, len = items.length; i < len; i++){
12982 if(fn.call(scope || items[i], items[i], i, len) === false){
12989 * Executes the specified function once for every key in the collection, passing each
12990 * key, and its associated item as the first two parameters.
12991 * @param {Function} fn The function to execute for each item.
12992 * @param {Object} scope (optional) The scope in which to execute the function.
12994 eachKey : function(fn, scope){
12995 for(var i = 0, len = this.keys.length; i < len; i++){
12996 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13001 * Returns the first item in the collection which elicits a true return value from the
13002 * passed selection function.
13003 * @param {Function} fn The selection function to execute for each item.
13004 * @param {Object} scope (optional) The scope in which to execute the function.
13005 * @return {Object} The first item in the collection which returned true from the selection function.
13007 find : function(fn, scope){
13008 for(var i = 0, len = this.items.length; i < len; i++){
13009 if(fn.call(scope || window, this.items[i], this.keys[i])){
13010 return this.items[i];
13017 * Inserts an item at the specified index in the collection.
13018 * @param {Number} index The index to insert the item at.
13019 * @param {String} key The key to associate with the new item, or the item itself.
13020 * @param {Object} o (optional) If the second parameter was a key, the new item.
13021 * @return {Object} The item inserted.
13023 insert : function(index, key, o){
13024 if(arguments.length == 2){
13026 key = this.getKey(o);
13028 if(index >= this.length){
13029 return this.add(key, o);
13032 this.items.splice(index, 0, o);
13033 if(typeof key != "undefined" && key != null){
13036 this.keys.splice(index, 0, key);
13037 this.fireEvent("add", index, o, key);
13042 * Removed an item from the collection.
13043 * @param {Object} o The item to remove.
13044 * @return {Object} The item removed.
13046 remove : function(o){
13047 return this.removeAt(this.indexOf(o));
13051 * Remove an item from a specified index in the collection.
13052 * @param {Number} index The index within the collection of the item to remove.
13054 removeAt : function(index){
13055 if(index < this.length && index >= 0){
13057 var o = this.items[index];
13058 this.items.splice(index, 1);
13059 var key = this.keys[index];
13060 if(typeof key != "undefined"){
13061 delete this.map[key];
13063 this.keys.splice(index, 1);
13064 this.fireEvent("remove", o, key);
13069 * Removed an item associated with the passed key fom the collection.
13070 * @param {String} key The key of the item to remove.
13072 removeKey : function(key){
13073 return this.removeAt(this.indexOfKey(key));
13077 * Returns the number of items in the collection.
13078 * @return {Number} the number of items in the collection.
13080 getCount : function(){
13081 return this.length;
13085 * Returns index within the collection of the passed Object.
13086 * @param {Object} o The item to find the index of.
13087 * @return {Number} index of the item.
13089 indexOf : function(o){
13090 if(!this.items.indexOf){
13091 for(var i = 0, len = this.items.length; i < len; i++){
13092 if(this.items[i] == o) return i;
13096 return this.items.indexOf(o);
13101 * Returns index within the collection of the passed key.
13102 * @param {String} key The key to find the index of.
13103 * @return {Number} index of the key.
13105 indexOfKey : function(key){
13106 if(!this.keys.indexOf){
13107 for(var i = 0, len = this.keys.length; i < len; i++){
13108 if(this.keys[i] == key) return i;
13112 return this.keys.indexOf(key);
13117 * Returns the item associated with the passed key OR index. Key has priority over index.
13118 * @param {String/Number} key The key or index of the item.
13119 * @return {Object} The item associated with the passed key.
13121 item : function(key){
13122 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13123 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13127 * Returns the item at the specified index.
13128 * @param {Number} index The index of the item.
13131 itemAt : function(index){
13132 return this.items[index];
13136 * Returns the item associated with the passed key.
13137 * @param {String/Number} key The key of the item.
13138 * @return {Object} The item associated with the passed key.
13140 key : function(key){
13141 return this.map[key];
13145 * Returns true if the collection contains the passed Object as an item.
13146 * @param {Object} o The Object to look for in the collection.
13147 * @return {Boolean} True if the collection contains the Object as an item.
13149 contains : function(o){
13150 return this.indexOf(o) != -1;
13154 * Returns true if the collection contains the passed Object as a key.
13155 * @param {String} key The key to look for in the collection.
13156 * @return {Boolean} True if the collection contains the Object as a key.
13158 containsKey : function(key){
13159 return typeof this.map[key] != "undefined";
13163 * Removes all items from the collection.
13165 clear : function(){
13170 this.fireEvent("clear");
13174 * Returns the first item in the collection.
13175 * @return {Object} the first item in the collection..
13177 first : function(){
13178 return this.items[0];
13182 * Returns the last item in the collection.
13183 * @return {Object} the last item in the collection..
13186 return this.items[this.length-1];
13189 _sort : function(property, dir, fn){
13190 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13191 fn = fn || function(a, b){
13194 var c = [], k = this.keys, items = this.items;
13195 for(var i = 0, len = items.length; i < len; i++){
13196 c[c.length] = {key: k[i], value: items[i], index: i};
13198 c.sort(function(a, b){
13199 var v = fn(a[property], b[property]) * dsc;
13201 v = (a.index < b.index ? -1 : 1);
13205 for(var i = 0, len = c.length; i < len; i++){
13206 items[i] = c[i].value;
13209 this.fireEvent("sort", this);
13213 * Sorts this collection with the passed comparison function
13214 * @param {String} direction (optional) "ASC" or "DESC"
13215 * @param {Function} fn (optional) comparison function
13217 sort : function(dir, fn){
13218 this._sort("value", dir, fn);
13222 * Sorts this collection by keys
13223 * @param {String} direction (optional) "ASC" or "DESC"
13224 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13226 keySort : function(dir, fn){
13227 this._sort("key", dir, fn || function(a, b){
13228 return String(a).toUpperCase()-String(b).toUpperCase();
13233 * Returns a range of items in this collection
13234 * @param {Number} startIndex (optional) defaults to 0
13235 * @param {Number} endIndex (optional) default to the last item
13236 * @return {Array} An array of items
13238 getRange : function(start, end){
13239 var items = this.items;
13240 if(items.length < 1){
13243 start = start || 0;
13244 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13247 for(var i = start; i <= end; i++) {
13248 r[r.length] = items[i];
13251 for(var i = start; i >= end; i--) {
13252 r[r.length] = items[i];
13259 * Filter the <i>objects</i> in this collection by a specific property.
13260 * Returns a new collection that has been filtered.
13261 * @param {String} property A property on your objects
13262 * @param {String/RegExp} value Either string that the property values
13263 * should start with or a RegExp to test against the property
13264 * @return {MixedCollection} The new filtered collection
13266 filter : function(property, value){
13267 if(!value.exec){ // not a regex
13268 value = String(value);
13269 if(value.length == 0){
13270 return this.clone();
13272 value = new RegExp("^" + Roo.escapeRe(value), "i");
13274 return this.filterBy(function(o){
13275 return o && value.test(o[property]);
13280 * Filter by a function. * Returns a new collection that has been filtered.
13281 * The passed function will be called with each
13282 * object in the collection. If the function returns true, the value is included
13283 * otherwise it is filtered.
13284 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13285 * @param {Object} scope (optional) The scope of the function (defaults to this)
13286 * @return {MixedCollection} The new filtered collection
13288 filterBy : function(fn, scope){
13289 var r = new Roo.util.MixedCollection();
13290 r.getKey = this.getKey;
13291 var k = this.keys, it = this.items;
13292 for(var i = 0, len = it.length; i < len; i++){
13293 if(fn.call(scope||this, it[i], k[i])){
13294 r.add(k[i], it[i]);
13301 * Creates a duplicate of this collection
13302 * @return {MixedCollection}
13304 clone : function(){
13305 var r = new Roo.util.MixedCollection();
13306 var k = this.keys, it = this.items;
13307 for(var i = 0, len = it.length; i < len; i++){
13308 r.add(k[i], it[i]);
13310 r.getKey = this.getKey;
13315 * Returns the item associated with the passed key or index.
13317 * @param {String/Number} key The key or index of the item.
13318 * @return {Object} The item associated with the passed key.
13320 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13322 * Ext JS Library 1.1.1
13323 * Copyright(c) 2006-2007, Ext JS, LLC.
13325 * Originally Released Under LGPL - original licence link has changed is not relivant.
13328 * <script type="text/javascript">
13331 * @class Roo.util.JSON
13332 * Modified version of Douglas Crockford"s json.js that doesn"t
13333 * mess with the Object prototype
13334 * http://www.json.org/js.html
13337 Roo.util.JSON = new (function(){
13338 var useHasOwn = {}.hasOwnProperty ? true : false;
13340 // crashes Safari in some instances
13341 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13343 var pad = function(n) {
13344 return n < 10 ? "0" + n : n;
13357 var encodeString = function(s){
13358 if (/["\\\x00-\x1f]/.test(s)) {
13359 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13364 c = b.charCodeAt();
13366 Math.floor(c / 16).toString(16) +
13367 (c % 16).toString(16);
13370 return '"' + s + '"';
13373 var encodeArray = function(o){
13374 var a = ["["], b, i, l = o.length, v;
13375 for (i = 0; i < l; i += 1) {
13377 switch (typeof v) {
13386 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13394 var encodeDate = function(o){
13395 return '"' + o.getFullYear() + "-" +
13396 pad(o.getMonth() + 1) + "-" +
13397 pad(o.getDate()) + "T" +
13398 pad(o.getHours()) + ":" +
13399 pad(o.getMinutes()) + ":" +
13400 pad(o.getSeconds()) + '"';
13404 * Encodes an Object, Array or other value
13405 * @param {Mixed} o The variable to encode
13406 * @return {String} The JSON string
13408 this.encode = function(o)
13410 // should this be extended to fully wrap stringify..
13412 if(typeof o == "undefined" || o === null){
13414 }else if(o instanceof Array){
13415 return encodeArray(o);
13416 }else if(o instanceof Date){
13417 return encodeDate(o);
13418 }else if(typeof o == "string"){
13419 return encodeString(o);
13420 }else if(typeof o == "number"){
13421 return isFinite(o) ? String(o) : "null";
13422 }else if(typeof o == "boolean"){
13425 var a = ["{"], b, i, v;
13427 if(!useHasOwn || o.hasOwnProperty(i)) {
13429 switch (typeof v) {
13438 a.push(this.encode(i), ":",
13439 v === null ? "null" : this.encode(v));
13450 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13451 * @param {String} json The JSON string
13452 * @return {Object} The resulting object
13454 this.decode = function(json){
13456 return /** eval:var:json */ eval("(" + json + ')');
13460 * Shorthand for {@link Roo.util.JSON#encode}
13461 * @member Roo encode
13463 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13465 * Shorthand for {@link Roo.util.JSON#decode}
13466 * @member Roo decode
13468 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13471 * Ext JS Library 1.1.1
13472 * Copyright(c) 2006-2007, Ext JS, LLC.
13474 * Originally Released Under LGPL - original licence link has changed is not relivant.
13477 * <script type="text/javascript">
13481 * @class Roo.util.Format
13482 * Reusable data formatting functions
13485 Roo.util.Format = function(){
13486 var trimRe = /^\s+|\s+$/g;
13489 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13490 * @param {String} value The string to truncate
13491 * @param {Number} length The maximum length to allow before truncating
13492 * @return {String} The converted text
13494 ellipsis : function(value, len){
13495 if(value && value.length > len){
13496 return value.substr(0, len-3)+"...";
13502 * Checks a reference and converts it to empty string if it is undefined
13503 * @param {Mixed} value Reference to check
13504 * @return {Mixed} Empty string if converted, otherwise the original value
13506 undef : function(value){
13507 return typeof value != "undefined" ? value : "";
13511 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13512 * @param {String} value The string to encode
13513 * @return {String} The encoded text
13515 htmlEncode : function(value){
13516 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13520 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13521 * @param {String} value The string to decode
13522 * @return {String} The decoded text
13524 htmlDecode : function(value){
13525 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13529 * Trims any whitespace from either side of a string
13530 * @param {String} value The text to trim
13531 * @return {String} The trimmed text
13533 trim : function(value){
13534 return String(value).replace(trimRe, "");
13538 * Returns a substring from within an original string
13539 * @param {String} value The original text
13540 * @param {Number} start The start index of the substring
13541 * @param {Number} length The length of the substring
13542 * @return {String} The substring
13544 substr : function(value, start, length){
13545 return String(value).substr(start, length);
13549 * Converts a string to all lower case letters
13550 * @param {String} value The text to convert
13551 * @return {String} The converted text
13553 lowercase : function(value){
13554 return String(value).toLowerCase();
13558 * Converts a string to all upper case letters
13559 * @param {String} value The text to convert
13560 * @return {String} The converted text
13562 uppercase : function(value){
13563 return String(value).toUpperCase();
13567 * Converts the first character only of a string to upper case
13568 * @param {String} value The text to convert
13569 * @return {String} The converted text
13571 capitalize : function(value){
13572 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13576 call : function(value, fn){
13577 if(arguments.length > 2){
13578 var args = Array.prototype.slice.call(arguments, 2);
13579 args.unshift(value);
13581 return /** eval:var:value */ eval(fn).apply(window, args);
13583 /** eval:var:value */
13584 return /** eval:var:value */ eval(fn).call(window, value);
13590 * safer version of Math.toFixed..??/
13591 * @param {Number/String} value The numeric value to format
13592 * @param {Number/String} value Decimal places
13593 * @return {String} The formatted currency string
13595 toFixed : function(v, n)
13597 // why not use to fixed - precision is buggered???
13599 return Math.round(v-0);
13601 var fact = Math.pow(10,n+1);
13602 v = (Math.round((v-0)*fact))/fact;
13603 var z = (''+fact).substring(2);
13604 if (v == Math.floor(v)) {
13605 return Math.floor(v) + '.' + z;
13608 // now just padd decimals..
13609 var ps = String(v).split('.');
13610 var fd = (ps[1] + z);
13611 var r = fd.substring(0,n);
13612 var rm = fd.substring(n);
13614 return ps[0] + '.' + r;
13616 r*=1; // turn it into a number;
13618 if (String(r).length != n) {
13621 r = String(r).substring(1); // chop the end off.
13624 return ps[0] + '.' + r;
13629 * Format a number as US currency
13630 * @param {Number/String} value The numeric value to format
13631 * @return {String} The formatted currency string
13633 usMoney : function(v){
13634 return '$' + Roo.util.Format.number(v);
13639 * eventually this should probably emulate php's number_format
13640 * @param {Number/String} value The numeric value to format
13641 * @param {Number} decimals number of decimal places
13642 * @return {String} The formatted currency string
13644 number : function(v,decimals)
13646 // multiply and round.
13647 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13648 var mul = Math.pow(10, decimals);
13649 var zero = String(mul).substring(1);
13650 v = (Math.round((v-0)*mul))/mul;
13652 // if it's '0' number.. then
13654 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13656 var ps = v.split('.');
13660 var r = /(\d+)(\d{3})/;
13662 while (r.test(whole)) {
13663 whole = whole.replace(r, '$1' + ',' + '$2');
13669 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13670 // does not have decimals
13671 (decimals ? ('.' + zero) : '');
13674 return whole + sub ;
13678 * Parse a value into a formatted date using the specified format pattern.
13679 * @param {Mixed} value The value to format
13680 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13681 * @return {String} The formatted date string
13683 date : function(v, format){
13687 if(!(v instanceof Date)){
13688 v = new Date(Date.parse(v));
13690 return v.dateFormat(format || Roo.util.Format.defaults.date);
13694 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13695 * @param {String} format Any valid date format string
13696 * @return {Function} The date formatting function
13698 dateRenderer : function(format){
13699 return function(v){
13700 return Roo.util.Format.date(v, format);
13705 stripTagsRE : /<\/?[^>]+>/gi,
13708 * Strips all HTML tags
13709 * @param {Mixed} value The text from which to strip tags
13710 * @return {String} The stripped text
13712 stripTags : function(v){
13713 return !v ? v : String(v).replace(this.stripTagsRE, "");
13717 Roo.util.Format.defaults = {
13721 * Ext JS Library 1.1.1
13722 * Copyright(c) 2006-2007, Ext JS, LLC.
13724 * Originally Released Under LGPL - original licence link has changed is not relivant.
13727 * <script type="text/javascript">
13734 * @class Roo.MasterTemplate
13735 * @extends Roo.Template
13736 * Provides a template that can have child templates. The syntax is:
13738 var t = new Roo.MasterTemplate(
13739 '<select name="{name}">',
13740 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13743 t.add('options', {value: 'foo', text: 'bar'});
13744 // or you can add multiple child elements in one shot
13745 t.addAll('options', [
13746 {value: 'foo', text: 'bar'},
13747 {value: 'foo2', text: 'bar2'},
13748 {value: 'foo3', text: 'bar3'}
13750 // then append, applying the master template values
13751 t.append('my-form', {name: 'my-select'});
13753 * A name attribute for the child template is not required if you have only one child
13754 * template or you want to refer to them by index.
13756 Roo.MasterTemplate = function(){
13757 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13758 this.originalHtml = this.html;
13760 var m, re = this.subTemplateRe;
13763 while(m = re.exec(this.html)){
13764 var name = m[1], content = m[2];
13769 tpl : new Roo.Template(content)
13772 st[name] = st[subIndex];
13774 st[subIndex].tpl.compile();
13775 st[subIndex].tpl.call = this.call.createDelegate(this);
13778 this.subCount = subIndex;
13781 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13783 * The regular expression used to match sub templates
13787 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13790 * Applies the passed values to a child template.
13791 * @param {String/Number} name (optional) The name or index of the child template
13792 * @param {Array/Object} values The values to be applied to the template
13793 * @return {MasterTemplate} this
13795 add : function(name, values){
13796 if(arguments.length == 1){
13797 values = arguments[0];
13800 var s = this.subs[name];
13801 s.buffer[s.buffer.length] = s.tpl.apply(values);
13806 * Applies all the passed values to a child template.
13807 * @param {String/Number} name (optional) The name or index of the child template
13808 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13809 * @param {Boolean} reset (optional) True to reset the template first
13810 * @return {MasterTemplate} this
13812 fill : function(name, values, reset){
13814 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13822 for(var i = 0, len = values.length; i < len; i++){
13823 this.add(name, values[i]);
13829 * Resets the template for reuse
13830 * @return {MasterTemplate} this
13832 reset : function(){
13834 for(var i = 0; i < this.subCount; i++){
13840 applyTemplate : function(values){
13842 var replaceIndex = -1;
13843 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13844 return s[++replaceIndex].buffer.join("");
13846 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13849 apply : function(){
13850 return this.applyTemplate.apply(this, arguments);
13853 compile : function(){return this;}
13857 * Alias for fill().
13860 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13862 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13863 * var tpl = Roo.MasterTemplate.from('element-id');
13864 * @param {String/HTMLElement} el
13865 * @param {Object} config
13868 Roo.MasterTemplate.from = function(el, config){
13869 el = Roo.getDom(el);
13870 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13873 * Ext JS Library 1.1.1
13874 * Copyright(c) 2006-2007, Ext JS, LLC.
13876 * Originally Released Under LGPL - original licence link has changed is not relivant.
13879 * <script type="text/javascript">
13884 * @class Roo.util.CSS
13885 * Utility class for manipulating CSS rules
13888 Roo.util.CSS = function(){
13890 var doc = document;
13892 var camelRe = /(-[a-z])/gi;
13893 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13897 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13898 * tag and appended to the HEAD of the document.
13899 * @param {String|Object} cssText The text containing the css rules
13900 * @param {String} id An id to add to the stylesheet for later removal
13901 * @return {StyleSheet}
13903 createStyleSheet : function(cssText, id){
13905 var head = doc.getElementsByTagName("head")[0];
13906 var nrules = doc.createElement("style");
13907 nrules.setAttribute("type", "text/css");
13909 nrules.setAttribute("id", id);
13911 if (typeof(cssText) != 'string') {
13912 // support object maps..
13913 // not sure if this a good idea..
13914 // perhaps it should be merged with the general css handling
13915 // and handle js style props.
13916 var cssTextNew = [];
13917 for(var n in cssText) {
13919 for(var k in cssText[n]) {
13920 citems.push( k + ' : ' +cssText[n][k] + ';' );
13922 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13925 cssText = cssTextNew.join("\n");
13931 head.appendChild(nrules);
13932 ss = nrules.styleSheet;
13933 ss.cssText = cssText;
13936 nrules.appendChild(doc.createTextNode(cssText));
13938 nrules.cssText = cssText;
13940 head.appendChild(nrules);
13941 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13943 this.cacheStyleSheet(ss);
13948 * Removes a style or link tag by id
13949 * @param {String} id The id of the tag
13951 removeStyleSheet : function(id){
13952 var existing = doc.getElementById(id);
13954 existing.parentNode.removeChild(existing);
13959 * Dynamically swaps an existing stylesheet reference for a new one
13960 * @param {String} id The id of an existing link tag to remove
13961 * @param {String} url The href of the new stylesheet to include
13963 swapStyleSheet : function(id, url){
13964 this.removeStyleSheet(id);
13965 var ss = doc.createElement("link");
13966 ss.setAttribute("rel", "stylesheet");
13967 ss.setAttribute("type", "text/css");
13968 ss.setAttribute("id", id);
13969 ss.setAttribute("href", url);
13970 doc.getElementsByTagName("head")[0].appendChild(ss);
13974 * Refresh the rule cache if you have dynamically added stylesheets
13975 * @return {Object} An object (hash) of rules indexed by selector
13977 refreshCache : function(){
13978 return this.getRules(true);
13982 cacheStyleSheet : function(stylesheet){
13986 try{// try catch for cross domain access issue
13987 var ssRules = stylesheet.cssRules || stylesheet.rules;
13988 for(var j = ssRules.length-1; j >= 0; --j){
13989 rules[ssRules[j].selectorText] = ssRules[j];
13995 * Gets all css rules for the document
13996 * @param {Boolean} refreshCache true to refresh the internal cache
13997 * @return {Object} An object (hash) of rules indexed by selector
13999 getRules : function(refreshCache){
14000 if(rules == null || refreshCache){
14002 var ds = doc.styleSheets;
14003 for(var i =0, len = ds.length; i < len; i++){
14005 this.cacheStyleSheet(ds[i]);
14013 * Gets an an individual CSS rule by selector(s)
14014 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14015 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14016 * @return {CSSRule} The CSS rule or null if one is not found
14018 getRule : function(selector, refreshCache){
14019 var rs = this.getRules(refreshCache);
14020 if(!(selector instanceof Array)){
14021 return rs[selector];
14023 for(var i = 0; i < selector.length; i++){
14024 if(rs[selector[i]]){
14025 return rs[selector[i]];
14033 * Updates a rule property
14034 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14035 * @param {String} property The css property
14036 * @param {String} value The new value for the property
14037 * @return {Boolean} true If a rule was found and updated
14039 updateRule : function(selector, property, value){
14040 if(!(selector instanceof Array)){
14041 var rule = this.getRule(selector);
14043 rule.style[property.replace(camelRe, camelFn)] = value;
14047 for(var i = 0; i < selector.length; i++){
14048 if(this.updateRule(selector[i], property, value)){
14058 * Ext JS Library 1.1.1
14059 * Copyright(c) 2006-2007, Ext JS, LLC.
14061 * Originally Released Under LGPL - original licence link has changed is not relivant.
14064 * <script type="text/javascript">
14070 * @class Roo.util.ClickRepeater
14071 * @extends Roo.util.Observable
14073 * A wrapper class which can be applied to any element. Fires a "click" event while the
14074 * mouse is pressed. The interval between firings may be specified in the config but
14075 * defaults to 10 milliseconds.
14077 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14079 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14080 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14081 * Similar to an autorepeat key delay.
14082 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14083 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14084 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14085 * "interval" and "delay" are ignored. "immediate" is honored.
14086 * @cfg {Boolean} preventDefault True to prevent the default click event
14087 * @cfg {Boolean} stopDefault True to stop the default click event
14090 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14091 * 2007-02-02 jvs Renamed to ClickRepeater
14092 * 2007-02-03 jvs Modifications for FF Mac and Safari
14095 * @param {String/HTMLElement/Element} el The element to listen on
14096 * @param {Object} config
14098 Roo.util.ClickRepeater = function(el, config)
14100 this.el = Roo.get(el);
14101 this.el.unselectable();
14103 Roo.apply(this, config);
14108 * Fires when the mouse button is depressed.
14109 * @param {Roo.util.ClickRepeater} this
14111 "mousedown" : true,
14114 * Fires on a specified interval during the time the element is pressed.
14115 * @param {Roo.util.ClickRepeater} this
14120 * Fires when the mouse key is released.
14121 * @param {Roo.util.ClickRepeater} this
14126 this.el.on("mousedown", this.handleMouseDown, this);
14127 if(this.preventDefault || this.stopDefault){
14128 this.el.on("click", function(e){
14129 if(this.preventDefault){
14130 e.preventDefault();
14132 if(this.stopDefault){
14138 // allow inline handler
14140 this.on("click", this.handler, this.scope || this);
14143 Roo.util.ClickRepeater.superclass.constructor.call(this);
14146 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14149 preventDefault : true,
14150 stopDefault : false,
14154 handleMouseDown : function(){
14155 clearTimeout(this.timer);
14157 if(this.pressClass){
14158 this.el.addClass(this.pressClass);
14160 this.mousedownTime = new Date();
14162 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14163 this.el.on("mouseout", this.handleMouseOut, this);
14165 this.fireEvent("mousedown", this);
14166 this.fireEvent("click", this);
14168 this.timer = this.click.defer(this.delay || this.interval, this);
14172 click : function(){
14173 this.fireEvent("click", this);
14174 this.timer = this.click.defer(this.getInterval(), this);
14178 getInterval: function(){
14179 if(!this.accelerate){
14180 return this.interval;
14182 var pressTime = this.mousedownTime.getElapsed();
14183 if(pressTime < 500){
14185 }else if(pressTime < 1700){
14187 }else if(pressTime < 2600){
14189 }else if(pressTime < 3500){
14191 }else if(pressTime < 4400){
14193 }else if(pressTime < 5300){
14195 }else if(pressTime < 6200){
14203 handleMouseOut : function(){
14204 clearTimeout(this.timer);
14205 if(this.pressClass){
14206 this.el.removeClass(this.pressClass);
14208 this.el.on("mouseover", this.handleMouseReturn, this);
14212 handleMouseReturn : function(){
14213 this.el.un("mouseover", this.handleMouseReturn);
14214 if(this.pressClass){
14215 this.el.addClass(this.pressClass);
14221 handleMouseUp : function(){
14222 clearTimeout(this.timer);
14223 this.el.un("mouseover", this.handleMouseReturn);
14224 this.el.un("mouseout", this.handleMouseOut);
14225 Roo.get(document).un("mouseup", this.handleMouseUp);
14226 this.el.removeClass(this.pressClass);
14227 this.fireEvent("mouseup", this);
14231 * Ext JS Library 1.1.1
14232 * Copyright(c) 2006-2007, Ext JS, LLC.
14234 * Originally Released Under LGPL - original licence link has changed is not relivant.
14237 * <script type="text/javascript">
14242 * @class Roo.KeyNav
14243 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14244 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14245 * way to implement custom navigation schemes for any UI component.</p>
14246 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14247 * pageUp, pageDown, del, home, end. Usage:</p>
14249 var nav = new Roo.KeyNav("my-element", {
14250 "left" : function(e){
14251 this.moveLeft(e.ctrlKey);
14253 "right" : function(e){
14254 this.moveRight(e.ctrlKey);
14256 "enter" : function(e){
14263 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14264 * @param {Object} config The config
14266 Roo.KeyNav = function(el, config){
14267 this.el = Roo.get(el);
14268 Roo.apply(this, config);
14269 if(!this.disabled){
14270 this.disabled = true;
14275 Roo.KeyNav.prototype = {
14277 * @cfg {Boolean} disabled
14278 * True to disable this KeyNav instance (defaults to false)
14282 * @cfg {String} defaultEventAction
14283 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14284 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14285 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14287 defaultEventAction: "stopEvent",
14289 * @cfg {Boolean} forceKeyDown
14290 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14291 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14292 * handle keydown instead of keypress.
14294 forceKeyDown : false,
14297 prepareEvent : function(e){
14298 var k = e.getKey();
14299 var h = this.keyToHandler[k];
14300 //if(h && this[h]){
14301 // e.stopPropagation();
14303 if(Roo.isSafari && h && k >= 37 && k <= 40){
14309 relay : function(e){
14310 var k = e.getKey();
14311 var h = this.keyToHandler[k];
14313 if(this.doRelay(e, this[h], h) !== true){
14314 e[this.defaultEventAction]();
14320 doRelay : function(e, h, hname){
14321 return h.call(this.scope || this, e);
14324 // possible handlers
14338 // quick lookup hash
14355 * Enable this KeyNav
14357 enable: function(){
14359 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14360 // the EventObject will normalize Safari automatically
14361 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14362 this.el.on("keydown", this.relay, this);
14364 this.el.on("keydown", this.prepareEvent, this);
14365 this.el.on("keypress", this.relay, this);
14367 this.disabled = false;
14372 * Disable this KeyNav
14374 disable: function(){
14375 if(!this.disabled){
14376 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14377 this.el.un("keydown", this.relay);
14379 this.el.un("keydown", this.prepareEvent);
14380 this.el.un("keypress", this.relay);
14382 this.disabled = true;
14387 * Ext JS Library 1.1.1
14388 * Copyright(c) 2006-2007, Ext JS, LLC.
14390 * Originally Released Under LGPL - original licence link has changed is not relivant.
14393 * <script type="text/javascript">
14398 * @class Roo.KeyMap
14399 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14400 * The constructor accepts the same config object as defined by {@link #addBinding}.
14401 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14402 * combination it will call the function with this signature (if the match is a multi-key
14403 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14404 * A KeyMap can also handle a string representation of keys.<br />
14407 // map one key by key code
14408 var map = new Roo.KeyMap("my-element", {
14409 key: 13, // or Roo.EventObject.ENTER
14414 // map multiple keys to one action by string
14415 var map = new Roo.KeyMap("my-element", {
14421 // map multiple keys to multiple actions by strings and array of codes
14422 var map = new Roo.KeyMap("my-element", [
14425 fn: function(){ alert("Return was pressed"); }
14428 fn: function(){ alert('a, b or c was pressed'); }
14433 fn: function(){ alert('Control + shift + tab was pressed.'); }
14437 * <b>Note: A KeyMap starts enabled</b>
14439 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14440 * @param {Object} config The config (see {@link #addBinding})
14441 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14443 Roo.KeyMap = function(el, config, eventName){
14444 this.el = Roo.get(el);
14445 this.eventName = eventName || "keydown";
14446 this.bindings = [];
14448 this.addBinding(config);
14453 Roo.KeyMap.prototype = {
14455 * True to stop the event from bubbling and prevent the default browser action if the
14456 * key was handled by the KeyMap (defaults to false)
14462 * Add a new binding to this KeyMap. The following config object properties are supported:
14464 Property Type Description
14465 ---------- --------------- ----------------------------------------------------------------------
14466 key String/Array A single keycode or an array of keycodes to handle
14467 shift Boolean True to handle key only when shift is pressed (defaults to false)
14468 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14469 alt Boolean True to handle key only when alt is pressed (defaults to false)
14470 fn Function The function to call when KeyMap finds the expected key combination
14471 scope Object The scope of the callback function
14477 var map = new Roo.KeyMap(document, {
14478 key: Roo.EventObject.ENTER,
14483 //Add a new binding to the existing KeyMap later
14491 * @param {Object/Array} config A single KeyMap config or an array of configs
14493 addBinding : function(config){
14494 if(config instanceof Array){
14495 for(var i = 0, len = config.length; i < len; i++){
14496 this.addBinding(config[i]);
14500 var keyCode = config.key,
14501 shift = config.shift,
14502 ctrl = config.ctrl,
14505 scope = config.scope;
14506 if(typeof keyCode == "string"){
14508 var keyString = keyCode.toUpperCase();
14509 for(var j = 0, len = keyString.length; j < len; j++){
14510 ks.push(keyString.charCodeAt(j));
14514 var keyArray = keyCode instanceof Array;
14515 var handler = function(e){
14516 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14517 var k = e.getKey();
14519 for(var i = 0, len = keyCode.length; i < len; i++){
14520 if(keyCode[i] == k){
14521 if(this.stopEvent){
14524 fn.call(scope || window, k, e);
14530 if(this.stopEvent){
14533 fn.call(scope || window, k, e);
14538 this.bindings.push(handler);
14542 * Shorthand for adding a single key listener
14543 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14544 * following options:
14545 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14546 * @param {Function} fn The function to call
14547 * @param {Object} scope (optional) The scope of the function
14549 on : function(key, fn, scope){
14550 var keyCode, shift, ctrl, alt;
14551 if(typeof key == "object" && !(key instanceof Array)){
14570 handleKeyDown : function(e){
14571 if(this.enabled){ //just in case
14572 var b = this.bindings;
14573 for(var i = 0, len = b.length; i < len; i++){
14574 b[i].call(this, e);
14580 * Returns true if this KeyMap is enabled
14581 * @return {Boolean}
14583 isEnabled : function(){
14584 return this.enabled;
14588 * Enables this KeyMap
14590 enable: function(){
14592 this.el.on(this.eventName, this.handleKeyDown, this);
14593 this.enabled = true;
14598 * Disable this KeyMap
14600 disable: function(){
14602 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14603 this.enabled = false;
14608 * Ext JS Library 1.1.1
14609 * Copyright(c) 2006-2007, Ext JS, LLC.
14611 * Originally Released Under LGPL - original licence link has changed is not relivant.
14614 * <script type="text/javascript">
14619 * @class Roo.util.TextMetrics
14620 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14621 * wide, in pixels, a given block of text will be.
14624 Roo.util.TextMetrics = function(){
14628 * Measures the size of the specified text
14629 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14630 * that can affect the size of the rendered text
14631 * @param {String} text The text to measure
14632 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14633 * in order to accurately measure the text height
14634 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14636 measure : function(el, text, fixedWidth){
14638 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14641 shared.setFixedWidth(fixedWidth || 'auto');
14642 return shared.getSize(text);
14646 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14647 * the overhead of multiple calls to initialize the style properties on each measurement.
14648 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14649 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14650 * in order to accurately measure the text height
14651 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14653 createInstance : function(el, fixedWidth){
14654 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14661 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14662 var ml = new Roo.Element(document.createElement('div'));
14663 document.body.appendChild(ml.dom);
14664 ml.position('absolute');
14665 ml.setLeftTop(-1000, -1000);
14669 ml.setWidth(fixedWidth);
14674 * Returns the size of the specified text based on the internal element's style and width properties
14675 * @memberOf Roo.util.TextMetrics.Instance#
14676 * @param {String} text The text to measure
14677 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14679 getSize : function(text){
14681 var s = ml.getSize();
14687 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14688 * that can affect the size of the rendered text
14689 * @memberOf Roo.util.TextMetrics.Instance#
14690 * @param {String/HTMLElement} el The element, dom node or id
14692 bind : function(el){
14694 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14699 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14700 * to set a fixed width in order to accurately measure the text height.
14701 * @memberOf Roo.util.TextMetrics.Instance#
14702 * @param {Number} width The width to set on the element
14704 setFixedWidth : function(width){
14705 ml.setWidth(width);
14709 * Returns the measured width of the specified text
14710 * @memberOf Roo.util.TextMetrics.Instance#
14711 * @param {String} text The text to measure
14712 * @return {Number} width The width in pixels
14714 getWidth : function(text){
14715 ml.dom.style.width = 'auto';
14716 return this.getSize(text).width;
14720 * Returns the measured height of the specified text. For multiline text, be sure to call
14721 * {@link #setFixedWidth} if necessary.
14722 * @memberOf Roo.util.TextMetrics.Instance#
14723 * @param {String} text The text to measure
14724 * @return {Number} height The height in pixels
14726 getHeight : function(text){
14727 return this.getSize(text).height;
14731 instance.bind(bindTo);
14736 // backwards compat
14737 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14739 * Ext JS Library 1.1.1
14740 * Copyright(c) 2006-2007, Ext JS, LLC.
14742 * Originally Released Under LGPL - original licence link has changed is not relivant.
14745 * <script type="text/javascript">
14749 * @class Roo.state.Provider
14750 * Abstract base class for state provider implementations. This class provides methods
14751 * for encoding and decoding <b>typed</b> variables including dates and defines the
14752 * Provider interface.
14754 Roo.state.Provider = function(){
14756 * @event statechange
14757 * Fires when a state change occurs.
14758 * @param {Provider} this This state provider
14759 * @param {String} key The state key which was changed
14760 * @param {String} value The encoded value for the state
14763 "statechange": true
14766 Roo.state.Provider.superclass.constructor.call(this);
14768 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14770 * Returns the current value for a key
14771 * @param {String} name The key name
14772 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14773 * @return {Mixed} The state data
14775 get : function(name, defaultValue){
14776 return typeof this.state[name] == "undefined" ?
14777 defaultValue : this.state[name];
14781 * Clears a value from the state
14782 * @param {String} name The key name
14784 clear : function(name){
14785 delete this.state[name];
14786 this.fireEvent("statechange", this, name, null);
14790 * Sets the value for a key
14791 * @param {String} name The key name
14792 * @param {Mixed} value The value to set
14794 set : function(name, value){
14795 this.state[name] = value;
14796 this.fireEvent("statechange", this, name, value);
14800 * Decodes a string previously encoded with {@link #encodeValue}.
14801 * @param {String} value The value to decode
14802 * @return {Mixed} The decoded value
14804 decodeValue : function(cookie){
14805 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14806 var matches = re.exec(unescape(cookie));
14807 if(!matches || !matches[1]) return; // non state cookie
14808 var type = matches[1];
14809 var v = matches[2];
14812 return parseFloat(v);
14814 return new Date(Date.parse(v));
14819 var values = v.split("^");
14820 for(var i = 0, len = values.length; i < len; i++){
14821 all.push(this.decodeValue(values[i]));
14826 var values = v.split("^");
14827 for(var i = 0, len = values.length; i < len; i++){
14828 var kv = values[i].split("=");
14829 all[kv[0]] = this.decodeValue(kv[1]);
14838 * Encodes a value including type information. Decode with {@link #decodeValue}.
14839 * @param {Mixed} value The value to encode
14840 * @return {String} The encoded value
14842 encodeValue : function(v){
14844 if(typeof v == "number"){
14846 }else if(typeof v == "boolean"){
14847 enc = "b:" + (v ? "1" : "0");
14848 }else if(v instanceof Date){
14849 enc = "d:" + v.toGMTString();
14850 }else if(v instanceof Array){
14852 for(var i = 0, len = v.length; i < len; i++){
14853 flat += this.encodeValue(v[i]);
14854 if(i != len-1) flat += "^";
14857 }else if(typeof v == "object"){
14860 if(typeof v[key] != "function"){
14861 flat += key + "=" + this.encodeValue(v[key]) + "^";
14864 enc = "o:" + flat.substring(0, flat.length-1);
14868 return escape(enc);
14874 * Ext JS Library 1.1.1
14875 * Copyright(c) 2006-2007, Ext JS, LLC.
14877 * Originally Released Under LGPL - original licence link has changed is not relivant.
14880 * <script type="text/javascript">
14883 * @class Roo.state.Manager
14884 * This is the global state manager. By default all components that are "state aware" check this class
14885 * for state information if you don't pass them a custom state provider. In order for this class
14886 * to be useful, it must be initialized with a provider when your application initializes.
14888 // in your initialization function
14890 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14892 // supposed you have a {@link Roo.BorderLayout}
14893 var layout = new Roo.BorderLayout(...);
14894 layout.restoreState();
14895 // or a {Roo.BasicDialog}
14896 var dialog = new Roo.BasicDialog(...);
14897 dialog.restoreState();
14901 Roo.state.Manager = function(){
14902 var provider = new Roo.state.Provider();
14906 * Configures the default state provider for your application
14907 * @param {Provider} stateProvider The state provider to set
14909 setProvider : function(stateProvider){
14910 provider = stateProvider;
14914 * Returns the current value for a key
14915 * @param {String} name The key name
14916 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14917 * @return {Mixed} The state data
14919 get : function(key, defaultValue){
14920 return provider.get(key, defaultValue);
14924 * Sets the value for a key
14925 * @param {String} name The key name
14926 * @param {Mixed} value The state data
14928 set : function(key, value){
14929 provider.set(key, value);
14933 * Clears a value from the state
14934 * @param {String} name The key name
14936 clear : function(key){
14937 provider.clear(key);
14941 * Gets the currently configured state provider
14942 * @return {Provider} The state provider
14944 getProvider : function(){
14951 * Ext JS Library 1.1.1
14952 * Copyright(c) 2006-2007, Ext JS, LLC.
14954 * Originally Released Under LGPL - original licence link has changed is not relivant.
14957 * <script type="text/javascript">
14960 * @class Roo.state.CookieProvider
14961 * @extends Roo.state.Provider
14962 * The default Provider implementation which saves state via cookies.
14965 var cp = new Roo.state.CookieProvider({
14967 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14968 domain: "roojs.com"
14970 Roo.state.Manager.setProvider(cp);
14972 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14973 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14974 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14975 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14976 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14977 * domain the page is running on including the 'www' like 'www.roojs.com')
14978 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14980 * Create a new CookieProvider
14981 * @param {Object} config The configuration object
14983 Roo.state.CookieProvider = function(config){
14984 Roo.state.CookieProvider.superclass.constructor.call(this);
14986 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14987 this.domain = null;
14988 this.secure = false;
14989 Roo.apply(this, config);
14990 this.state = this.readCookies();
14993 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14995 set : function(name, value){
14996 if(typeof value == "undefined" || value === null){
15000 this.setCookie(name, value);
15001 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15005 clear : function(name){
15006 this.clearCookie(name);
15007 Roo.state.CookieProvider.superclass.clear.call(this, name);
15011 readCookies : function(){
15013 var c = document.cookie + ";";
15014 var re = /\s?(.*?)=(.*?);/g;
15016 while((matches = re.exec(c)) != null){
15017 var name = matches[1];
15018 var value = matches[2];
15019 if(name && name.substring(0,3) == "ys-"){
15020 cookies[name.substr(3)] = this.decodeValue(value);
15027 setCookie : function(name, value){
15028 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15029 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15030 ((this.path == null) ? "" : ("; path=" + this.path)) +
15031 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15032 ((this.secure == true) ? "; secure" : "");
15036 clearCookie : function(name){
15037 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15038 ((this.path == null) ? "" : ("; path=" + this.path)) +
15039 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15040 ((this.secure == true) ? "; secure" : "");
15044 * Ext JS Library 1.1.1
15045 * Copyright(c) 2006-2007, Ext JS, LLC.
15047 * Originally Released Under LGPL - original licence link has changed is not relivant.
15050 * <script type="text/javascript">
15055 * @class Roo.ComponentMgr
15056 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15059 Roo.ComponentMgr = function(){
15060 var all = new Roo.util.MixedCollection();
15064 * Registers a component.
15065 * @param {Roo.Component} c The component
15067 register : function(c){
15072 * Unregisters a component.
15073 * @param {Roo.Component} c The component
15075 unregister : function(c){
15080 * Returns a component by id
15081 * @param {String} id The component id
15083 get : function(id){
15084 return all.get(id);
15088 * Registers a function that will be called when a specified component is added to ComponentMgr
15089 * @param {String} id The component id
15090 * @param {Funtction} fn The callback function
15091 * @param {Object} scope The scope of the callback
15093 onAvailable : function(id, fn, scope){
15094 all.on("add", function(index, o){
15096 fn.call(scope || o, o);
15097 all.un("add", fn, scope);
15104 * Ext JS Library 1.1.1
15105 * Copyright(c) 2006-2007, Ext JS, LLC.
15107 * Originally Released Under LGPL - original licence link has changed is not relivant.
15110 * <script type="text/javascript">
15114 * @class Roo.Component
15115 * @extends Roo.util.Observable
15116 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15117 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15118 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15119 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15120 * All visual components (widgets) that require rendering into a layout should subclass Component.
15122 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15123 * 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
15124 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15126 Roo.Component = function(config){
15127 config = config || {};
15128 if(config.tagName || config.dom || typeof config == "string"){ // element object
15129 config = {el: config, id: config.id || config};
15131 this.initialConfig = config;
15133 Roo.apply(this, config);
15137 * Fires after the component is disabled.
15138 * @param {Roo.Component} this
15143 * Fires after the component is enabled.
15144 * @param {Roo.Component} this
15148 * @event beforeshow
15149 * Fires before the component is shown. Return false to stop the show.
15150 * @param {Roo.Component} this
15155 * Fires after the component is shown.
15156 * @param {Roo.Component} this
15160 * @event beforehide
15161 * Fires before the component is hidden. Return false to stop the hide.
15162 * @param {Roo.Component} this
15167 * Fires after the component is hidden.
15168 * @param {Roo.Component} this
15172 * @event beforerender
15173 * Fires before the component is rendered. Return false to stop the render.
15174 * @param {Roo.Component} this
15176 beforerender : true,
15179 * Fires after the component is rendered.
15180 * @param {Roo.Component} this
15184 * @event beforedestroy
15185 * Fires before the component is destroyed. Return false to stop the destroy.
15186 * @param {Roo.Component} this
15188 beforedestroy : true,
15191 * Fires after the component is destroyed.
15192 * @param {Roo.Component} this
15197 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15199 Roo.ComponentMgr.register(this);
15200 Roo.Component.superclass.constructor.call(this);
15201 this.initComponent();
15202 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15203 this.render(this.renderTo);
15204 delete this.renderTo;
15209 Roo.Component.AUTO_ID = 1000;
15211 Roo.extend(Roo.Component, Roo.util.Observable, {
15213 * @scope Roo.Component.prototype
15215 * true if this component is hidden. Read-only.
15220 * true if this component is disabled. Read-only.
15225 * true if this component has been rendered. Read-only.
15229 /** @cfg {String} disableClass
15230 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15232 disabledClass : "x-item-disabled",
15233 /** @cfg {Boolean} allowDomMove
15234 * Whether the component can move the Dom node when rendering (defaults to true).
15236 allowDomMove : true,
15237 /** @cfg {String} hideMode (display|visibility)
15238 * How this component should hidden. Supported values are
15239 * "visibility" (css visibility), "offsets" (negative offset position) and
15240 * "display" (css display) - defaults to "display".
15242 hideMode: 'display',
15245 ctype : "Roo.Component",
15248 * @cfg {String} actionMode
15249 * which property holds the element that used for hide() / show() / disable() / enable()
15255 getActionEl : function(){
15256 return this[this.actionMode];
15259 initComponent : Roo.emptyFn,
15261 * If this is a lazy rendering component, render it to its container element.
15262 * @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.
15264 render : function(container, position){
15265 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15266 if(!container && this.el){
15267 this.el = Roo.get(this.el);
15268 container = this.el.dom.parentNode;
15269 this.allowDomMove = false;
15271 this.container = Roo.get(container);
15272 this.rendered = true;
15273 if(position !== undefined){
15274 if(typeof position == 'number'){
15275 position = this.container.dom.childNodes[position];
15277 position = Roo.getDom(position);
15280 this.onRender(this.container, position || null);
15282 this.el.addClass(this.cls);
15286 this.el.applyStyles(this.style);
15289 this.fireEvent("render", this);
15290 this.afterRender(this.container);
15302 // default function is not really useful
15303 onRender : function(ct, position){
15305 this.el = Roo.get(this.el);
15306 if(this.allowDomMove !== false){
15307 ct.dom.insertBefore(this.el.dom, position);
15313 getAutoCreate : function(){
15314 var cfg = typeof this.autoCreate == "object" ?
15315 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15316 if(this.id && !cfg.id){
15323 afterRender : Roo.emptyFn,
15326 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15327 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15329 destroy : function(){
15330 if(this.fireEvent("beforedestroy", this) !== false){
15331 this.purgeListeners();
15332 this.beforeDestroy();
15334 this.el.removeAllListeners();
15336 if(this.actionMode == "container"){
15337 this.container.remove();
15341 Roo.ComponentMgr.unregister(this);
15342 this.fireEvent("destroy", this);
15347 beforeDestroy : function(){
15352 onDestroy : function(){
15357 * Returns the underlying {@link Roo.Element}.
15358 * @return {Roo.Element} The element
15360 getEl : function(){
15365 * Returns the id of this component.
15368 getId : function(){
15373 * Try to focus this component.
15374 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15375 * @return {Roo.Component} this
15377 focus : function(selectText){
15380 if(selectText === true){
15381 this.el.dom.select();
15396 * Disable this component.
15397 * @return {Roo.Component} this
15399 disable : function(){
15403 this.disabled = true;
15404 this.fireEvent("disable", this);
15409 onDisable : function(){
15410 this.getActionEl().addClass(this.disabledClass);
15411 this.el.dom.disabled = true;
15415 * Enable this component.
15416 * @return {Roo.Component} this
15418 enable : function(){
15422 this.disabled = false;
15423 this.fireEvent("enable", this);
15428 onEnable : function(){
15429 this.getActionEl().removeClass(this.disabledClass);
15430 this.el.dom.disabled = false;
15434 * Convenience function for setting disabled/enabled by boolean.
15435 * @param {Boolean} disabled
15437 setDisabled : function(disabled){
15438 this[disabled ? "disable" : "enable"]();
15442 * Show this component.
15443 * @return {Roo.Component} this
15446 if(this.fireEvent("beforeshow", this) !== false){
15447 this.hidden = false;
15451 this.fireEvent("show", this);
15457 onShow : function(){
15458 var ae = this.getActionEl();
15459 if(this.hideMode == 'visibility'){
15460 ae.dom.style.visibility = "visible";
15461 }else if(this.hideMode == 'offsets'){
15462 ae.removeClass('x-hidden');
15464 ae.dom.style.display = "";
15469 * Hide this component.
15470 * @return {Roo.Component} this
15473 if(this.fireEvent("beforehide", this) !== false){
15474 this.hidden = true;
15478 this.fireEvent("hide", this);
15484 onHide : function(){
15485 var ae = this.getActionEl();
15486 if(this.hideMode == 'visibility'){
15487 ae.dom.style.visibility = "hidden";
15488 }else if(this.hideMode == 'offsets'){
15489 ae.addClass('x-hidden');
15491 ae.dom.style.display = "none";
15496 * Convenience function to hide or show this component by boolean.
15497 * @param {Boolean} visible True to show, false to hide
15498 * @return {Roo.Component} this
15500 setVisible: function(visible){
15510 * Returns true if this component is visible.
15512 isVisible : function(){
15513 return this.getActionEl().isVisible();
15516 cloneConfig : function(overrides){
15517 overrides = overrides || {};
15518 var id = overrides.id || Roo.id();
15519 var cfg = Roo.applyIf(overrides, this.initialConfig);
15520 cfg.id = id; // prevent dup id
15521 return new this.constructor(cfg);
15525 * Ext JS Library 1.1.1
15526 * Copyright(c) 2006-2007, Ext JS, LLC.
15528 * Originally Released Under LGPL - original licence link has changed is not relivant.
15531 * <script type="text/javascript">
15535 * @class Roo.BoxComponent
15536 * @extends Roo.Component
15537 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15538 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15539 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15540 * layout containers.
15542 * @param {Roo.Element/String/Object} config The configuration options.
15544 Roo.BoxComponent = function(config){
15545 Roo.Component.call(this, config);
15549 * Fires after the component is resized.
15550 * @param {Roo.Component} this
15551 * @param {Number} adjWidth The box-adjusted width that was set
15552 * @param {Number} adjHeight The box-adjusted height that was set
15553 * @param {Number} rawWidth The width that was originally specified
15554 * @param {Number} rawHeight The height that was originally specified
15559 * Fires after the component is moved.
15560 * @param {Roo.Component} this
15561 * @param {Number} x The new x position
15562 * @param {Number} y The new y position
15568 Roo.extend(Roo.BoxComponent, Roo.Component, {
15569 // private, set in afterRender to signify that the component has been rendered
15571 // private, used to defer height settings to subclasses
15572 deferHeight: false,
15573 /** @cfg {Number} width
15574 * width (optional) size of component
15576 /** @cfg {Number} height
15577 * height (optional) size of component
15581 * Sets the width and height of the component. This method fires the resize event. This method can accept
15582 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15583 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15584 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15585 * @return {Roo.BoxComponent} this
15587 setSize : function(w, h){
15588 // support for standard size objects
15589 if(typeof w == 'object'){
15594 if(!this.boxReady){
15600 // prevent recalcs when not needed
15601 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15604 this.lastSize = {width: w, height: h};
15606 var adj = this.adjustSize(w, h);
15607 var aw = adj.width, ah = adj.height;
15608 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15609 var rz = this.getResizeEl();
15610 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15611 rz.setSize(aw, ah);
15612 }else if(!this.deferHeight && ah !== undefined){
15614 }else if(aw !== undefined){
15617 this.onResize(aw, ah, w, h);
15618 this.fireEvent('resize', this, aw, ah, w, h);
15624 * Gets the current size of the component's underlying element.
15625 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15627 getSize : function(){
15628 return this.el.getSize();
15632 * Gets the current XY position of the component's underlying element.
15633 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15634 * @return {Array} The XY position of the element (e.g., [100, 200])
15636 getPosition : function(local){
15637 if(local === true){
15638 return [this.el.getLeft(true), this.el.getTop(true)];
15640 return this.xy || this.el.getXY();
15644 * Gets the current box measurements of the component's underlying element.
15645 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15646 * @returns {Object} box An object in the format {x, y, width, height}
15648 getBox : function(local){
15649 var s = this.el.getSize();
15651 s.x = this.el.getLeft(true);
15652 s.y = this.el.getTop(true);
15654 var xy = this.xy || this.el.getXY();
15662 * Sets the current box measurements of the component's underlying element.
15663 * @param {Object} box An object in the format {x, y, width, height}
15664 * @returns {Roo.BoxComponent} this
15666 updateBox : function(box){
15667 this.setSize(box.width, box.height);
15668 this.setPagePosition(box.x, box.y);
15673 getResizeEl : function(){
15674 return this.resizeEl || this.el;
15678 getPositionEl : function(){
15679 return this.positionEl || this.el;
15683 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15684 * This method fires the move event.
15685 * @param {Number} left The new left
15686 * @param {Number} top The new top
15687 * @returns {Roo.BoxComponent} this
15689 setPosition : function(x, y){
15692 if(!this.boxReady){
15695 var adj = this.adjustPosition(x, y);
15696 var ax = adj.x, ay = adj.y;
15698 var el = this.getPositionEl();
15699 if(ax !== undefined || ay !== undefined){
15700 if(ax !== undefined && ay !== undefined){
15701 el.setLeftTop(ax, ay);
15702 }else if(ax !== undefined){
15704 }else if(ay !== undefined){
15707 this.onPosition(ax, ay);
15708 this.fireEvent('move', this, ax, ay);
15714 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15715 * This method fires the move event.
15716 * @param {Number} x The new x position
15717 * @param {Number} y The new y position
15718 * @returns {Roo.BoxComponent} this
15720 setPagePosition : function(x, y){
15723 if(!this.boxReady){
15726 if(x === undefined || y === undefined){ // cannot translate undefined points
15729 var p = this.el.translatePoints(x, y);
15730 this.setPosition(p.left, p.top);
15735 onRender : function(ct, position){
15736 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15738 this.resizeEl = Roo.get(this.resizeEl);
15740 if(this.positionEl){
15741 this.positionEl = Roo.get(this.positionEl);
15746 afterRender : function(){
15747 Roo.BoxComponent.superclass.afterRender.call(this);
15748 this.boxReady = true;
15749 this.setSize(this.width, this.height);
15750 if(this.x || this.y){
15751 this.setPosition(this.x, this.y);
15753 if(this.pageX || this.pageY){
15754 this.setPagePosition(this.pageX, this.pageY);
15759 * Force the component's size to recalculate based on the underlying element's current height and width.
15760 * @returns {Roo.BoxComponent} this
15762 syncSize : function(){
15763 delete this.lastSize;
15764 this.setSize(this.el.getWidth(), this.el.getHeight());
15769 * Called after the component is resized, this method is empty by default but can be implemented by any
15770 * subclass that needs to perform custom logic after a resize occurs.
15771 * @param {Number} adjWidth The box-adjusted width that was set
15772 * @param {Number} adjHeight The box-adjusted height that was set
15773 * @param {Number} rawWidth The width that was originally specified
15774 * @param {Number} rawHeight The height that was originally specified
15776 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15781 * Called after the component is moved, this method is empty by default but can be implemented by any
15782 * subclass that needs to perform custom logic after a move occurs.
15783 * @param {Number} x The new x position
15784 * @param {Number} y The new y position
15786 onPosition : function(x, y){
15791 adjustSize : function(w, h){
15792 if(this.autoWidth){
15795 if(this.autoHeight){
15798 return {width : w, height: h};
15802 adjustPosition : function(x, y){
15803 return {x : x, y: y};
15806 * Original code for Roojs - LGPL
15807 * <script type="text/javascript">
15811 * @class Roo.XComponent
15812 * A delayed Element creator...
15813 * Or a way to group chunks of interface together.
15814 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15815 * used in conjunction with XComponent.build() it will create an instance of each element,
15816 * then call addxtype() to build the User interface.
15818 * Mypart.xyx = new Roo.XComponent({
15820 parent : 'Mypart.xyz', // empty == document.element.!!
15824 disabled : function() {}
15826 tree : function() { // return an tree of xtype declared components
15830 xtype : 'NestedLayoutPanel',
15837 * It can be used to build a big heiracy, with parent etc.
15838 * or you can just use this to render a single compoent to a dom element
15839 * MYPART.render(Roo.Element | String(id) | dom_element )
15846 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15847 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15849 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15851 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15852 * - if mulitple topModules exist, the last one is defined as the top module.
15856 * When the top level or multiple modules are to embedded into a existing HTML page,
15857 * the parent element can container '#id' of the element where the module will be drawn.
15861 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15862 * it relies more on a include mechanism, where sub modules are included into an outer page.
15863 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15865 * Bootstrap Roo Included elements
15867 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15868 * hence confusing the component builder as it thinks there are multiple top level elements.
15872 * @extends Roo.util.Observable
15874 * @param cfg {Object} configuration of component
15877 Roo.XComponent = function(cfg) {
15878 Roo.apply(this, cfg);
15882 * Fires when this the componnt is built
15883 * @param {Roo.XComponent} c the component
15888 this.region = this.region || 'center'; // default..
15889 Roo.XComponent.register(this);
15890 this.modules = false;
15891 this.el = false; // where the layout goes..
15895 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15898 * The created element (with Roo.factory())
15899 * @type {Roo.Layout}
15905 * for BC - use el in new code
15906 * @type {Roo.Layout}
15912 * for BC - use el in new code
15913 * @type {Roo.Layout}
15918 * @cfg {Function|boolean} disabled
15919 * If this module is disabled by some rule, return true from the funtion
15924 * @cfg {String} parent
15925 * Name of parent element which it get xtype added to..
15930 * @cfg {String} order
15931 * Used to set the order in which elements are created (usefull for multiple tabs)
15936 * @cfg {String} name
15937 * String to display while loading.
15941 * @cfg {String} region
15942 * Region to render component to (defaults to center)
15947 * @cfg {Array} items
15948 * A single item array - the first element is the root of the tree..
15949 * It's done this way to stay compatible with the Xtype system...
15955 * The method that retuns the tree of parts that make up this compoennt
15962 * render element to dom or tree
15963 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15966 render : function(el)
15970 var hp = this.parent ? 1 : 0;
15971 Roo.debug && Roo.log(this);
15973 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15974 // if parent is a '#.....' string, then let's use that..
15975 var ename = this.parent.substr(1);
15976 this.parent = false;
15977 Roo.debug && Roo.log(ename);
15979 case 'bootstrap-body' :
15980 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15981 this.parent = { el : new Roo.bootstrap.Body() };
15982 Roo.debug && Roo.log("setting el to doc body");
15985 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15989 this.parent = { el : true};
15992 el = Roo.get(ename);
15997 if (!el && !this.parent) {
15998 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16002 Roo.debug && Roo.log("EL:");
16003 Roo.debug && Roo.log(el);
16004 Roo.debug && Roo.log("this.parent.el:");
16005 Roo.debug && Roo.log(this.parent.el);
16007 var tree = this._tree ? this._tree() : this.tree();
16009 // altertive root elements ??? - we need a better way to indicate these.
16010 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16011 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16013 if (!this.parent && is_alt) {
16014 //el = Roo.get(document.body);
16015 this.parent = { el : true };
16020 if (!this.parent) {
16022 Roo.debug && Roo.log("no parent - creating one");
16024 el = el ? Roo.get(el) : false;
16026 // it's a top level one..
16028 el : new Roo.BorderLayout(el || document.body, {
16034 tabPosition: 'top',
16035 //resizeTabs: true,
16036 alwaysShowTabs: el && hp? false : true,
16037 hideTabs: el || !hp ? true : false,
16044 if (!this.parent.el) {
16045 // probably an old style ctor, which has been disabled.
16049 // The 'tree' method is '_tree now'
16051 tree.region = tree.region || this.region;
16053 if (this.parent.el === true) {
16054 // bootstrap... - body..
16055 this.parent.el = Roo.factory(tree);
16058 this.el = this.parent.el.addxtype(tree);
16059 this.fireEvent('built', this);
16061 this.panel = this.el;
16062 this.layout = this.panel.layout;
16063 this.parentLayout = this.parent.layout || false;
16069 Roo.apply(Roo.XComponent, {
16071 * @property hideProgress
16072 * true to disable the building progress bar.. usefull on single page renders.
16075 hideProgress : false,
16077 * @property buildCompleted
16078 * True when the builder has completed building the interface.
16081 buildCompleted : false,
16084 * @property topModule
16085 * the upper most module - uses document.element as it's constructor.
16092 * @property modules
16093 * array of modules to be created by registration system.
16094 * @type {Array} of Roo.XComponent
16099 * @property elmodules
16100 * array of modules to be created by which use #ID
16101 * @type {Array} of Roo.XComponent
16107 * @property build_from_html
16108 * Build elements from html - used by bootstrap HTML stuff
16109 * - this is cleared after build is completed
16110 * @type {boolean} true (default false)
16113 build_from_html : false,
16116 * Register components to be built later.
16118 * This solves the following issues
16119 * - Building is not done on page load, but after an authentication process has occured.
16120 * - Interface elements are registered on page load
16121 * - Parent Interface elements may not be loaded before child, so this handles that..
16128 module : 'Pman.Tab.projectMgr',
16130 parent : 'Pman.layout',
16131 disabled : false, // or use a function..
16134 * * @param {Object} details about module
16136 register : function(obj) {
16138 Roo.XComponent.event.fireEvent('register', obj);
16139 switch(typeof(obj.disabled) ) {
16145 if ( obj.disabled() ) {
16151 if (obj.disabled) {
16157 this.modules.push(obj);
16161 * convert a string to an object..
16162 * eg. 'AAA.BBB' -> finds AAA.BBB
16166 toObject : function(str)
16168 if (!str || typeof(str) == 'object') {
16171 if (str.substring(0,1) == '#') {
16175 var ar = str.split('.');
16180 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16182 throw "Module not found : " + str;
16186 throw "Module not found : " + str;
16188 Roo.each(ar, function(e) {
16189 if (typeof(o[e]) == 'undefined') {
16190 throw "Module not found : " + str;
16201 * move modules into their correct place in the tree..
16204 preBuild : function ()
16207 Roo.each(this.modules , function (obj)
16209 Roo.XComponent.event.fireEvent('beforebuild', obj);
16211 var opar = obj.parent;
16213 obj.parent = this.toObject(opar);
16215 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16220 Roo.debug && Roo.log("GOT top level module");
16221 Roo.debug && Roo.log(obj);
16222 obj.modules = new Roo.util.MixedCollection(false,
16223 function(o) { return o.order + '' }
16225 this.topModule = obj;
16228 // parent is a string (usually a dom element name..)
16229 if (typeof(obj.parent) == 'string') {
16230 this.elmodules.push(obj);
16233 if (obj.parent.constructor != Roo.XComponent) {
16234 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16236 if (!obj.parent.modules) {
16237 obj.parent.modules = new Roo.util.MixedCollection(false,
16238 function(o) { return o.order + '' }
16241 if (obj.parent.disabled) {
16242 obj.disabled = true;
16244 obj.parent.modules.add(obj);
16249 * make a list of modules to build.
16250 * @return {Array} list of modules.
16253 buildOrder : function()
16256 var cmp = function(a,b) {
16257 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16259 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16260 throw "No top level modules to build";
16263 // make a flat list in order of modules to build.
16264 var mods = this.topModule ? [ this.topModule ] : [];
16267 // elmodules (is a list of DOM based modules )
16268 Roo.each(this.elmodules, function(e) {
16270 if (!this.topModule &&
16271 typeof(e.parent) == 'string' &&
16272 e.parent.substring(0,1) == '#' &&
16273 Roo.get(e.parent.substr(1))
16276 _this.topModule = e;
16282 // add modules to their parents..
16283 var addMod = function(m) {
16284 Roo.debug && Roo.log("build Order: add: " + m.name);
16287 if (m.modules && !m.disabled) {
16288 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16289 m.modules.keySort('ASC', cmp );
16290 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16292 m.modules.each(addMod);
16294 Roo.debug && Roo.log("build Order: no child modules");
16296 // not sure if this is used any more..
16298 m.finalize.name = m.name + " (clean up) ";
16299 mods.push(m.finalize);
16303 if (this.topModule && this.topModule.modules) {
16304 this.topModule.modules.keySort('ASC', cmp );
16305 this.topModule.modules.each(addMod);
16311 * Build the registered modules.
16312 * @param {Object} parent element.
16313 * @param {Function} optional method to call after module has been added.
16317 build : function(opts)
16320 if (typeof(opts) != 'undefined') {
16321 Roo.apply(this,opts);
16325 var mods = this.buildOrder();
16327 //this.allmods = mods;
16328 //Roo.debug && Roo.log(mods);
16330 if (!mods.length) { // should not happen
16331 throw "NO modules!!!";
16335 var msg = "Building Interface...";
16336 // flash it up as modal - so we store the mask!?
16337 if (!this.hideProgress && Roo.MessageBox) {
16338 Roo.MessageBox.show({ title: 'loading' });
16339 Roo.MessageBox.show({
16340 title: "Please wait...",
16349 var total = mods.length;
16352 var progressRun = function() {
16353 if (!mods.length) {
16354 Roo.debug && Roo.log('hide?');
16355 if (!this.hideProgress && Roo.MessageBox) {
16356 Roo.MessageBox.hide();
16358 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16360 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16366 var m = mods.shift();
16369 Roo.debug && Roo.log(m);
16370 // not sure if this is supported any more.. - modules that are are just function
16371 if (typeof(m) == 'function') {
16373 return progressRun.defer(10, _this);
16377 msg = "Building Interface " + (total - mods.length) +
16379 (m.name ? (' - ' + m.name) : '');
16380 Roo.debug && Roo.log(msg);
16381 if (!this.hideProgress && Roo.MessageBox) {
16382 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16386 // is the module disabled?
16387 var disabled = (typeof(m.disabled) == 'function') ?
16388 m.disabled.call(m.module.disabled) : m.disabled;
16392 return progressRun(); // we do not update the display!
16400 // it's 10 on top level, and 1 on others??? why...
16401 return progressRun.defer(10, _this);
16404 progressRun.defer(1, _this);
16418 * wrapper for event.on - aliased later..
16419 * Typically use to register a event handler for register:
16421 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16430 Roo.XComponent.event = new Roo.util.Observable({
16434 * Fires when an Component is registered,
16435 * set the disable property on the Component to stop registration.
16436 * @param {Roo.XComponent} c the component being registerd.
16441 * @event beforebuild
16442 * Fires before each Component is built
16443 * can be used to apply permissions.
16444 * @param {Roo.XComponent} c the component being registerd.
16447 'beforebuild' : true,
16449 * @event buildcomplete
16450 * Fires on the top level element when all elements have been built
16451 * @param {Roo.XComponent} the top level component.
16453 'buildcomplete' : true
16458 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16461 * Ext JS Library 1.1.1
16462 * Copyright(c) 2006-2007, Ext JS, LLC.
16464 * Originally Released Under LGPL - original licence link has changed is not relivant.
16467 * <script type="text/javascript">
16473 * These classes are derivatives of the similarly named classes in the YUI Library.
16474 * The original license:
16475 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16476 * Code licensed under the BSD License:
16477 * http://developer.yahoo.net/yui/license.txt
16482 var Event=Roo.EventManager;
16483 var Dom=Roo.lib.Dom;
16486 * @class Roo.dd.DragDrop
16487 * @extends Roo.util.Observable
16488 * Defines the interface and base operation of items that that can be
16489 * dragged or can be drop targets. It was designed to be extended, overriding
16490 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16491 * Up to three html elements can be associated with a DragDrop instance:
16493 * <li>linked element: the element that is passed into the constructor.
16494 * This is the element which defines the boundaries for interaction with
16495 * other DragDrop objects.</li>
16496 * <li>handle element(s): The drag operation only occurs if the element that
16497 * was clicked matches a handle element. By default this is the linked
16498 * element, but there are times that you will want only a portion of the
16499 * linked element to initiate the drag operation, and the setHandleElId()
16500 * method provides a way to define this.</li>
16501 * <li>drag element: this represents the element that would be moved along
16502 * with the cursor during a drag operation. By default, this is the linked
16503 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16504 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16507 * This class should not be instantiated until the onload event to ensure that
16508 * the associated elements are available.
16509 * The following would define a DragDrop obj that would interact with any
16510 * other DragDrop obj in the "group1" group:
16512 * dd = new Roo.dd.DragDrop("div1", "group1");
16514 * Since none of the event handlers have been implemented, nothing would
16515 * actually happen if you were to run the code above. Normally you would
16516 * override this class or one of the default implementations, but you can
16517 * also override the methods you want on an instance of the class...
16519 * dd.onDragDrop = function(e, id) {
16520 * alert("dd was dropped on " + id);
16524 * @param {String} id of the element that is linked to this instance
16525 * @param {String} sGroup the group of related DragDrop objects
16526 * @param {object} config an object containing configurable attributes
16527 * Valid properties for DragDrop:
16528 * padding, isTarget, maintainOffset, primaryButtonOnly
16530 Roo.dd.DragDrop = function(id, sGroup, config) {
16532 this.init(id, sGroup, config);
16537 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16540 * The id of the element associated with this object. This is what we
16541 * refer to as the "linked element" because the size and position of
16542 * this element is used to determine when the drag and drop objects have
16550 * Configuration attributes passed into the constructor
16557 * The id of the element that will be dragged. By default this is same
16558 * as the linked element , but could be changed to another element. Ex:
16560 * @property dragElId
16567 * the id of the element that initiates the drag operation. By default
16568 * this is the linked element, but could be changed to be a child of this
16569 * element. This lets us do things like only starting the drag when the
16570 * header element within the linked html element is clicked.
16571 * @property handleElId
16578 * An associative array of HTML tags that will be ignored if clicked.
16579 * @property invalidHandleTypes
16580 * @type {string: string}
16582 invalidHandleTypes: null,
16585 * An associative array of ids for elements that will be ignored if clicked
16586 * @property invalidHandleIds
16587 * @type {string: string}
16589 invalidHandleIds: null,
16592 * An indexted array of css class names for elements that will be ignored
16594 * @property invalidHandleClasses
16597 invalidHandleClasses: null,
16600 * The linked element's absolute X position at the time the drag was
16602 * @property startPageX
16609 * The linked element's absolute X position at the time the drag was
16611 * @property startPageY
16618 * The group defines a logical collection of DragDrop objects that are
16619 * related. Instances only get events when interacting with other
16620 * DragDrop object in the same group. This lets us define multiple
16621 * groups using a single DragDrop subclass if we want.
16623 * @type {string: string}
16628 * Individual drag/drop instances can be locked. This will prevent
16629 * onmousedown start drag.
16637 * Lock this instance
16640 lock: function() { this.locked = true; },
16643 * Unlock this instace
16646 unlock: function() { this.locked = false; },
16649 * By default, all insances can be a drop target. This can be disabled by
16650 * setting isTarget to false.
16657 * The padding configured for this drag and drop object for calculating
16658 * the drop zone intersection with this object.
16665 * Cached reference to the linked element
16666 * @property _domRef
16672 * Internal typeof flag
16673 * @property __ygDragDrop
16676 __ygDragDrop: true,
16679 * Set to true when horizontal contraints are applied
16680 * @property constrainX
16687 * Set to true when vertical contraints are applied
16688 * @property constrainY
16695 * The left constraint
16703 * The right constraint
16711 * The up constraint
16720 * The down constraint
16728 * Maintain offsets when we resetconstraints. Set to true when you want
16729 * the position of the element relative to its parent to stay the same
16730 * when the page changes
16732 * @property maintainOffset
16735 maintainOffset: false,
16738 * Array of pixel locations the element will snap to if we specified a
16739 * horizontal graduation/interval. This array is generated automatically
16740 * when you define a tick interval.
16747 * Array of pixel locations the element will snap to if we specified a
16748 * vertical graduation/interval. This array is generated automatically
16749 * when you define a tick interval.
16756 * By default the drag and drop instance will only respond to the primary
16757 * button click (left button for a right-handed mouse). Set to true to
16758 * allow drag and drop to start with any mouse click that is propogated
16760 * @property primaryButtonOnly
16763 primaryButtonOnly: true,
16766 * The availabe property is false until the linked dom element is accessible.
16767 * @property available
16773 * By default, drags can only be initiated if the mousedown occurs in the
16774 * region the linked element is. This is done in part to work around a
16775 * bug in some browsers that mis-report the mousedown if the previous
16776 * mouseup happened outside of the window. This property is set to true
16777 * if outer handles are defined.
16779 * @property hasOuterHandles
16783 hasOuterHandles: false,
16786 * Code that executes immediately before the startDrag event
16787 * @method b4StartDrag
16790 b4StartDrag: function(x, y) { },
16793 * Abstract method called after a drag/drop object is clicked
16794 * and the drag or mousedown time thresholds have beeen met.
16795 * @method startDrag
16796 * @param {int} X click location
16797 * @param {int} Y click location
16799 startDrag: function(x, y) { /* override this */ },
16802 * Code that executes immediately before the onDrag event
16806 b4Drag: function(e) { },
16809 * Abstract method called during the onMouseMove event while dragging an
16812 * @param {Event} e the mousemove event
16814 onDrag: function(e) { /* override this */ },
16817 * Abstract method called when this element fist begins hovering over
16818 * another DragDrop obj
16819 * @method onDragEnter
16820 * @param {Event} e the mousemove event
16821 * @param {String|DragDrop[]} id In POINT mode, the element
16822 * id this is hovering over. In INTERSECT mode, an array of one or more
16823 * dragdrop items being hovered over.
16825 onDragEnter: function(e, id) { /* override this */ },
16828 * Code that executes immediately before the onDragOver event
16829 * @method b4DragOver
16832 b4DragOver: function(e) { },
16835 * Abstract method called when this element is hovering over another
16837 * @method onDragOver
16838 * @param {Event} e the mousemove event
16839 * @param {String|DragDrop[]} id In POINT mode, the element
16840 * id this is hovering over. In INTERSECT mode, an array of dd items
16841 * being hovered over.
16843 onDragOver: function(e, id) { /* override this */ },
16846 * Code that executes immediately before the onDragOut event
16847 * @method b4DragOut
16850 b4DragOut: function(e) { },
16853 * Abstract method called when we are no longer hovering over an element
16854 * @method onDragOut
16855 * @param {Event} e the mousemove event
16856 * @param {String|DragDrop[]} id In POINT mode, the element
16857 * id this was hovering over. In INTERSECT mode, an array of dd items
16858 * that the mouse is no longer over.
16860 onDragOut: function(e, id) { /* override this */ },
16863 * Code that executes immediately before the onDragDrop event
16864 * @method b4DragDrop
16867 b4DragDrop: function(e) { },
16870 * Abstract method called when this item is dropped on another DragDrop
16872 * @method onDragDrop
16873 * @param {Event} e the mouseup event
16874 * @param {String|DragDrop[]} id In POINT mode, the element
16875 * id this was dropped on. In INTERSECT mode, an array of dd items this
16878 onDragDrop: function(e, id) { /* override this */ },
16881 * Abstract method called when this item is dropped on an area with no
16883 * @method onInvalidDrop
16884 * @param {Event} e the mouseup event
16886 onInvalidDrop: function(e) { /* override this */ },
16889 * Code that executes immediately before the endDrag event
16890 * @method b4EndDrag
16893 b4EndDrag: function(e) { },
16896 * Fired when we are done dragging the object
16898 * @param {Event} e the mouseup event
16900 endDrag: function(e) { /* override this */ },
16903 * Code executed immediately before the onMouseDown event
16904 * @method b4MouseDown
16905 * @param {Event} e the mousedown event
16908 b4MouseDown: function(e) { },
16911 * Event handler that fires when a drag/drop obj gets a mousedown
16912 * @method onMouseDown
16913 * @param {Event} e the mousedown event
16915 onMouseDown: function(e) { /* override this */ },
16918 * Event handler that fires when a drag/drop obj gets a mouseup
16919 * @method onMouseUp
16920 * @param {Event} e the mouseup event
16922 onMouseUp: function(e) { /* override this */ },
16925 * Override the onAvailable method to do what is needed after the initial
16926 * position was determined.
16927 * @method onAvailable
16929 onAvailable: function () {
16933 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16936 defaultPadding : {left:0, right:0, top:0, bottom:0},
16939 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16943 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16944 { dragElId: "existingProxyDiv" });
16945 dd.startDrag = function(){
16946 this.constrainTo("parent-id");
16949 * Or you can initalize it using the {@link Roo.Element} object:
16951 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16952 startDrag : function(){
16953 this.constrainTo("parent-id");
16957 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16958 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16959 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16960 * an object containing the sides to pad. For example: {right:10, bottom:10}
16961 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16963 constrainTo : function(constrainTo, pad, inContent){
16964 if(typeof pad == "number"){
16965 pad = {left: pad, right:pad, top:pad, bottom:pad};
16967 pad = pad || this.defaultPadding;
16968 var b = Roo.get(this.getEl()).getBox();
16969 var ce = Roo.get(constrainTo);
16970 var s = ce.getScroll();
16971 var c, cd = ce.dom;
16972 if(cd == document.body){
16973 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16976 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16980 var topSpace = b.y - c.y;
16981 var leftSpace = b.x - c.x;
16983 this.resetConstraints();
16984 this.setXConstraint(leftSpace - (pad.left||0), // left
16985 c.width - leftSpace - b.width - (pad.right||0) //right
16987 this.setYConstraint(topSpace - (pad.top||0), //top
16988 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16993 * Returns a reference to the linked element
16995 * @return {HTMLElement} the html element
16997 getEl: function() {
16998 if (!this._domRef) {
16999 this._domRef = Roo.getDom(this.id);
17002 return this._domRef;
17006 * Returns a reference to the actual element to drag. By default this is
17007 * the same as the html element, but it can be assigned to another
17008 * element. An example of this can be found in Roo.dd.DDProxy
17009 * @method getDragEl
17010 * @return {HTMLElement} the html element
17012 getDragEl: function() {
17013 return Roo.getDom(this.dragElId);
17017 * Sets up the DragDrop object. Must be called in the constructor of any
17018 * Roo.dd.DragDrop subclass
17020 * @param id the id of the linked element
17021 * @param {String} sGroup the group of related items
17022 * @param {object} config configuration attributes
17024 init: function(id, sGroup, config) {
17025 this.initTarget(id, sGroup, config);
17026 if (!Roo.isTouch) {
17027 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17029 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17030 // Event.on(this.id, "selectstart", Event.preventDefault);
17034 * Initializes Targeting functionality only... the object does not
17035 * get a mousedown handler.
17036 * @method initTarget
17037 * @param id the id of the linked element
17038 * @param {String} sGroup the group of related items
17039 * @param {object} config configuration attributes
17041 initTarget: function(id, sGroup, config) {
17043 // configuration attributes
17044 this.config = config || {};
17046 // create a local reference to the drag and drop manager
17047 this.DDM = Roo.dd.DDM;
17048 // initialize the groups array
17051 // assume that we have an element reference instead of an id if the
17052 // parameter is not a string
17053 if (typeof id !== "string") {
17060 // add to an interaction group
17061 this.addToGroup((sGroup) ? sGroup : "default");
17063 // We don't want to register this as the handle with the manager
17064 // so we just set the id rather than calling the setter.
17065 this.handleElId = id;
17067 // the linked element is the element that gets dragged by default
17068 this.setDragElId(id);
17070 // by default, clicked anchors will not start drag operations.
17071 this.invalidHandleTypes = { A: "A" };
17072 this.invalidHandleIds = {};
17073 this.invalidHandleClasses = [];
17075 this.applyConfig();
17077 this.handleOnAvailable();
17081 * Applies the configuration parameters that were passed into the constructor.
17082 * This is supposed to happen at each level through the inheritance chain. So
17083 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17084 * DragDrop in order to get all of the parameters that are available in
17086 * @method applyConfig
17088 applyConfig: function() {
17090 // configurable properties:
17091 // padding, isTarget, maintainOffset, primaryButtonOnly
17092 this.padding = this.config.padding || [0, 0, 0, 0];
17093 this.isTarget = (this.config.isTarget !== false);
17094 this.maintainOffset = (this.config.maintainOffset);
17095 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17100 * Executed when the linked element is available
17101 * @method handleOnAvailable
17104 handleOnAvailable: function() {
17105 this.available = true;
17106 this.resetConstraints();
17107 this.onAvailable();
17111 * Configures the padding for the target zone in px. Effectively expands
17112 * (or reduces) the virtual object size for targeting calculations.
17113 * Supports css-style shorthand; if only one parameter is passed, all sides
17114 * will have that padding, and if only two are passed, the top and bottom
17115 * will have the first param, the left and right the second.
17116 * @method setPadding
17117 * @param {int} iTop Top pad
17118 * @param {int} iRight Right pad
17119 * @param {int} iBot Bot pad
17120 * @param {int} iLeft Left pad
17122 setPadding: function(iTop, iRight, iBot, iLeft) {
17123 // this.padding = [iLeft, iRight, iTop, iBot];
17124 if (!iRight && 0 !== iRight) {
17125 this.padding = [iTop, iTop, iTop, iTop];
17126 } else if (!iBot && 0 !== iBot) {
17127 this.padding = [iTop, iRight, iTop, iRight];
17129 this.padding = [iTop, iRight, iBot, iLeft];
17134 * Stores the initial placement of the linked element.
17135 * @method setInitialPosition
17136 * @param {int} diffX the X offset, default 0
17137 * @param {int} diffY the Y offset, default 0
17139 setInitPosition: function(diffX, diffY) {
17140 var el = this.getEl();
17142 if (!this.DDM.verifyEl(el)) {
17146 var dx = diffX || 0;
17147 var dy = diffY || 0;
17149 var p = Dom.getXY( el );
17151 this.initPageX = p[0] - dx;
17152 this.initPageY = p[1] - dy;
17154 this.lastPageX = p[0];
17155 this.lastPageY = p[1];
17158 this.setStartPosition(p);
17162 * Sets the start position of the element. This is set when the obj
17163 * is initialized, the reset when a drag is started.
17164 * @method setStartPosition
17165 * @param pos current position (from previous lookup)
17168 setStartPosition: function(pos) {
17169 var p = pos || Dom.getXY( this.getEl() );
17170 this.deltaSetXY = null;
17172 this.startPageX = p[0];
17173 this.startPageY = p[1];
17177 * Add this instance to a group of related drag/drop objects. All
17178 * instances belong to at least one group, and can belong to as many
17179 * groups as needed.
17180 * @method addToGroup
17181 * @param sGroup {string} the name of the group
17183 addToGroup: function(sGroup) {
17184 this.groups[sGroup] = true;
17185 this.DDM.regDragDrop(this, sGroup);
17189 * Remove's this instance from the supplied interaction group
17190 * @method removeFromGroup
17191 * @param {string} sGroup The group to drop
17193 removeFromGroup: function(sGroup) {
17194 if (this.groups[sGroup]) {
17195 delete this.groups[sGroup];
17198 this.DDM.removeDDFromGroup(this, sGroup);
17202 * Allows you to specify that an element other than the linked element
17203 * will be moved with the cursor during a drag
17204 * @method setDragElId
17205 * @param id {string} the id of the element that will be used to initiate the drag
17207 setDragElId: function(id) {
17208 this.dragElId = id;
17212 * Allows you to specify a child of the linked element that should be
17213 * used to initiate the drag operation. An example of this would be if
17214 * you have a content div with text and links. Clicking anywhere in the
17215 * content area would normally start the drag operation. Use this method
17216 * to specify that an element inside of the content div is the element
17217 * that starts the drag operation.
17218 * @method setHandleElId
17219 * @param id {string} the id of the element that will be used to
17220 * initiate the drag.
17222 setHandleElId: function(id) {
17223 if (typeof id !== "string") {
17226 this.handleElId = id;
17227 this.DDM.regHandle(this.id, id);
17231 * Allows you to set an element outside of the linked element as a drag
17233 * @method setOuterHandleElId
17234 * @param id the id of the element that will be used to initiate the drag
17236 setOuterHandleElId: function(id) {
17237 if (typeof id !== "string") {
17240 Event.on(id, "mousedown",
17241 this.handleMouseDown, this);
17242 this.setHandleElId(id);
17244 this.hasOuterHandles = true;
17248 * Remove all drag and drop hooks for this element
17251 unreg: function() {
17252 Event.un(this.id, "mousedown",
17253 this.handleMouseDown);
17254 Event.un(this.id, "touchstart",
17255 this.handleMouseDown);
17256 this._domRef = null;
17257 this.DDM._remove(this);
17260 destroy : function(){
17265 * Returns true if this instance is locked, or the drag drop mgr is locked
17266 * (meaning that all drag/drop is disabled on the page.)
17268 * @return {boolean} true if this obj or all drag/drop is locked, else
17271 isLocked: function() {
17272 return (this.DDM.isLocked() || this.locked);
17276 * Fired when this object is clicked
17277 * @method handleMouseDown
17279 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17282 handleMouseDown: function(e, oDD){
17284 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17285 //Roo.log('not touch/ button !=0');
17288 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17289 return; // double touch..
17293 if (this.isLocked()) {
17294 //Roo.log('locked');
17298 this.DDM.refreshCache(this.groups);
17299 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17300 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17301 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17302 //Roo.log('no outer handes or not over target');
17305 // Roo.log('check validator');
17306 if (this.clickValidator(e)) {
17307 // Roo.log('validate success');
17308 // set the initial element position
17309 this.setStartPosition();
17312 this.b4MouseDown(e);
17313 this.onMouseDown(e);
17315 this.DDM.handleMouseDown(e, this);
17317 this.DDM.stopEvent(e);
17325 clickValidator: function(e) {
17326 var target = e.getTarget();
17327 return ( this.isValidHandleChild(target) &&
17328 (this.id == this.handleElId ||
17329 this.DDM.handleWasClicked(target, this.id)) );
17333 * Allows you to specify a tag name that should not start a drag operation
17334 * when clicked. This is designed to facilitate embedding links within a
17335 * drag handle that do something other than start the drag.
17336 * @method addInvalidHandleType
17337 * @param {string} tagName the type of element to exclude
17339 addInvalidHandleType: function(tagName) {
17340 var type = tagName.toUpperCase();
17341 this.invalidHandleTypes[type] = type;
17345 * Lets you to specify an element id for a child of a drag handle
17346 * that should not initiate a drag
17347 * @method addInvalidHandleId
17348 * @param {string} id the element id of the element you wish to ignore
17350 addInvalidHandleId: function(id) {
17351 if (typeof id !== "string") {
17354 this.invalidHandleIds[id] = id;
17358 * Lets you specify a css class of elements that will not initiate a drag
17359 * @method addInvalidHandleClass
17360 * @param {string} cssClass the class of the elements you wish to ignore
17362 addInvalidHandleClass: function(cssClass) {
17363 this.invalidHandleClasses.push(cssClass);
17367 * Unsets an excluded tag name set by addInvalidHandleType
17368 * @method removeInvalidHandleType
17369 * @param {string} tagName the type of element to unexclude
17371 removeInvalidHandleType: function(tagName) {
17372 var type = tagName.toUpperCase();
17373 // this.invalidHandleTypes[type] = null;
17374 delete this.invalidHandleTypes[type];
17378 * Unsets an invalid handle id
17379 * @method removeInvalidHandleId
17380 * @param {string} id the id of the element to re-enable
17382 removeInvalidHandleId: function(id) {
17383 if (typeof id !== "string") {
17386 delete this.invalidHandleIds[id];
17390 * Unsets an invalid css class
17391 * @method removeInvalidHandleClass
17392 * @param {string} cssClass the class of the element(s) you wish to
17395 removeInvalidHandleClass: function(cssClass) {
17396 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17397 if (this.invalidHandleClasses[i] == cssClass) {
17398 delete this.invalidHandleClasses[i];
17404 * Checks the tag exclusion list to see if this click should be ignored
17405 * @method isValidHandleChild
17406 * @param {HTMLElement} node the HTMLElement to evaluate
17407 * @return {boolean} true if this is a valid tag type, false if not
17409 isValidHandleChild: function(node) {
17412 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17415 nodeName = node.nodeName.toUpperCase();
17417 nodeName = node.nodeName;
17419 valid = valid && !this.invalidHandleTypes[nodeName];
17420 valid = valid && !this.invalidHandleIds[node.id];
17422 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17423 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17432 * Create the array of horizontal tick marks if an interval was specified
17433 * in setXConstraint().
17434 * @method setXTicks
17437 setXTicks: function(iStartX, iTickSize) {
17439 this.xTickSize = iTickSize;
17443 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17445 this.xTicks[this.xTicks.length] = i;
17450 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17452 this.xTicks[this.xTicks.length] = i;
17457 this.xTicks.sort(this.DDM.numericSort) ;
17461 * Create the array of vertical tick marks if an interval was specified in
17462 * setYConstraint().
17463 * @method setYTicks
17466 setYTicks: function(iStartY, iTickSize) {
17468 this.yTickSize = iTickSize;
17472 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17474 this.yTicks[this.yTicks.length] = i;
17479 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17481 this.yTicks[this.yTicks.length] = i;
17486 this.yTicks.sort(this.DDM.numericSort) ;
17490 * By default, the element can be dragged any place on the screen. Use
17491 * this method to limit the horizontal travel of the element. Pass in
17492 * 0,0 for the parameters if you want to lock the drag to the y axis.
17493 * @method setXConstraint
17494 * @param {int} iLeft the number of pixels the element can move to the left
17495 * @param {int} iRight the number of pixels the element can move to the
17497 * @param {int} iTickSize optional parameter for specifying that the
17499 * should move iTickSize pixels at a time.
17501 setXConstraint: function(iLeft, iRight, iTickSize) {
17502 this.leftConstraint = iLeft;
17503 this.rightConstraint = iRight;
17505 this.minX = this.initPageX - iLeft;
17506 this.maxX = this.initPageX + iRight;
17507 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17509 this.constrainX = true;
17513 * Clears any constraints applied to this instance. Also clears ticks
17514 * since they can't exist independent of a constraint at this time.
17515 * @method clearConstraints
17517 clearConstraints: function() {
17518 this.constrainX = false;
17519 this.constrainY = false;
17524 * Clears any tick interval defined for this instance
17525 * @method clearTicks
17527 clearTicks: function() {
17528 this.xTicks = null;
17529 this.yTicks = null;
17530 this.xTickSize = 0;
17531 this.yTickSize = 0;
17535 * By default, the element can be dragged any place on the screen. Set
17536 * this to limit the vertical travel of the element. Pass in 0,0 for the
17537 * parameters if you want to lock the drag to the x axis.
17538 * @method setYConstraint
17539 * @param {int} iUp the number of pixels the element can move up
17540 * @param {int} iDown the number of pixels the element can move down
17541 * @param {int} iTickSize optional parameter for specifying that the
17542 * element should move iTickSize pixels at a time.
17544 setYConstraint: function(iUp, iDown, iTickSize) {
17545 this.topConstraint = iUp;
17546 this.bottomConstraint = iDown;
17548 this.minY = this.initPageY - iUp;
17549 this.maxY = this.initPageY + iDown;
17550 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17552 this.constrainY = true;
17557 * resetConstraints must be called if you manually reposition a dd element.
17558 * @method resetConstraints
17559 * @param {boolean} maintainOffset
17561 resetConstraints: function() {
17564 // Maintain offsets if necessary
17565 if (this.initPageX || this.initPageX === 0) {
17566 // figure out how much this thing has moved
17567 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17568 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17570 this.setInitPosition(dx, dy);
17572 // This is the first time we have detected the element's position
17574 this.setInitPosition();
17577 if (this.constrainX) {
17578 this.setXConstraint( this.leftConstraint,
17579 this.rightConstraint,
17583 if (this.constrainY) {
17584 this.setYConstraint( this.topConstraint,
17585 this.bottomConstraint,
17591 * Normally the drag element is moved pixel by pixel, but we can specify
17592 * that it move a number of pixels at a time. This method resolves the
17593 * location when we have it set up like this.
17595 * @param {int} val where we want to place the object
17596 * @param {int[]} tickArray sorted array of valid points
17597 * @return {int} the closest tick
17600 getTick: function(val, tickArray) {
17603 // If tick interval is not defined, it is effectively 1 pixel,
17604 // so we return the value passed to us.
17606 } else if (tickArray[0] >= val) {
17607 // The value is lower than the first tick, so we return the first
17609 return tickArray[0];
17611 for (var i=0, len=tickArray.length; i<len; ++i) {
17613 if (tickArray[next] && tickArray[next] >= val) {
17614 var diff1 = val - tickArray[i];
17615 var diff2 = tickArray[next] - val;
17616 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17620 // The value is larger than the last tick, so we return the last
17622 return tickArray[tickArray.length - 1];
17629 * @return {string} string representation of the dd obj
17631 toString: function() {
17632 return ("DragDrop " + this.id);
17640 * Ext JS Library 1.1.1
17641 * Copyright(c) 2006-2007, Ext JS, LLC.
17643 * Originally Released Under LGPL - original licence link has changed is not relivant.
17646 * <script type="text/javascript">
17651 * The drag and drop utility provides a framework for building drag and drop
17652 * applications. In addition to enabling drag and drop for specific elements,
17653 * the drag and drop elements are tracked by the manager class, and the
17654 * interactions between the various elements are tracked during the drag and
17655 * the implementing code is notified about these important moments.
17658 // Only load the library once. Rewriting the manager class would orphan
17659 // existing drag and drop instances.
17660 if (!Roo.dd.DragDropMgr) {
17663 * @class Roo.dd.DragDropMgr
17664 * DragDropMgr is a singleton that tracks the element interaction for
17665 * all DragDrop items in the window. Generally, you will not call
17666 * this class directly, but it does have helper methods that could
17667 * be useful in your DragDrop implementations.
17670 Roo.dd.DragDropMgr = function() {
17672 var Event = Roo.EventManager;
17677 * Two dimensional Array of registered DragDrop objects. The first
17678 * dimension is the DragDrop item group, the second the DragDrop
17681 * @type {string: string}
17688 * Array of element ids defined as drag handles. Used to determine
17689 * if the element that generated the mousedown event is actually the
17690 * handle and not the html element itself.
17691 * @property handleIds
17692 * @type {string: string}
17699 * the DragDrop object that is currently being dragged
17700 * @property dragCurrent
17708 * the DragDrop object(s) that are being hovered over
17709 * @property dragOvers
17717 * the X distance between the cursor and the object being dragged
17726 * the Y distance between the cursor and the object being dragged
17735 * Flag to determine if we should prevent the default behavior of the
17736 * events we define. By default this is true, but this can be set to
17737 * false if you need the default behavior (not recommended)
17738 * @property preventDefault
17742 preventDefault: true,
17745 * Flag to determine if we should stop the propagation of the events
17746 * we generate. This is true by default but you may want to set it to
17747 * false if the html element contains other features that require the
17749 * @property stopPropagation
17753 stopPropagation: true,
17756 * Internal flag that is set to true when drag and drop has been
17758 * @property initialized
17765 * All drag and drop can be disabled.
17773 * Called the first time an element is registered.
17779 this.initialized = true;
17783 * In point mode, drag and drop interaction is defined by the
17784 * location of the cursor during the drag/drop
17792 * In intersect mode, drag and drop interactio nis defined by the
17793 * overlap of two or more drag and drop objects.
17794 * @property INTERSECT
17801 * The current drag and drop mode. Default: POINT
17809 * Runs method on all drag and drop objects
17810 * @method _execOnAll
17814 _execOnAll: function(sMethod, args) {
17815 for (var i in this.ids) {
17816 for (var j in this.ids[i]) {
17817 var oDD = this.ids[i][j];
17818 if (! this.isTypeOfDD(oDD)) {
17821 oDD[sMethod].apply(oDD, args);
17827 * Drag and drop initialization. Sets up the global event handlers
17832 _onLoad: function() {
17836 if (!Roo.isTouch) {
17837 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17838 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17840 Event.on(document, "touchend", this.handleMouseUp, this, true);
17841 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17843 Event.on(window, "unload", this._onUnload, this, true);
17844 Event.on(window, "resize", this._onResize, this, true);
17845 // Event.on(window, "mouseout", this._test);
17850 * Reset constraints on all drag and drop objs
17851 * @method _onResize
17855 _onResize: function(e) {
17856 this._execOnAll("resetConstraints", []);
17860 * Lock all drag and drop functionality
17864 lock: function() { this.locked = true; },
17867 * Unlock all drag and drop functionality
17871 unlock: function() { this.locked = false; },
17874 * Is drag and drop locked?
17876 * @return {boolean} True if drag and drop is locked, false otherwise.
17879 isLocked: function() { return this.locked; },
17882 * Location cache that is set for all drag drop objects when a drag is
17883 * initiated, cleared when the drag is finished.
17884 * @property locationCache
17891 * Set useCache to false if you want to force object the lookup of each
17892 * drag and drop linked element constantly during a drag.
17893 * @property useCache
17900 * The number of pixels that the mouse needs to move after the
17901 * mousedown before the drag is initiated. Default=3;
17902 * @property clickPixelThresh
17906 clickPixelThresh: 3,
17909 * The number of milliseconds after the mousedown event to initiate the
17910 * drag if we don't get a mouseup event. Default=1000
17911 * @property clickTimeThresh
17915 clickTimeThresh: 350,
17918 * Flag that indicates that either the drag pixel threshold or the
17919 * mousdown time threshold has been met
17920 * @property dragThreshMet
17925 dragThreshMet: false,
17928 * Timeout used for the click time threshold
17929 * @property clickTimeout
17934 clickTimeout: null,
17937 * The X position of the mousedown event stored for later use when a
17938 * drag threshold is met.
17947 * The Y position of the mousedown event stored for later use when a
17948 * drag threshold is met.
17957 * Each DragDrop instance must be registered with the DragDropMgr.
17958 * This is executed in DragDrop.init()
17959 * @method regDragDrop
17960 * @param {DragDrop} oDD the DragDrop object to register
17961 * @param {String} sGroup the name of the group this element belongs to
17964 regDragDrop: function(oDD, sGroup) {
17965 if (!this.initialized) { this.init(); }
17967 if (!this.ids[sGroup]) {
17968 this.ids[sGroup] = {};
17970 this.ids[sGroup][oDD.id] = oDD;
17974 * Removes the supplied dd instance from the supplied group. Executed
17975 * by DragDrop.removeFromGroup, so don't call this function directly.
17976 * @method removeDDFromGroup
17980 removeDDFromGroup: function(oDD, sGroup) {
17981 if (!this.ids[sGroup]) {
17982 this.ids[sGroup] = {};
17985 var obj = this.ids[sGroup];
17986 if (obj && obj[oDD.id]) {
17987 delete obj[oDD.id];
17992 * Unregisters a drag and drop item. This is executed in
17993 * DragDrop.unreg, use that method instead of calling this directly.
17998 _remove: function(oDD) {
17999 for (var g in oDD.groups) {
18000 if (g && this.ids[g][oDD.id]) {
18001 delete this.ids[g][oDD.id];
18004 delete this.handleIds[oDD.id];
18008 * Each DragDrop handle element must be registered. This is done
18009 * automatically when executing DragDrop.setHandleElId()
18010 * @method regHandle
18011 * @param {String} sDDId the DragDrop id this element is a handle for
18012 * @param {String} sHandleId the id of the element that is the drag
18016 regHandle: function(sDDId, sHandleId) {
18017 if (!this.handleIds[sDDId]) {
18018 this.handleIds[sDDId] = {};
18020 this.handleIds[sDDId][sHandleId] = sHandleId;
18024 * Utility function to determine if a given element has been
18025 * registered as a drag drop item.
18026 * @method isDragDrop
18027 * @param {String} id the element id to check
18028 * @return {boolean} true if this element is a DragDrop item,
18032 isDragDrop: function(id) {
18033 return ( this.getDDById(id) ) ? true : false;
18037 * Returns the drag and drop instances that are in all groups the
18038 * passed in instance belongs to.
18039 * @method getRelated
18040 * @param {DragDrop} p_oDD the obj to get related data for
18041 * @param {boolean} bTargetsOnly if true, only return targetable objs
18042 * @return {DragDrop[]} the related instances
18045 getRelated: function(p_oDD, bTargetsOnly) {
18047 for (var i in p_oDD.groups) {
18048 for (j in this.ids[i]) {
18049 var dd = this.ids[i][j];
18050 if (! this.isTypeOfDD(dd)) {
18053 if (!bTargetsOnly || dd.isTarget) {
18054 oDDs[oDDs.length] = dd;
18063 * Returns true if the specified dd target is a legal target for
18064 * the specifice drag obj
18065 * @method isLegalTarget
18066 * @param {DragDrop} the drag obj
18067 * @param {DragDrop} the target
18068 * @return {boolean} true if the target is a legal target for the
18072 isLegalTarget: function (oDD, oTargetDD) {
18073 var targets = this.getRelated(oDD, true);
18074 for (var i=0, len=targets.length;i<len;++i) {
18075 if (targets[i].id == oTargetDD.id) {
18084 * My goal is to be able to transparently determine if an object is
18085 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18086 * returns "object", oDD.constructor.toString() always returns
18087 * "DragDrop" and not the name of the subclass. So for now it just
18088 * evaluates a well-known variable in DragDrop.
18089 * @method isTypeOfDD
18090 * @param {Object} the object to evaluate
18091 * @return {boolean} true if typeof oDD = DragDrop
18094 isTypeOfDD: function (oDD) {
18095 return (oDD && oDD.__ygDragDrop);
18099 * Utility function to determine if a given element has been
18100 * registered as a drag drop handle for the given Drag Drop object.
18102 * @param {String} id the element id to check
18103 * @return {boolean} true if this element is a DragDrop handle, false
18107 isHandle: function(sDDId, sHandleId) {
18108 return ( this.handleIds[sDDId] &&
18109 this.handleIds[sDDId][sHandleId] );
18113 * Returns the DragDrop instance for a given id
18114 * @method getDDById
18115 * @param {String} id the id of the DragDrop object
18116 * @return {DragDrop} the drag drop object, null if it is not found
18119 getDDById: function(id) {
18120 for (var i in this.ids) {
18121 if (this.ids[i][id]) {
18122 return this.ids[i][id];
18129 * Fired after a registered DragDrop object gets the mousedown event.
18130 * Sets up the events required to track the object being dragged
18131 * @method handleMouseDown
18132 * @param {Event} e the event
18133 * @param oDD the DragDrop object being dragged
18137 handleMouseDown: function(e, oDD) {
18139 Roo.QuickTips.disable();
18141 this.currentTarget = e.getTarget();
18143 this.dragCurrent = oDD;
18145 var el = oDD.getEl();
18147 // track start position
18148 this.startX = e.getPageX();
18149 this.startY = e.getPageY();
18151 this.deltaX = this.startX - el.offsetLeft;
18152 this.deltaY = this.startY - el.offsetTop;
18154 this.dragThreshMet = false;
18156 this.clickTimeout = setTimeout(
18158 var DDM = Roo.dd.DDM;
18159 DDM.startDrag(DDM.startX, DDM.startY);
18161 this.clickTimeThresh );
18165 * Fired when either the drag pixel threshol or the mousedown hold
18166 * time threshold has been met.
18167 * @method startDrag
18168 * @param x {int} the X position of the original mousedown
18169 * @param y {int} the Y position of the original mousedown
18172 startDrag: function(x, y) {
18173 clearTimeout(this.clickTimeout);
18174 if (this.dragCurrent) {
18175 this.dragCurrent.b4StartDrag(x, y);
18176 this.dragCurrent.startDrag(x, y);
18178 this.dragThreshMet = true;
18182 * Internal function to handle the mouseup event. Will be invoked
18183 * from the context of the document.
18184 * @method handleMouseUp
18185 * @param {Event} e the event
18189 handleMouseUp: function(e) {
18192 Roo.QuickTips.enable();
18194 if (! this.dragCurrent) {
18198 clearTimeout(this.clickTimeout);
18200 if (this.dragThreshMet) {
18201 this.fireEvents(e, true);
18211 * Utility to stop event propagation and event default, if these
18212 * features are turned on.
18213 * @method stopEvent
18214 * @param {Event} e the event as returned by this.getEvent()
18217 stopEvent: function(e){
18218 if(this.stopPropagation) {
18219 e.stopPropagation();
18222 if (this.preventDefault) {
18223 e.preventDefault();
18228 * Internal function to clean up event handlers after the drag
18229 * operation is complete
18231 * @param {Event} e the event
18235 stopDrag: function(e) {
18236 // Fire the drag end event for the item that was dragged
18237 if (this.dragCurrent) {
18238 if (this.dragThreshMet) {
18239 this.dragCurrent.b4EndDrag(e);
18240 this.dragCurrent.endDrag(e);
18243 this.dragCurrent.onMouseUp(e);
18246 this.dragCurrent = null;
18247 this.dragOvers = {};
18251 * Internal function to handle the mousemove event. Will be invoked
18252 * from the context of the html element.
18254 * @TODO figure out what we can do about mouse events lost when the
18255 * user drags objects beyond the window boundary. Currently we can
18256 * detect this in internet explorer by verifying that the mouse is
18257 * down during the mousemove event. Firefox doesn't give us the
18258 * button state on the mousemove event.
18259 * @method handleMouseMove
18260 * @param {Event} e the event
18264 handleMouseMove: function(e) {
18265 if (! this.dragCurrent) {
18269 // var button = e.which || e.button;
18271 // check for IE mouseup outside of page boundary
18272 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18274 return this.handleMouseUp(e);
18277 if (!this.dragThreshMet) {
18278 var diffX = Math.abs(this.startX - e.getPageX());
18279 var diffY = Math.abs(this.startY - e.getPageY());
18280 if (diffX > this.clickPixelThresh ||
18281 diffY > this.clickPixelThresh) {
18282 this.startDrag(this.startX, this.startY);
18286 if (this.dragThreshMet) {
18287 this.dragCurrent.b4Drag(e);
18288 this.dragCurrent.onDrag(e);
18289 if(!this.dragCurrent.moveOnly){
18290 this.fireEvents(e, false);
18300 * Iterates over all of the DragDrop elements to find ones we are
18301 * hovering over or dropping on
18302 * @method fireEvents
18303 * @param {Event} e the event
18304 * @param {boolean} isDrop is this a drop op or a mouseover op?
18308 fireEvents: function(e, isDrop) {
18309 var dc = this.dragCurrent;
18311 // If the user did the mouse up outside of the window, we could
18312 // get here even though we have ended the drag.
18313 if (!dc || dc.isLocked()) {
18317 var pt = e.getPoint();
18319 // cache the previous dragOver array
18325 var enterEvts = [];
18327 // Check to see if the object(s) we were hovering over is no longer
18328 // being hovered over so we can fire the onDragOut event
18329 for (var i in this.dragOvers) {
18331 var ddo = this.dragOvers[i];
18333 if (! this.isTypeOfDD(ddo)) {
18337 if (! this.isOverTarget(pt, ddo, this.mode)) {
18338 outEvts.push( ddo );
18341 oldOvers[i] = true;
18342 delete this.dragOvers[i];
18345 for (var sGroup in dc.groups) {
18347 if ("string" != typeof sGroup) {
18351 for (i in this.ids[sGroup]) {
18352 var oDD = this.ids[sGroup][i];
18353 if (! this.isTypeOfDD(oDD)) {
18357 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18358 if (this.isOverTarget(pt, oDD, this.mode)) {
18359 // look for drop interactions
18361 dropEvts.push( oDD );
18362 // look for drag enter and drag over interactions
18365 // initial drag over: dragEnter fires
18366 if (!oldOvers[oDD.id]) {
18367 enterEvts.push( oDD );
18368 // subsequent drag overs: dragOver fires
18370 overEvts.push( oDD );
18373 this.dragOvers[oDD.id] = oDD;
18381 if (outEvts.length) {
18382 dc.b4DragOut(e, outEvts);
18383 dc.onDragOut(e, outEvts);
18386 if (enterEvts.length) {
18387 dc.onDragEnter(e, enterEvts);
18390 if (overEvts.length) {
18391 dc.b4DragOver(e, overEvts);
18392 dc.onDragOver(e, overEvts);
18395 if (dropEvts.length) {
18396 dc.b4DragDrop(e, dropEvts);
18397 dc.onDragDrop(e, dropEvts);
18401 // fire dragout events
18403 for (i=0, len=outEvts.length; i<len; ++i) {
18404 dc.b4DragOut(e, outEvts[i].id);
18405 dc.onDragOut(e, outEvts[i].id);
18408 // fire enter events
18409 for (i=0,len=enterEvts.length; i<len; ++i) {
18410 // dc.b4DragEnter(e, oDD.id);
18411 dc.onDragEnter(e, enterEvts[i].id);
18414 // fire over events
18415 for (i=0,len=overEvts.length; i<len; ++i) {
18416 dc.b4DragOver(e, overEvts[i].id);
18417 dc.onDragOver(e, overEvts[i].id);
18420 // fire drop events
18421 for (i=0, len=dropEvts.length; i<len; ++i) {
18422 dc.b4DragDrop(e, dropEvts[i].id);
18423 dc.onDragDrop(e, dropEvts[i].id);
18428 // notify about a drop that did not find a target
18429 if (isDrop && !dropEvts.length) {
18430 dc.onInvalidDrop(e);
18436 * Helper function for getting the best match from the list of drag
18437 * and drop objects returned by the drag and drop events when we are
18438 * in INTERSECT mode. It returns either the first object that the
18439 * cursor is over, or the object that has the greatest overlap with
18440 * the dragged element.
18441 * @method getBestMatch
18442 * @param {DragDrop[]} dds The array of drag and drop objects
18444 * @return {DragDrop} The best single match
18447 getBestMatch: function(dds) {
18449 // Return null if the input is not what we expect
18450 //if (!dds || !dds.length || dds.length == 0) {
18452 // If there is only one item, it wins
18453 //} else if (dds.length == 1) {
18455 var len = dds.length;
18460 // Loop through the targeted items
18461 for (var i=0; i<len; ++i) {
18463 // If the cursor is over the object, it wins. If the
18464 // cursor is over multiple matches, the first one we come
18466 if (dd.cursorIsOver) {
18469 // Otherwise the object with the most overlap wins
18472 winner.overlap.getArea() < dd.overlap.getArea()) {
18483 * Refreshes the cache of the top-left and bottom-right points of the
18484 * drag and drop objects in the specified group(s). This is in the
18485 * format that is stored in the drag and drop instance, so typical
18488 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18492 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18494 * @TODO this really should be an indexed array. Alternatively this
18495 * method could accept both.
18496 * @method refreshCache
18497 * @param {Object} groups an associative array of groups to refresh
18500 refreshCache: function(groups) {
18501 for (var sGroup in groups) {
18502 if ("string" != typeof sGroup) {
18505 for (var i in this.ids[sGroup]) {
18506 var oDD = this.ids[sGroup][i];
18508 if (this.isTypeOfDD(oDD)) {
18509 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18510 var loc = this.getLocation(oDD);
18512 this.locationCache[oDD.id] = loc;
18514 delete this.locationCache[oDD.id];
18515 // this will unregister the drag and drop object if
18516 // the element is not in a usable state
18525 * This checks to make sure an element exists and is in the DOM. The
18526 * main purpose is to handle cases where innerHTML is used to remove
18527 * drag and drop objects from the DOM. IE provides an 'unspecified
18528 * error' when trying to access the offsetParent of such an element
18530 * @param {HTMLElement} el the element to check
18531 * @return {boolean} true if the element looks usable
18534 verifyEl: function(el) {
18539 parent = el.offsetParent;
18542 parent = el.offsetParent;
18553 * Returns a Region object containing the drag and drop element's position
18554 * and size, including the padding configured for it
18555 * @method getLocation
18556 * @param {DragDrop} oDD the drag and drop object to get the
18558 * @return {Roo.lib.Region} a Region object representing the total area
18559 * the element occupies, including any padding
18560 * the instance is configured for.
18563 getLocation: function(oDD) {
18564 if (! this.isTypeOfDD(oDD)) {
18568 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18571 pos= Roo.lib.Dom.getXY(el);
18579 x2 = x1 + el.offsetWidth;
18581 y2 = y1 + el.offsetHeight;
18583 t = y1 - oDD.padding[0];
18584 r = x2 + oDD.padding[1];
18585 b = y2 + oDD.padding[2];
18586 l = x1 - oDD.padding[3];
18588 return new Roo.lib.Region( t, r, b, l );
18592 * Checks the cursor location to see if it over the target
18593 * @method isOverTarget
18594 * @param {Roo.lib.Point} pt The point to evaluate
18595 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18596 * @return {boolean} true if the mouse is over the target
18600 isOverTarget: function(pt, oTarget, intersect) {
18601 // use cache if available
18602 var loc = this.locationCache[oTarget.id];
18603 if (!loc || !this.useCache) {
18604 loc = this.getLocation(oTarget);
18605 this.locationCache[oTarget.id] = loc;
18613 oTarget.cursorIsOver = loc.contains( pt );
18615 // DragDrop is using this as a sanity check for the initial mousedown
18616 // in this case we are done. In POINT mode, if the drag obj has no
18617 // contraints, we are also done. Otherwise we need to evaluate the
18618 // location of the target as related to the actual location of the
18619 // dragged element.
18620 var dc = this.dragCurrent;
18621 if (!dc || !dc.getTargetCoord ||
18622 (!intersect && !dc.constrainX && !dc.constrainY)) {
18623 return oTarget.cursorIsOver;
18626 oTarget.overlap = null;
18628 // Get the current location of the drag element, this is the
18629 // location of the mouse event less the delta that represents
18630 // where the original mousedown happened on the element. We
18631 // need to consider constraints and ticks as well.
18632 var pos = dc.getTargetCoord(pt.x, pt.y);
18634 var el = dc.getDragEl();
18635 var curRegion = new Roo.lib.Region( pos.y,
18636 pos.x + el.offsetWidth,
18637 pos.y + el.offsetHeight,
18640 var overlap = curRegion.intersect(loc);
18643 oTarget.overlap = overlap;
18644 return (intersect) ? true : oTarget.cursorIsOver;
18651 * unload event handler
18652 * @method _onUnload
18656 _onUnload: function(e, me) {
18657 Roo.dd.DragDropMgr.unregAll();
18661 * Cleans up the drag and drop events and objects.
18666 unregAll: function() {
18668 if (this.dragCurrent) {
18670 this.dragCurrent = null;
18673 this._execOnAll("unreg", []);
18675 for (i in this.elementCache) {
18676 delete this.elementCache[i];
18679 this.elementCache = {};
18684 * A cache of DOM elements
18685 * @property elementCache
18692 * Get the wrapper for the DOM element specified
18693 * @method getElWrapper
18694 * @param {String} id the id of the element to get
18695 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18697 * @deprecated This wrapper isn't that useful
18700 getElWrapper: function(id) {
18701 var oWrapper = this.elementCache[id];
18702 if (!oWrapper || !oWrapper.el) {
18703 oWrapper = this.elementCache[id] =
18704 new this.ElementWrapper(Roo.getDom(id));
18710 * Returns the actual DOM element
18711 * @method getElement
18712 * @param {String} id the id of the elment to get
18713 * @return {Object} The element
18714 * @deprecated use Roo.getDom instead
18717 getElement: function(id) {
18718 return Roo.getDom(id);
18722 * Returns the style property for the DOM element (i.e.,
18723 * document.getElById(id).style)
18725 * @param {String} id the id of the elment to get
18726 * @return {Object} The style property of the element
18727 * @deprecated use Roo.getDom instead
18730 getCss: function(id) {
18731 var el = Roo.getDom(id);
18732 return (el) ? el.style : null;
18736 * Inner class for cached elements
18737 * @class DragDropMgr.ElementWrapper
18742 ElementWrapper: function(el) {
18747 this.el = el || null;
18752 this.id = this.el && el.id;
18754 * A reference to the style property
18757 this.css = this.el && el.style;
18761 * Returns the X position of an html element
18763 * @param el the element for which to get the position
18764 * @return {int} the X coordinate
18766 * @deprecated use Roo.lib.Dom.getX instead
18769 getPosX: function(el) {
18770 return Roo.lib.Dom.getX(el);
18774 * Returns the Y position of an html element
18776 * @param el the element for which to get the position
18777 * @return {int} the Y coordinate
18778 * @deprecated use Roo.lib.Dom.getY instead
18781 getPosY: function(el) {
18782 return Roo.lib.Dom.getY(el);
18786 * Swap two nodes. In IE, we use the native method, for others we
18787 * emulate the IE behavior
18789 * @param n1 the first node to swap
18790 * @param n2 the other node to swap
18793 swapNode: function(n1, n2) {
18797 var p = n2.parentNode;
18798 var s = n2.nextSibling;
18801 p.insertBefore(n1, n2);
18802 } else if (n2 == n1.nextSibling) {
18803 p.insertBefore(n2, n1);
18805 n1.parentNode.replaceChild(n2, n1);
18806 p.insertBefore(n1, s);
18812 * Returns the current scroll position
18813 * @method getScroll
18817 getScroll: function () {
18818 var t, l, dde=document.documentElement, db=document.body;
18819 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18821 l = dde.scrollLeft;
18828 return { top: t, left: l };
18832 * Returns the specified element style property
18834 * @param {HTMLElement} el the element
18835 * @param {string} styleProp the style property
18836 * @return {string} The value of the style property
18837 * @deprecated use Roo.lib.Dom.getStyle
18840 getStyle: function(el, styleProp) {
18841 return Roo.fly(el).getStyle(styleProp);
18845 * Gets the scrollTop
18846 * @method getScrollTop
18847 * @return {int} the document's scrollTop
18850 getScrollTop: function () { return this.getScroll().top; },
18853 * Gets the scrollLeft
18854 * @method getScrollLeft
18855 * @return {int} the document's scrollTop
18858 getScrollLeft: function () { return this.getScroll().left; },
18861 * Sets the x/y position of an element to the location of the
18864 * @param {HTMLElement} moveEl The element to move
18865 * @param {HTMLElement} targetEl The position reference element
18868 moveToEl: function (moveEl, targetEl) {
18869 var aCoord = Roo.lib.Dom.getXY(targetEl);
18870 Roo.lib.Dom.setXY(moveEl, aCoord);
18874 * Numeric array sort function
18875 * @method numericSort
18878 numericSort: function(a, b) { return (a - b); },
18882 * @property _timeoutCount
18889 * Trying to make the load order less important. Without this we get
18890 * an error if this file is loaded before the Event Utility.
18891 * @method _addListeners
18895 _addListeners: function() {
18896 var DDM = Roo.dd.DDM;
18897 if ( Roo.lib.Event && document ) {
18900 if (DDM._timeoutCount > 2000) {
18902 setTimeout(DDM._addListeners, 10);
18903 if (document && document.body) {
18904 DDM._timeoutCount += 1;
18911 * Recursively searches the immediate parent and all child nodes for
18912 * the handle element in order to determine wheter or not it was
18914 * @method handleWasClicked
18915 * @param node the html element to inspect
18918 handleWasClicked: function(node, id) {
18919 if (this.isHandle(id, node.id)) {
18922 // check to see if this is a text node child of the one we want
18923 var p = node.parentNode;
18926 if (this.isHandle(id, p.id)) {
18941 // shorter alias, save a few bytes
18942 Roo.dd.DDM = Roo.dd.DragDropMgr;
18943 Roo.dd.DDM._addListeners();
18947 * Ext JS Library 1.1.1
18948 * Copyright(c) 2006-2007, Ext JS, LLC.
18950 * Originally Released Under LGPL - original licence link has changed is not relivant.
18953 * <script type="text/javascript">
18958 * A DragDrop implementation where the linked element follows the
18959 * mouse cursor during a drag.
18960 * @extends Roo.dd.DragDrop
18962 * @param {String} id the id of the linked element
18963 * @param {String} sGroup the group of related DragDrop items
18964 * @param {object} config an object containing configurable attributes
18965 * Valid properties for DD:
18968 Roo.dd.DD = function(id, sGroup, config) {
18970 this.init(id, sGroup, config);
18974 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18977 * When set to true, the utility automatically tries to scroll the browser
18978 * window wehn a drag and drop element is dragged near the viewport boundary.
18979 * Defaults to true.
18986 * Sets the pointer offset to the distance between the linked element's top
18987 * left corner and the location the element was clicked
18988 * @method autoOffset
18989 * @param {int} iPageX the X coordinate of the click
18990 * @param {int} iPageY the Y coordinate of the click
18992 autoOffset: function(iPageX, iPageY) {
18993 var x = iPageX - this.startPageX;
18994 var y = iPageY - this.startPageY;
18995 this.setDelta(x, y);
18999 * Sets the pointer offset. You can call this directly to force the
19000 * offset to be in a particular location (e.g., pass in 0,0 to set it
19001 * to the center of the object)
19003 * @param {int} iDeltaX the distance from the left
19004 * @param {int} iDeltaY the distance from the top
19006 setDelta: function(iDeltaX, iDeltaY) {
19007 this.deltaX = iDeltaX;
19008 this.deltaY = iDeltaY;
19012 * Sets the drag element to the location of the mousedown or click event,
19013 * maintaining the cursor location relative to the location on the element
19014 * that was clicked. Override this if you want to place the element in a
19015 * location other than where the cursor is.
19016 * @method setDragElPos
19017 * @param {int} iPageX the X coordinate of the mousedown or drag event
19018 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19020 setDragElPos: function(iPageX, iPageY) {
19021 // the first time we do this, we are going to check to make sure
19022 // the element has css positioning
19024 var el = this.getDragEl();
19025 this.alignElWithMouse(el, iPageX, iPageY);
19029 * Sets the element to the location of the mousedown or click event,
19030 * maintaining the cursor location relative to the location on the element
19031 * that was clicked. Override this if you want to place the element in a
19032 * location other than where the cursor is.
19033 * @method alignElWithMouse
19034 * @param {HTMLElement} el the element to move
19035 * @param {int} iPageX the X coordinate of the mousedown or drag event
19036 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19038 alignElWithMouse: function(el, iPageX, iPageY) {
19039 var oCoord = this.getTargetCoord(iPageX, iPageY);
19040 var fly = el.dom ? el : Roo.fly(el);
19041 if (!this.deltaSetXY) {
19042 var aCoord = [oCoord.x, oCoord.y];
19044 var newLeft = fly.getLeft(true);
19045 var newTop = fly.getTop(true);
19046 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19048 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19051 this.cachePosition(oCoord.x, oCoord.y);
19052 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19057 * Saves the most recent position so that we can reset the constraints and
19058 * tick marks on-demand. We need to know this so that we can calculate the
19059 * number of pixels the element is offset from its original position.
19060 * @method cachePosition
19061 * @param iPageX the current x position (optional, this just makes it so we
19062 * don't have to look it up again)
19063 * @param iPageY the current y position (optional, this just makes it so we
19064 * don't have to look it up again)
19066 cachePosition: function(iPageX, iPageY) {
19068 this.lastPageX = iPageX;
19069 this.lastPageY = iPageY;
19071 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19072 this.lastPageX = aCoord[0];
19073 this.lastPageY = aCoord[1];
19078 * Auto-scroll the window if the dragged object has been moved beyond the
19079 * visible window boundary.
19080 * @method autoScroll
19081 * @param {int} x the drag element's x position
19082 * @param {int} y the drag element's y position
19083 * @param {int} h the height of the drag element
19084 * @param {int} w the width of the drag element
19087 autoScroll: function(x, y, h, w) {
19090 // The client height
19091 var clientH = Roo.lib.Dom.getViewWidth();
19093 // The client width
19094 var clientW = Roo.lib.Dom.getViewHeight();
19096 // The amt scrolled down
19097 var st = this.DDM.getScrollTop();
19099 // The amt scrolled right
19100 var sl = this.DDM.getScrollLeft();
19102 // Location of the bottom of the element
19105 // Location of the right of the element
19108 // The distance from the cursor to the bottom of the visible area,
19109 // adjusted so that we don't scroll if the cursor is beyond the
19110 // element drag constraints
19111 var toBot = (clientH + st - y - this.deltaY);
19113 // The distance from the cursor to the right of the visible area
19114 var toRight = (clientW + sl - x - this.deltaX);
19117 // How close to the edge the cursor must be before we scroll
19118 // var thresh = (document.all) ? 100 : 40;
19121 // How many pixels to scroll per autoscroll op. This helps to reduce
19122 // clunky scrolling. IE is more sensitive about this ... it needs this
19123 // value to be higher.
19124 var scrAmt = (document.all) ? 80 : 30;
19126 // Scroll down if we are near the bottom of the visible page and the
19127 // obj extends below the crease
19128 if ( bot > clientH && toBot < thresh ) {
19129 window.scrollTo(sl, st + scrAmt);
19132 // Scroll up if the window is scrolled down and the top of the object
19133 // goes above the top border
19134 if ( y < st && st > 0 && y - st < thresh ) {
19135 window.scrollTo(sl, st - scrAmt);
19138 // Scroll right if the obj is beyond the right border and the cursor is
19139 // near the border.
19140 if ( right > clientW && toRight < thresh ) {
19141 window.scrollTo(sl + scrAmt, st);
19144 // Scroll left if the window has been scrolled to the right and the obj
19145 // extends past the left border
19146 if ( x < sl && sl > 0 && x - sl < thresh ) {
19147 window.scrollTo(sl - scrAmt, st);
19153 * Finds the location the element should be placed if we want to move
19154 * it to where the mouse location less the click offset would place us.
19155 * @method getTargetCoord
19156 * @param {int} iPageX the X coordinate of the click
19157 * @param {int} iPageY the Y coordinate of the click
19158 * @return an object that contains the coordinates (Object.x and Object.y)
19161 getTargetCoord: function(iPageX, iPageY) {
19164 var x = iPageX - this.deltaX;
19165 var y = iPageY - this.deltaY;
19167 if (this.constrainX) {
19168 if (x < this.minX) { x = this.minX; }
19169 if (x > this.maxX) { x = this.maxX; }
19172 if (this.constrainY) {
19173 if (y < this.minY) { y = this.minY; }
19174 if (y > this.maxY) { y = this.maxY; }
19177 x = this.getTick(x, this.xTicks);
19178 y = this.getTick(y, this.yTicks);
19185 * Sets up config options specific to this class. Overrides
19186 * Roo.dd.DragDrop, but all versions of this method through the
19187 * inheritance chain are called
19189 applyConfig: function() {
19190 Roo.dd.DD.superclass.applyConfig.call(this);
19191 this.scroll = (this.config.scroll !== false);
19195 * Event that fires prior to the onMouseDown event. Overrides
19198 b4MouseDown: function(e) {
19199 // this.resetConstraints();
19200 this.autoOffset(e.getPageX(),
19205 * Event that fires prior to the onDrag event. Overrides
19208 b4Drag: function(e) {
19209 this.setDragElPos(e.getPageX(),
19213 toString: function() {
19214 return ("DD " + this.id);
19217 //////////////////////////////////////////////////////////////////////////
19218 // Debugging ygDragDrop events that can be overridden
19219 //////////////////////////////////////////////////////////////////////////
19221 startDrag: function(x, y) {
19224 onDrag: function(e) {
19227 onDragEnter: function(e, id) {
19230 onDragOver: function(e, id) {
19233 onDragOut: function(e, id) {
19236 onDragDrop: function(e, id) {
19239 endDrag: function(e) {
19246 * Ext JS Library 1.1.1
19247 * Copyright(c) 2006-2007, Ext JS, LLC.
19249 * Originally Released Under LGPL - original licence link has changed is not relivant.
19252 * <script type="text/javascript">
19256 * @class Roo.dd.DDProxy
19257 * A DragDrop implementation that inserts an empty, bordered div into
19258 * the document that follows the cursor during drag operations. At the time of
19259 * the click, the frame div is resized to the dimensions of the linked html
19260 * element, and moved to the exact location of the linked element.
19262 * References to the "frame" element refer to the single proxy element that
19263 * was created to be dragged in place of all DDProxy elements on the
19266 * @extends Roo.dd.DD
19268 * @param {String} id the id of the linked html element
19269 * @param {String} sGroup the group of related DragDrop objects
19270 * @param {object} config an object containing configurable attributes
19271 * Valid properties for DDProxy in addition to those in DragDrop:
19272 * resizeFrame, centerFrame, dragElId
19274 Roo.dd.DDProxy = function(id, sGroup, config) {
19276 this.init(id, sGroup, config);
19282 * The default drag frame div id
19283 * @property Roo.dd.DDProxy.dragElId
19287 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19289 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19292 * By default we resize the drag frame to be the same size as the element
19293 * we want to drag (this is to get the frame effect). We can turn it off
19294 * if we want a different behavior.
19295 * @property resizeFrame
19301 * By default the frame is positioned exactly where the drag element is, so
19302 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19303 * you do not have constraints on the obj is to have the drag frame centered
19304 * around the cursor. Set centerFrame to true for this effect.
19305 * @property centerFrame
19308 centerFrame: false,
19311 * Creates the proxy element if it does not yet exist
19312 * @method createFrame
19314 createFrame: function() {
19316 var body = document.body;
19318 if (!body || !body.firstChild) {
19319 setTimeout( function() { self.createFrame(); }, 50 );
19323 var div = this.getDragEl();
19326 div = document.createElement("div");
19327 div.id = this.dragElId;
19330 s.position = "absolute";
19331 s.visibility = "hidden";
19333 s.border = "2px solid #aaa";
19336 // appendChild can blow up IE if invoked prior to the window load event
19337 // while rendering a table. It is possible there are other scenarios
19338 // that would cause this to happen as well.
19339 body.insertBefore(div, body.firstChild);
19344 * Initialization for the drag frame element. Must be called in the
19345 * constructor of all subclasses
19346 * @method initFrame
19348 initFrame: function() {
19349 this.createFrame();
19352 applyConfig: function() {
19353 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19355 this.resizeFrame = (this.config.resizeFrame !== false);
19356 this.centerFrame = (this.config.centerFrame);
19357 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19361 * Resizes the drag frame to the dimensions of the clicked object, positions
19362 * it over the object, and finally displays it
19363 * @method showFrame
19364 * @param {int} iPageX X click position
19365 * @param {int} iPageY Y click position
19368 showFrame: function(iPageX, iPageY) {
19369 var el = this.getEl();
19370 var dragEl = this.getDragEl();
19371 var s = dragEl.style;
19373 this._resizeProxy();
19375 if (this.centerFrame) {
19376 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19377 Math.round(parseInt(s.height, 10)/2) );
19380 this.setDragElPos(iPageX, iPageY);
19382 Roo.fly(dragEl).show();
19386 * The proxy is automatically resized to the dimensions of the linked
19387 * element when a drag is initiated, unless resizeFrame is set to false
19388 * @method _resizeProxy
19391 _resizeProxy: function() {
19392 if (this.resizeFrame) {
19393 var el = this.getEl();
19394 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19398 // overrides Roo.dd.DragDrop
19399 b4MouseDown: function(e) {
19400 var x = e.getPageX();
19401 var y = e.getPageY();
19402 this.autoOffset(x, y);
19403 this.setDragElPos(x, y);
19406 // overrides Roo.dd.DragDrop
19407 b4StartDrag: function(x, y) {
19408 // show the drag frame
19409 this.showFrame(x, y);
19412 // overrides Roo.dd.DragDrop
19413 b4EndDrag: function(e) {
19414 Roo.fly(this.getDragEl()).hide();
19417 // overrides Roo.dd.DragDrop
19418 // By default we try to move the element to the last location of the frame.
19419 // This is so that the default behavior mirrors that of Roo.dd.DD.
19420 endDrag: function(e) {
19422 var lel = this.getEl();
19423 var del = this.getDragEl();
19425 // Show the drag frame briefly so we can get its position
19426 del.style.visibility = "";
19429 // Hide the linked element before the move to get around a Safari
19431 lel.style.visibility = "hidden";
19432 Roo.dd.DDM.moveToEl(lel, del);
19433 del.style.visibility = "hidden";
19434 lel.style.visibility = "";
19439 beforeMove : function(){
19443 afterDrag : function(){
19447 toString: function() {
19448 return ("DDProxy " + this.id);
19454 * Ext JS Library 1.1.1
19455 * Copyright(c) 2006-2007, Ext JS, LLC.
19457 * Originally Released Under LGPL - original licence link has changed is not relivant.
19460 * <script type="text/javascript">
19464 * @class Roo.dd.DDTarget
19465 * A DragDrop implementation that does not move, but can be a drop
19466 * target. You would get the same result by simply omitting implementation
19467 * for the event callbacks, but this way we reduce the processing cost of the
19468 * event listener and the callbacks.
19469 * @extends Roo.dd.DragDrop
19471 * @param {String} id the id of the element that is a drop target
19472 * @param {String} sGroup the group of related DragDrop objects
19473 * @param {object} config an object containing configurable attributes
19474 * Valid properties for DDTarget in addition to those in
19478 Roo.dd.DDTarget = function(id, sGroup, config) {
19480 this.initTarget(id, sGroup, config);
19482 if (config.listeners || config.events) {
19483 Roo.dd.DragDrop.superclass.constructor.call(this, {
19484 listeners : config.listeners || {},
19485 events : config.events || {}
19490 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19491 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19492 toString: function() {
19493 return ("DDTarget " + this.id);
19498 * Ext JS Library 1.1.1
19499 * Copyright(c) 2006-2007, Ext JS, LLC.
19501 * Originally Released Under LGPL - original licence link has changed is not relivant.
19504 * <script type="text/javascript">
19509 * @class Roo.dd.ScrollManager
19510 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19511 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19514 Roo.dd.ScrollManager = function(){
19515 var ddm = Roo.dd.DragDropMgr;
19522 var onStop = function(e){
19527 var triggerRefresh = function(){
19528 if(ddm.dragCurrent){
19529 ddm.refreshCache(ddm.dragCurrent.groups);
19533 var doScroll = function(){
19534 if(ddm.dragCurrent){
19535 var dds = Roo.dd.ScrollManager;
19537 if(proc.el.scroll(proc.dir, dds.increment)){
19541 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19546 var clearProc = function(){
19548 clearInterval(proc.id);
19555 var startProc = function(el, dir){
19556 Roo.log('scroll startproc');
19560 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19563 var onFire = function(e, isDrop){
19565 if(isDrop || !ddm.dragCurrent){ return; }
19566 var dds = Roo.dd.ScrollManager;
19567 if(!dragEl || dragEl != ddm.dragCurrent){
19568 dragEl = ddm.dragCurrent;
19569 // refresh regions on drag start
19570 dds.refreshCache();
19573 var xy = Roo.lib.Event.getXY(e);
19574 var pt = new Roo.lib.Point(xy[0], xy[1]);
19575 for(var id in els){
19576 var el = els[id], r = el._region;
19577 if(r && r.contains(pt) && el.isScrollable()){
19578 if(r.bottom - pt.y <= dds.thresh){
19580 startProc(el, "down");
19583 }else if(r.right - pt.x <= dds.thresh){
19585 startProc(el, "left");
19588 }else if(pt.y - r.top <= dds.thresh){
19590 startProc(el, "up");
19593 }else if(pt.x - r.left <= dds.thresh){
19595 startProc(el, "right");
19604 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19605 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19609 * Registers new overflow element(s) to auto scroll
19610 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19612 register : function(el){
19613 if(el instanceof Array){
19614 for(var i = 0, len = el.length; i < len; i++) {
19615 this.register(el[i]);
19621 Roo.dd.ScrollManager.els = els;
19625 * Unregisters overflow element(s) so they are no longer scrolled
19626 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19628 unregister : function(el){
19629 if(el instanceof Array){
19630 for(var i = 0, len = el.length; i < len; i++) {
19631 this.unregister(el[i]);
19640 * The number of pixels from the edge of a container the pointer needs to be to
19641 * trigger scrolling (defaults to 25)
19647 * The number of pixels to scroll in each scroll increment (defaults to 50)
19653 * The frequency of scrolls in milliseconds (defaults to 500)
19659 * True to animate the scroll (defaults to true)
19665 * The animation duration in seconds -
19666 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19672 * Manually trigger a cache refresh.
19674 refreshCache : function(){
19675 for(var id in els){
19676 if(typeof els[id] == 'object'){ // for people extending the object prototype
19677 els[id]._region = els[id].getRegion();
19684 * Ext JS Library 1.1.1
19685 * Copyright(c) 2006-2007, Ext JS, LLC.
19687 * Originally Released Under LGPL - original licence link has changed is not relivant.
19690 * <script type="text/javascript">
19695 * @class Roo.dd.Registry
19696 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19697 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19700 Roo.dd.Registry = function(){
19703 var autoIdSeed = 0;
19705 var getId = function(el, autogen){
19706 if(typeof el == "string"){
19710 if(!id && autogen !== false){
19711 id = "roodd-" + (++autoIdSeed);
19719 * Register a drag drop element
19720 * @param {String|HTMLElement} element The id or DOM node to register
19721 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19722 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19723 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19724 * populated in the data object (if applicable):
19726 Value Description<br />
19727 --------- ------------------------------------------<br />
19728 handles Array of DOM nodes that trigger dragging<br />
19729 for the element being registered<br />
19730 isHandle True if the element passed in triggers<br />
19731 dragging itself, else false
19734 register : function(el, data){
19736 if(typeof el == "string"){
19737 el = document.getElementById(el);
19740 elements[getId(el)] = data;
19741 if(data.isHandle !== false){
19742 handles[data.ddel.id] = data;
19745 var hs = data.handles;
19746 for(var i = 0, len = hs.length; i < len; i++){
19747 handles[getId(hs[i])] = data;
19753 * Unregister a drag drop element
19754 * @param {String|HTMLElement} element The id or DOM node to unregister
19756 unregister : function(el){
19757 var id = getId(el, false);
19758 var data = elements[id];
19760 delete elements[id];
19762 var hs = data.handles;
19763 for(var i = 0, len = hs.length; i < len; i++){
19764 delete handles[getId(hs[i], false)];
19771 * Returns the handle registered for a DOM Node by id
19772 * @param {String|HTMLElement} id The DOM node or id to look up
19773 * @return {Object} handle The custom handle data
19775 getHandle : function(id){
19776 if(typeof id != "string"){ // must be element?
19779 return handles[id];
19783 * Returns the handle that is registered for the DOM node that is the target of the event
19784 * @param {Event} e The event
19785 * @return {Object} handle The custom handle data
19787 getHandleFromEvent : function(e){
19788 var t = Roo.lib.Event.getTarget(e);
19789 return t ? handles[t.id] : null;
19793 * Returns a custom data object that is registered for a DOM node by id
19794 * @param {String|HTMLElement} id The DOM node or id to look up
19795 * @return {Object} data The custom data
19797 getTarget : function(id){
19798 if(typeof id != "string"){ // must be element?
19801 return elements[id];
19805 * Returns a custom data object that is registered for the DOM node that is the target of the event
19806 * @param {Event} e The event
19807 * @return {Object} data The custom data
19809 getTargetFromEvent : function(e){
19810 var t = Roo.lib.Event.getTarget(e);
19811 return t ? elements[t.id] || handles[t.id] : null;
19816 * Ext JS Library 1.1.1
19817 * Copyright(c) 2006-2007, Ext JS, LLC.
19819 * Originally Released Under LGPL - original licence link has changed is not relivant.
19822 * <script type="text/javascript">
19827 * @class Roo.dd.StatusProxy
19828 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19829 * default drag proxy used by all Roo.dd components.
19831 * @param {Object} config
19833 Roo.dd.StatusProxy = function(config){
19834 Roo.apply(this, config);
19835 this.id = this.id || Roo.id();
19836 this.el = new Roo.Layer({
19838 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19839 {tag: "div", cls: "x-dd-drop-icon"},
19840 {tag: "div", cls: "x-dd-drag-ghost"}
19843 shadow: !config || config.shadow !== false
19845 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19846 this.dropStatus = this.dropNotAllowed;
19849 Roo.dd.StatusProxy.prototype = {
19851 * @cfg {String} dropAllowed
19852 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19854 dropAllowed : "x-dd-drop-ok",
19856 * @cfg {String} dropNotAllowed
19857 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19859 dropNotAllowed : "x-dd-drop-nodrop",
19862 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19863 * over the current target element.
19864 * @param {String} cssClass The css class for the new drop status indicator image
19866 setStatus : function(cssClass){
19867 cssClass = cssClass || this.dropNotAllowed;
19868 if(this.dropStatus != cssClass){
19869 this.el.replaceClass(this.dropStatus, cssClass);
19870 this.dropStatus = cssClass;
19875 * Resets the status indicator to the default dropNotAllowed value
19876 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19878 reset : function(clearGhost){
19879 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19880 this.dropStatus = this.dropNotAllowed;
19882 this.ghost.update("");
19887 * Updates the contents of the ghost element
19888 * @param {String} html The html that will replace the current innerHTML of the ghost element
19890 update : function(html){
19891 if(typeof html == "string"){
19892 this.ghost.update(html);
19894 this.ghost.update("");
19895 html.style.margin = "0";
19896 this.ghost.dom.appendChild(html);
19898 // ensure float = none set?? cant remember why though.
19899 var el = this.ghost.dom.firstChild;
19901 Roo.fly(el).setStyle('float', 'none');
19906 * Returns the underlying proxy {@link Roo.Layer}
19907 * @return {Roo.Layer} el
19909 getEl : function(){
19914 * Returns the ghost element
19915 * @return {Roo.Element} el
19917 getGhost : function(){
19923 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19925 hide : function(clear){
19933 * Stops the repair animation if it's currently running
19936 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19942 * Displays this proxy
19949 * Force the Layer to sync its shadow and shim positions to the element
19956 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19957 * invalid drop operation by the item being dragged.
19958 * @param {Array} xy The XY position of the element ([x, y])
19959 * @param {Function} callback The function to call after the repair is complete
19960 * @param {Object} scope The scope in which to execute the callback
19962 repair : function(xy, callback, scope){
19963 this.callback = callback;
19964 this.scope = scope;
19965 if(xy && this.animRepair !== false){
19966 this.el.addClass("x-dd-drag-repair");
19967 this.el.hideUnders(true);
19968 this.anim = this.el.shift({
19969 duration: this.repairDuration || .5,
19973 callback: this.afterRepair,
19977 this.afterRepair();
19982 afterRepair : function(){
19984 if(typeof this.callback == "function"){
19985 this.callback.call(this.scope || this);
19987 this.callback = null;
19992 * Ext JS Library 1.1.1
19993 * Copyright(c) 2006-2007, Ext JS, LLC.
19995 * Originally Released Under LGPL - original licence link has changed is not relivant.
19998 * <script type="text/javascript">
20002 * @class Roo.dd.DragSource
20003 * @extends Roo.dd.DDProxy
20004 * A simple class that provides the basic implementation needed to make any element draggable.
20006 * @param {String/HTMLElement/Element} el The container element
20007 * @param {Object} config
20009 Roo.dd.DragSource = function(el, config){
20010 this.el = Roo.get(el);
20011 this.dragData = {};
20013 Roo.apply(this, config);
20016 this.proxy = new Roo.dd.StatusProxy();
20019 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20020 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20022 this.dragging = false;
20025 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20027 * @cfg {String} dropAllowed
20028 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20030 dropAllowed : "x-dd-drop-ok",
20032 * @cfg {String} dropNotAllowed
20033 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20035 dropNotAllowed : "x-dd-drop-nodrop",
20038 * Returns the data object associated with this drag source
20039 * @return {Object} data An object containing arbitrary data
20041 getDragData : function(e){
20042 return this.dragData;
20046 onDragEnter : function(e, id){
20047 var target = Roo.dd.DragDropMgr.getDDById(id);
20048 this.cachedTarget = target;
20049 if(this.beforeDragEnter(target, e, id) !== false){
20050 if(target.isNotifyTarget){
20051 var status = target.notifyEnter(this, e, this.dragData);
20052 this.proxy.setStatus(status);
20054 this.proxy.setStatus(this.dropAllowed);
20057 if(this.afterDragEnter){
20059 * An empty function by default, but provided so that you can perform a custom action
20060 * when the dragged item enters the drop target by providing an implementation.
20061 * @param {Roo.dd.DragDrop} target The drop target
20062 * @param {Event} e The event object
20063 * @param {String} id The id of the dragged element
20064 * @method afterDragEnter
20066 this.afterDragEnter(target, e, id);
20072 * An empty function by default, but provided so that you can perform a custom action
20073 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20074 * @param {Roo.dd.DragDrop} target The drop target
20075 * @param {Event} e The event object
20076 * @param {String} id The id of the dragged element
20077 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20079 beforeDragEnter : function(target, e, id){
20084 alignElWithMouse: function() {
20085 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20090 onDragOver : function(e, id){
20091 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20092 if(this.beforeDragOver(target, e, id) !== false){
20093 if(target.isNotifyTarget){
20094 var status = target.notifyOver(this, e, this.dragData);
20095 this.proxy.setStatus(status);
20098 if(this.afterDragOver){
20100 * An empty function by default, but provided so that you can perform a custom action
20101 * while the dragged item is over the drop target by providing an implementation.
20102 * @param {Roo.dd.DragDrop} target The drop target
20103 * @param {Event} e The event object
20104 * @param {String} id The id of the dragged element
20105 * @method afterDragOver
20107 this.afterDragOver(target, e, id);
20113 * An empty function by default, but provided so that you can perform a custom action
20114 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20115 * @param {Roo.dd.DragDrop} target The drop target
20116 * @param {Event} e The event object
20117 * @param {String} id The id of the dragged element
20118 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20120 beforeDragOver : function(target, e, id){
20125 onDragOut : function(e, id){
20126 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20127 if(this.beforeDragOut(target, e, id) !== false){
20128 if(target.isNotifyTarget){
20129 target.notifyOut(this, e, this.dragData);
20131 this.proxy.reset();
20132 if(this.afterDragOut){
20134 * An empty function by default, but provided so that you can perform a custom action
20135 * after the dragged item is dragged out of the target without dropping.
20136 * @param {Roo.dd.DragDrop} target The drop target
20137 * @param {Event} e The event object
20138 * @param {String} id The id of the dragged element
20139 * @method afterDragOut
20141 this.afterDragOut(target, e, id);
20144 this.cachedTarget = null;
20148 * An empty function by default, but provided so that you can perform a custom action before the dragged
20149 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20150 * @param {Roo.dd.DragDrop} target The drop target
20151 * @param {Event} e The event object
20152 * @param {String} id The id of the dragged element
20153 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20155 beforeDragOut : function(target, e, id){
20160 onDragDrop : function(e, id){
20161 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20162 if(this.beforeDragDrop(target, e, id) !== false){
20163 if(target.isNotifyTarget){
20164 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20165 this.onValidDrop(target, e, id);
20167 this.onInvalidDrop(target, e, id);
20170 this.onValidDrop(target, e, id);
20173 if(this.afterDragDrop){
20175 * An empty function by default, but provided so that you can perform a custom action
20176 * after a valid drag drop has occurred by providing an implementation.
20177 * @param {Roo.dd.DragDrop} target The drop target
20178 * @param {Event} e The event object
20179 * @param {String} id The id of the dropped element
20180 * @method afterDragDrop
20182 this.afterDragDrop(target, e, id);
20185 delete this.cachedTarget;
20189 * An empty function by default, but provided so that you can perform a custom action before the dragged
20190 * item is dropped onto the target and optionally cancel the onDragDrop.
20191 * @param {Roo.dd.DragDrop} target The drop target
20192 * @param {Event} e The event object
20193 * @param {String} id The id of the dragged element
20194 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20196 beforeDragDrop : function(target, e, id){
20201 onValidDrop : function(target, e, id){
20203 if(this.afterValidDrop){
20205 * An empty function by default, but provided so that you can perform a custom action
20206 * after a valid drop has occurred by providing an implementation.
20207 * @param {Object} target The target DD
20208 * @param {Event} e The event object
20209 * @param {String} id The id of the dropped element
20210 * @method afterInvalidDrop
20212 this.afterValidDrop(target, e, id);
20217 getRepairXY : function(e, data){
20218 return this.el.getXY();
20222 onInvalidDrop : function(target, e, id){
20223 this.beforeInvalidDrop(target, e, id);
20224 if(this.cachedTarget){
20225 if(this.cachedTarget.isNotifyTarget){
20226 this.cachedTarget.notifyOut(this, e, this.dragData);
20228 this.cacheTarget = null;
20230 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20232 if(this.afterInvalidDrop){
20234 * An empty function by default, but provided so that you can perform a custom action
20235 * after an invalid drop has occurred by providing an implementation.
20236 * @param {Event} e The event object
20237 * @param {String} id The id of the dropped element
20238 * @method afterInvalidDrop
20240 this.afterInvalidDrop(e, id);
20245 afterRepair : function(){
20247 this.el.highlight(this.hlColor || "c3daf9");
20249 this.dragging = false;
20253 * An empty function by default, but provided so that you can perform a custom action after an invalid
20254 * drop has occurred.
20255 * @param {Roo.dd.DragDrop} target The drop target
20256 * @param {Event} e The event object
20257 * @param {String} id The id of the dragged element
20258 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20260 beforeInvalidDrop : function(target, e, id){
20265 handleMouseDown : function(e){
20266 if(this.dragging) {
20269 var data = this.getDragData(e);
20270 if(data && this.onBeforeDrag(data, e) !== false){
20271 this.dragData = data;
20273 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20278 * An empty function by default, but provided so that you can perform a custom action before the initial
20279 * drag event begins and optionally cancel it.
20280 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20281 * @param {Event} e The event object
20282 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20284 onBeforeDrag : function(data, e){
20289 * An empty function by default, but provided so that you can perform a custom action once the initial
20290 * drag event has begun. The drag cannot be canceled from this function.
20291 * @param {Number} x The x position of the click on the dragged object
20292 * @param {Number} y The y position of the click on the dragged object
20294 onStartDrag : Roo.emptyFn,
20296 // private - YUI override
20297 startDrag : function(x, y){
20298 this.proxy.reset();
20299 this.dragging = true;
20300 this.proxy.update("");
20301 this.onInitDrag(x, y);
20306 onInitDrag : function(x, y){
20307 var clone = this.el.dom.cloneNode(true);
20308 clone.id = Roo.id(); // prevent duplicate ids
20309 this.proxy.update(clone);
20310 this.onStartDrag(x, y);
20315 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20316 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20318 getProxy : function(){
20323 * Hides the drag source's {@link Roo.dd.StatusProxy}
20325 hideProxy : function(){
20327 this.proxy.reset(true);
20328 this.dragging = false;
20332 triggerCacheRefresh : function(){
20333 Roo.dd.DDM.refreshCache(this.groups);
20336 // private - override to prevent hiding
20337 b4EndDrag: function(e) {
20340 // private - override to prevent moving
20341 endDrag : function(e){
20342 this.onEndDrag(this.dragData, e);
20346 onEndDrag : function(data, e){
20349 // private - pin to cursor
20350 autoOffset : function(x, y) {
20351 this.setDelta(-12, -20);
20355 * Ext JS Library 1.1.1
20356 * Copyright(c) 2006-2007, Ext JS, LLC.
20358 * Originally Released Under LGPL - original licence link has changed is not relivant.
20361 * <script type="text/javascript">
20366 * @class Roo.dd.DropTarget
20367 * @extends Roo.dd.DDTarget
20368 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20369 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20371 * @param {String/HTMLElement/Element} el The container element
20372 * @param {Object} config
20374 Roo.dd.DropTarget = function(el, config){
20375 this.el = Roo.get(el);
20377 var listeners = false; ;
20378 if (config && config.listeners) {
20379 listeners= config.listeners;
20380 delete config.listeners;
20382 Roo.apply(this, config);
20384 if(this.containerScroll){
20385 Roo.dd.ScrollManager.register(this.el);
20389 * @scope Roo.dd.DropTarget
20394 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20395 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20396 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20398 * IMPORTANT : it should set this.overClass and this.dropAllowed
20400 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20401 * @param {Event} e The event
20402 * @param {Object} data An object containing arbitrary data supplied by the drag source
20408 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20409 * This method will be called on every mouse movement while the drag source is over the drop target.
20410 * This default implementation simply returns the dropAllowed config value.
20412 * IMPORTANT : it should set this.dropAllowed
20414 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20415 * @param {Event} e The event
20416 * @param {Object} data An object containing arbitrary data supplied by the drag source
20422 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20423 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20424 * overClass (if any) from the drop element.
20426 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20427 * @param {Event} e The event
20428 * @param {Object} data An object containing arbitrary data supplied by the drag source
20434 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20435 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20436 * implementation that does something to process the drop event and returns true so that the drag source's
20437 * repair action does not run.
20439 * IMPORTANT : it should set this.success
20441 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20442 * @param {Event} e The event
20443 * @param {Object} data An object containing arbitrary data supplied by the drag source
20449 Roo.dd.DropTarget.superclass.constructor.call( this,
20451 this.ddGroup || this.group,
20454 listeners : listeners || {}
20462 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20464 * @cfg {String} overClass
20465 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20468 * @cfg {String} ddGroup
20469 * The drag drop group to handle drop events for
20473 * @cfg {String} dropAllowed
20474 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20476 dropAllowed : "x-dd-drop-ok",
20478 * @cfg {String} dropNotAllowed
20479 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20481 dropNotAllowed : "x-dd-drop-nodrop",
20483 * @cfg {boolean} success
20484 * set this after drop listener..
20488 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20489 * if the drop point is valid for over/enter..
20496 isNotifyTarget : true,
20501 notifyEnter : function(dd, e, data)
20504 this.fireEvent('enter', dd, e, data);
20505 if(this.overClass){
20506 this.el.addClass(this.overClass);
20508 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20509 this.valid ? this.dropAllowed : this.dropNotAllowed
20516 notifyOver : function(dd, e, data)
20519 this.fireEvent('over', dd, e, data);
20520 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20521 this.valid ? this.dropAllowed : this.dropNotAllowed
20528 notifyOut : function(dd, e, data)
20530 this.fireEvent('out', dd, e, data);
20531 if(this.overClass){
20532 this.el.removeClass(this.overClass);
20539 notifyDrop : function(dd, e, data)
20541 this.success = false;
20542 this.fireEvent('drop', dd, e, data);
20543 return this.success;
20547 * Ext JS Library 1.1.1
20548 * Copyright(c) 2006-2007, Ext JS, LLC.
20550 * Originally Released Under LGPL - original licence link has changed is not relivant.
20553 * <script type="text/javascript">
20558 * @class Roo.dd.DragZone
20559 * @extends Roo.dd.DragSource
20560 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20561 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20563 * @param {String/HTMLElement/Element} el The container element
20564 * @param {Object} config
20566 Roo.dd.DragZone = function(el, config){
20567 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20568 if(this.containerScroll){
20569 Roo.dd.ScrollManager.register(this.el);
20573 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20575 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20576 * for auto scrolling during drag operations.
20579 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20580 * method after a failed drop (defaults to "c3daf9" - light blue)
20584 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20585 * for a valid target to drag based on the mouse down. Override this method
20586 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20587 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20588 * @param {EventObject} e The mouse down event
20589 * @return {Object} The dragData
20591 getDragData : function(e){
20592 return Roo.dd.Registry.getHandleFromEvent(e);
20596 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20597 * this.dragData.ddel
20598 * @param {Number} x The x position of the click on the dragged object
20599 * @param {Number} y The y position of the click on the dragged object
20600 * @return {Boolean} true to continue the drag, false to cancel
20602 onInitDrag : function(x, y){
20603 this.proxy.update(this.dragData.ddel.cloneNode(true));
20604 this.onStartDrag(x, y);
20609 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20611 afterRepair : function(){
20613 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20615 this.dragging = false;
20619 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20620 * the XY of this.dragData.ddel
20621 * @param {EventObject} e The mouse up event
20622 * @return {Array} The xy location (e.g. [100, 200])
20624 getRepairXY : function(e){
20625 return Roo.Element.fly(this.dragData.ddel).getXY();
20629 * Ext JS Library 1.1.1
20630 * Copyright(c) 2006-2007, Ext JS, LLC.
20632 * Originally Released Under LGPL - original licence link has changed is not relivant.
20635 * <script type="text/javascript">
20638 * @class Roo.dd.DropZone
20639 * @extends Roo.dd.DropTarget
20640 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20641 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20643 * @param {String/HTMLElement/Element} el The container element
20644 * @param {Object} config
20646 Roo.dd.DropZone = function(el, config){
20647 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20650 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20652 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20653 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20654 * provide your own custom lookup.
20655 * @param {Event} e The event
20656 * @return {Object} data The custom data
20658 getTargetFromEvent : function(e){
20659 return Roo.dd.Registry.getTargetFromEvent(e);
20663 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20664 * that it has registered. This method has no default implementation and should be overridden to provide
20665 * node-specific processing if necessary.
20666 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20667 * {@link #getTargetFromEvent} for this node)
20668 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20669 * @param {Event} e The event
20670 * @param {Object} data An object containing arbitrary data supplied by the drag source
20672 onNodeEnter : function(n, dd, e, data){
20677 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20678 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20679 * overridden to provide the proper feedback.
20680 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20681 * {@link #getTargetFromEvent} for this node)
20682 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20683 * @param {Event} e The event
20684 * @param {Object} data An object containing arbitrary data supplied by the drag source
20685 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20686 * underlying {@link Roo.dd.StatusProxy} can be updated
20688 onNodeOver : function(n, dd, e, data){
20689 return this.dropAllowed;
20693 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20694 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20695 * node-specific processing if necessary.
20696 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20697 * {@link #getTargetFromEvent} for this node)
20698 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20699 * @param {Event} e The event
20700 * @param {Object} data An object containing arbitrary data supplied by the drag source
20702 onNodeOut : function(n, dd, e, data){
20707 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20708 * the drop node. The default implementation returns false, so it should be overridden to provide the
20709 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20710 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20711 * {@link #getTargetFromEvent} for this node)
20712 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20713 * @param {Event} e The event
20714 * @param {Object} data An object containing arbitrary data supplied by the drag source
20715 * @return {Boolean} True if the drop was valid, else false
20717 onNodeDrop : function(n, dd, e, data){
20722 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20723 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20724 * it should be overridden to provide the proper feedback if necessary.
20725 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20726 * @param {Event} e The event
20727 * @param {Object} data An object containing arbitrary data supplied by the drag source
20728 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20729 * underlying {@link Roo.dd.StatusProxy} can be updated
20731 onContainerOver : function(dd, e, data){
20732 return this.dropNotAllowed;
20736 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20737 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20738 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20739 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20740 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20741 * @param {Event} e The event
20742 * @param {Object} data An object containing arbitrary data supplied by the drag source
20743 * @return {Boolean} True if the drop was valid, else false
20745 onContainerDrop : function(dd, e, data){
20750 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20751 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20752 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20753 * you should override this method and provide a custom implementation.
20754 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20755 * @param {Event} e The event
20756 * @param {Object} data An object containing arbitrary data supplied by the drag source
20757 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20758 * underlying {@link Roo.dd.StatusProxy} can be updated
20760 notifyEnter : function(dd, e, data){
20761 return this.dropNotAllowed;
20765 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20766 * This method will be called on every mouse movement while the drag source is over the drop zone.
20767 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20768 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20769 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20770 * registered node, it will call {@link #onContainerOver}.
20771 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20772 * @param {Event} e The event
20773 * @param {Object} data An object containing arbitrary data supplied by the drag source
20774 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20775 * underlying {@link Roo.dd.StatusProxy} can be updated
20777 notifyOver : function(dd, e, data){
20778 var n = this.getTargetFromEvent(e);
20779 if(!n){ // not over valid drop target
20780 if(this.lastOverNode){
20781 this.onNodeOut(this.lastOverNode, dd, e, data);
20782 this.lastOverNode = null;
20784 return this.onContainerOver(dd, e, data);
20786 if(this.lastOverNode != n){
20787 if(this.lastOverNode){
20788 this.onNodeOut(this.lastOverNode, dd, e, data);
20790 this.onNodeEnter(n, dd, e, data);
20791 this.lastOverNode = n;
20793 return this.onNodeOver(n, dd, e, data);
20797 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20798 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20799 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20800 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20801 * @param {Event} e The event
20802 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20804 notifyOut : function(dd, e, data){
20805 if(this.lastOverNode){
20806 this.onNodeOut(this.lastOverNode, dd, e, data);
20807 this.lastOverNode = null;
20812 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20813 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20814 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20815 * otherwise it will call {@link #onContainerDrop}.
20816 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20817 * @param {Event} e The event
20818 * @param {Object} data An object containing arbitrary data supplied by the drag source
20819 * @return {Boolean} True if the drop was valid, else false
20821 notifyDrop : function(dd, e, data){
20822 if(this.lastOverNode){
20823 this.onNodeOut(this.lastOverNode, dd, e, data);
20824 this.lastOverNode = null;
20826 var n = this.getTargetFromEvent(e);
20828 this.onNodeDrop(n, dd, e, data) :
20829 this.onContainerDrop(dd, e, data);
20833 triggerCacheRefresh : function(){
20834 Roo.dd.DDM.refreshCache(this.groups);
20838 * Ext JS Library 1.1.1
20839 * Copyright(c) 2006-2007, Ext JS, LLC.
20841 * Originally Released Under LGPL - original licence link has changed is not relivant.
20844 * <script type="text/javascript">
20849 * @class Roo.data.SortTypes
20851 * Defines the default sorting (casting?) comparison functions used when sorting data.
20853 Roo.data.SortTypes = {
20855 * Default sort that does nothing
20856 * @param {Mixed} s The value being converted
20857 * @return {Mixed} The comparison value
20859 none : function(s){
20864 * The regular expression used to strip tags
20868 stripTagsRE : /<\/?[^>]+>/gi,
20871 * Strips all HTML tags to sort on text only
20872 * @param {Mixed} s The value being converted
20873 * @return {String} The comparison value
20875 asText : function(s){
20876 return String(s).replace(this.stripTagsRE, "");
20880 * Strips all HTML tags to sort on text only - Case insensitive
20881 * @param {Mixed} s The value being converted
20882 * @return {String} The comparison value
20884 asUCText : function(s){
20885 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20889 * Case insensitive string
20890 * @param {Mixed} s The value being converted
20891 * @return {String} The comparison value
20893 asUCString : function(s) {
20894 return String(s).toUpperCase();
20899 * @param {Mixed} s The value being converted
20900 * @return {Number} The comparison value
20902 asDate : function(s) {
20906 if(s instanceof Date){
20907 return s.getTime();
20909 return Date.parse(String(s));
20914 * @param {Mixed} s The value being converted
20915 * @return {Float} The comparison value
20917 asFloat : function(s) {
20918 var val = parseFloat(String(s).replace(/,/g, ""));
20919 if(isNaN(val)) val = 0;
20925 * @param {Mixed} s The value being converted
20926 * @return {Number} The comparison value
20928 asInt : function(s) {
20929 var val = parseInt(String(s).replace(/,/g, ""));
20930 if(isNaN(val)) val = 0;
20935 * Ext JS Library 1.1.1
20936 * Copyright(c) 2006-2007, Ext JS, LLC.
20938 * Originally Released Under LGPL - original licence link has changed is not relivant.
20941 * <script type="text/javascript">
20945 * @class Roo.data.Record
20946 * Instances of this class encapsulate both record <em>definition</em> information, and record
20947 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20948 * to access Records cached in an {@link Roo.data.Store} object.<br>
20950 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20951 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20954 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20956 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20957 * {@link #create}. The parameters are the same.
20958 * @param {Array} data An associative Array of data values keyed by the field name.
20959 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20960 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20961 * not specified an integer id is generated.
20963 Roo.data.Record = function(data, id){
20964 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20969 * Generate a constructor for a specific record layout.
20970 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20971 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20972 * Each field definition object may contain the following properties: <ul>
20973 * <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,
20974 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20975 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20976 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20977 * is being used, then this is a string containing the javascript expression to reference the data relative to
20978 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20979 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20980 * this may be omitted.</p></li>
20981 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20982 * <ul><li>auto (Default, implies no conversion)</li>
20987 * <li>date</li></ul></p></li>
20988 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20989 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20990 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20991 * by the Reader into an object that will be stored in the Record. It is passed the
20992 * following parameters:<ul>
20993 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20995 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20997 * <br>usage:<br><pre><code>
20998 var TopicRecord = Roo.data.Record.create(
20999 {name: 'title', mapping: 'topic_title'},
21000 {name: 'author', mapping: 'username'},
21001 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
21002 {name: 'lastPost', mapping: 'post_time', type: 'date'},
21003 {name: 'lastPoster', mapping: 'user2'},
21004 {name: 'excerpt', mapping: 'post_text'}
21007 var myNewRecord = new TopicRecord({
21008 title: 'Do my job please',
21011 lastPost: new Date(),
21012 lastPoster: 'Animal',
21013 excerpt: 'No way dude!'
21015 myStore.add(myNewRecord);
21020 Roo.data.Record.create = function(o){
21021 var f = function(){
21022 f.superclass.constructor.apply(this, arguments);
21024 Roo.extend(f, Roo.data.Record);
21025 var p = f.prototype;
21026 p.fields = new Roo.util.MixedCollection(false, function(field){
21029 for(var i = 0, len = o.length; i < len; i++){
21030 p.fields.add(new Roo.data.Field(o[i]));
21032 f.getField = function(name){
21033 return p.fields.get(name);
21038 Roo.data.Record.AUTO_ID = 1000;
21039 Roo.data.Record.EDIT = 'edit';
21040 Roo.data.Record.REJECT = 'reject';
21041 Roo.data.Record.COMMIT = 'commit';
21043 Roo.data.Record.prototype = {
21045 * Readonly flag - true if this record has been modified.
21054 join : function(store){
21055 this.store = store;
21059 * Set the named field to the specified value.
21060 * @param {String} name The name of the field to set.
21061 * @param {Object} value The value to set the field to.
21063 set : function(name, value){
21064 if(this.data[name] == value){
21068 if(!this.modified){
21069 this.modified = {};
21071 if(typeof this.modified[name] == 'undefined'){
21072 this.modified[name] = this.data[name];
21074 this.data[name] = value;
21075 if(!this.editing && this.store){
21076 this.store.afterEdit(this);
21081 * Get the value of the named field.
21082 * @param {String} name The name of the field to get the value of.
21083 * @return {Object} The value of the field.
21085 get : function(name){
21086 return this.data[name];
21090 beginEdit : function(){
21091 this.editing = true;
21092 this.modified = {};
21096 cancelEdit : function(){
21097 this.editing = false;
21098 delete this.modified;
21102 endEdit : function(){
21103 this.editing = false;
21104 if(this.dirty && this.store){
21105 this.store.afterEdit(this);
21110 * Usually called by the {@link Roo.data.Store} which owns the Record.
21111 * Rejects all changes made to the Record since either creation, or the last commit operation.
21112 * Modified fields are reverted to their original values.
21114 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21115 * of reject operations.
21117 reject : function(){
21118 var m = this.modified;
21120 if(typeof m[n] != "function"){
21121 this.data[n] = m[n];
21124 this.dirty = false;
21125 delete this.modified;
21126 this.editing = false;
21128 this.store.afterReject(this);
21133 * Usually called by the {@link Roo.data.Store} which owns the Record.
21134 * Commits all changes made to the Record since either creation, or the last commit operation.
21136 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21137 * of commit operations.
21139 commit : function(){
21140 this.dirty = false;
21141 delete this.modified;
21142 this.editing = false;
21144 this.store.afterCommit(this);
21149 hasError : function(){
21150 return this.error != null;
21154 clearError : function(){
21159 * Creates a copy of this record.
21160 * @param {String} id (optional) A new record id if you don't want to use this record's id
21163 copy : function(newId) {
21164 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21168 * Ext JS Library 1.1.1
21169 * Copyright(c) 2006-2007, Ext JS, LLC.
21171 * Originally Released Under LGPL - original licence link has changed is not relivant.
21174 * <script type="text/javascript">
21180 * @class Roo.data.Store
21181 * @extends Roo.util.Observable
21182 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21183 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21185 * 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
21186 * has no knowledge of the format of the data returned by the Proxy.<br>
21188 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21189 * instances from the data object. These records are cached and made available through accessor functions.
21191 * Creates a new Store.
21192 * @param {Object} config A config object containing the objects needed for the Store to access data,
21193 * and read the data into Records.
21195 Roo.data.Store = function(config){
21196 this.data = new Roo.util.MixedCollection(false);
21197 this.data.getKey = function(o){
21200 this.baseParams = {};
21202 this.paramNames = {
21207 "multisort" : "_multisort"
21210 if(config && config.data){
21211 this.inlineData = config.data;
21212 delete config.data;
21215 Roo.apply(this, config);
21217 if(this.reader){ // reader passed
21218 this.reader = Roo.factory(this.reader, Roo.data);
21219 this.reader.xmodule = this.xmodule || false;
21220 if(!this.recordType){
21221 this.recordType = this.reader.recordType;
21223 if(this.reader.onMetaChange){
21224 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21228 if(this.recordType){
21229 this.fields = this.recordType.prototype.fields;
21231 this.modified = [];
21235 * @event datachanged
21236 * Fires when the data cache has changed, and a widget which is using this Store
21237 * as a Record cache should refresh its view.
21238 * @param {Store} this
21240 datachanged : true,
21242 * @event metachange
21243 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21244 * @param {Store} this
21245 * @param {Object} meta The JSON metadata
21250 * Fires when Records have been added to the Store
21251 * @param {Store} this
21252 * @param {Roo.data.Record[]} records The array of Records added
21253 * @param {Number} index The index at which the record(s) were added
21258 * Fires when a Record has been removed from the Store
21259 * @param {Store} this
21260 * @param {Roo.data.Record} record The Record that was removed
21261 * @param {Number} index The index at which the record was removed
21266 * Fires when a Record has been updated
21267 * @param {Store} this
21268 * @param {Roo.data.Record} record The Record that was updated
21269 * @param {String} operation The update operation being performed. Value may be one of:
21271 Roo.data.Record.EDIT
21272 Roo.data.Record.REJECT
21273 Roo.data.Record.COMMIT
21279 * Fires when the data cache has been cleared.
21280 * @param {Store} this
21284 * @event beforeload
21285 * Fires before a request is made for a new data object. If the beforeload handler returns false
21286 * the load action will be canceled.
21287 * @param {Store} this
21288 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21292 * @event beforeloadadd
21293 * Fires after a new set of Records has been loaded.
21294 * @param {Store} this
21295 * @param {Roo.data.Record[]} records The Records that were loaded
21296 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21298 beforeloadadd : true,
21301 * Fires after a new set of Records has been loaded, before they are added to the store.
21302 * @param {Store} this
21303 * @param {Roo.data.Record[]} records The Records that were loaded
21304 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21305 * @params {Object} return from reader
21309 * @event loadexception
21310 * Fires if an exception occurs in the Proxy during loading.
21311 * Called with the signature of the Proxy's "loadexception" event.
21312 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21315 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21316 * @param {Object} load options
21317 * @param {Object} jsonData from your request (normally this contains the Exception)
21319 loadexception : true
21323 this.proxy = Roo.factory(this.proxy, Roo.data);
21324 this.proxy.xmodule = this.xmodule || false;
21325 this.relayEvents(this.proxy, ["loadexception"]);
21327 this.sortToggle = {};
21328 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21330 Roo.data.Store.superclass.constructor.call(this);
21332 if(this.inlineData){
21333 this.loadData(this.inlineData);
21334 delete this.inlineData;
21338 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21340 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21341 * without a remote query - used by combo/forms at present.
21345 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21348 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21351 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21352 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21355 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21356 * on any HTTP request
21359 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21362 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21366 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21367 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21369 remoteSort : false,
21372 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21373 * loaded or when a record is removed. (defaults to false).
21375 pruneModifiedRecords : false,
21378 lastOptions : null,
21381 * Add Records to the Store and fires the add event.
21382 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21384 add : function(records){
21385 records = [].concat(records);
21386 for(var i = 0, len = records.length; i < len; i++){
21387 records[i].join(this);
21389 var index = this.data.length;
21390 this.data.addAll(records);
21391 this.fireEvent("add", this, records, index);
21395 * Remove a Record from the Store and fires the remove event.
21396 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21398 remove : function(record){
21399 var index = this.data.indexOf(record);
21400 this.data.removeAt(index);
21401 if(this.pruneModifiedRecords){
21402 this.modified.remove(record);
21404 this.fireEvent("remove", this, record, index);
21408 * Remove all Records from the Store and fires the clear event.
21410 removeAll : function(){
21412 if(this.pruneModifiedRecords){
21413 this.modified = [];
21415 this.fireEvent("clear", this);
21419 * Inserts Records to the Store at the given index and fires the add event.
21420 * @param {Number} index The start index at which to insert the passed Records.
21421 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21423 insert : function(index, records){
21424 records = [].concat(records);
21425 for(var i = 0, len = records.length; i < len; i++){
21426 this.data.insert(index, records[i]);
21427 records[i].join(this);
21429 this.fireEvent("add", this, records, index);
21433 * Get the index within the cache of the passed Record.
21434 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21435 * @return {Number} The index of the passed Record. Returns -1 if not found.
21437 indexOf : function(record){
21438 return this.data.indexOf(record);
21442 * Get the index within the cache of the Record with the passed id.
21443 * @param {String} id The id of the Record to find.
21444 * @return {Number} The index of the Record. Returns -1 if not found.
21446 indexOfId : function(id){
21447 return this.data.indexOfKey(id);
21451 * Get the Record with the specified id.
21452 * @param {String} id The id of the Record to find.
21453 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21455 getById : function(id){
21456 return this.data.key(id);
21460 * Get the Record at the specified index.
21461 * @param {Number} index The index of the Record to find.
21462 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21464 getAt : function(index){
21465 return this.data.itemAt(index);
21469 * Returns a range of Records between specified indices.
21470 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21471 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21472 * @return {Roo.data.Record[]} An array of Records
21474 getRange : function(start, end){
21475 return this.data.getRange(start, end);
21479 storeOptions : function(o){
21480 o = Roo.apply({}, o);
21483 this.lastOptions = o;
21487 * Loads the Record cache from the configured Proxy using the configured Reader.
21489 * If using remote paging, then the first load call must specify the <em>start</em>
21490 * and <em>limit</em> properties in the options.params property to establish the initial
21491 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21493 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21494 * and this call will return before the new data has been loaded. Perform any post-processing
21495 * in a callback function, or in a "load" event handler.</strong>
21497 * @param {Object} options An object containing properties which control loading options:<ul>
21498 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21499 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21500 * passed the following arguments:<ul>
21501 * <li>r : Roo.data.Record[]</li>
21502 * <li>options: Options object from the load call</li>
21503 * <li>success: Boolean success indicator</li></ul></li>
21504 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21505 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21508 load : function(options){
21509 options = options || {};
21510 if(this.fireEvent("beforeload", this, options) !== false){
21511 this.storeOptions(options);
21512 var p = Roo.apply(options.params || {}, this.baseParams);
21513 // if meta was not loaded from remote source.. try requesting it.
21514 if (!this.reader.metaFromRemote) {
21515 p._requestMeta = 1;
21517 if(this.sortInfo && this.remoteSort){
21518 var pn = this.paramNames;
21519 p[pn["sort"]] = this.sortInfo.field;
21520 p[pn["dir"]] = this.sortInfo.direction;
21522 if (this.multiSort) {
21523 var pn = this.paramNames;
21524 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21527 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21532 * Reloads the Record cache from the configured Proxy using the configured Reader and
21533 * the options from the last load operation performed.
21534 * @param {Object} options (optional) An object containing properties which may override the options
21535 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21536 * the most recently used options are reused).
21538 reload : function(options){
21539 this.load(Roo.applyIf(options||{}, this.lastOptions));
21543 // Called as a callback by the Reader during a load operation.
21544 loadRecords : function(o, options, success){
21545 if(!o || success === false){
21546 if(success !== false){
21547 this.fireEvent("load", this, [], options, o);
21549 if(options.callback){
21550 options.callback.call(options.scope || this, [], options, false);
21554 // if data returned failure - throw an exception.
21555 if (o.success === false) {
21556 // show a message if no listener is registered.
21557 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21558 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21560 // loadmask wil be hooked into this..
21561 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21564 var r = o.records, t = o.totalRecords || r.length;
21566 this.fireEvent("beforeloadadd", this, r, options, o);
21568 if(!options || options.add !== true){
21569 if(this.pruneModifiedRecords){
21570 this.modified = [];
21572 for(var i = 0, len = r.length; i < len; i++){
21576 this.data = this.snapshot;
21577 delete this.snapshot;
21580 this.data.addAll(r);
21581 this.totalLength = t;
21583 this.fireEvent("datachanged", this);
21585 this.totalLength = Math.max(t, this.data.length+r.length);
21588 this.fireEvent("load", this, r, options, o);
21589 if(options.callback){
21590 options.callback.call(options.scope || this, r, options, true);
21596 * Loads data from a passed data block. A Reader which understands the format of the data
21597 * must have been configured in the constructor.
21598 * @param {Object} data The data block from which to read the Records. The format of the data expected
21599 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21600 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21602 loadData : function(o, append){
21603 var r = this.reader.readRecords(o);
21604 this.loadRecords(r, {add: append}, true);
21608 * Gets the number of cached records.
21610 * <em>If using paging, this may not be the total size of the dataset. If the data object
21611 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21612 * the data set size</em>
21614 getCount : function(){
21615 return this.data.length || 0;
21619 * Gets the total number of records in the dataset as returned by the server.
21621 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21622 * the dataset size</em>
21624 getTotalCount : function(){
21625 return this.totalLength || 0;
21629 * Returns the sort state of the Store as an object with two properties:
21631 field {String} The name of the field by which the Records are sorted
21632 direction {String} The sort order, "ASC" or "DESC"
21635 getSortState : function(){
21636 return this.sortInfo;
21640 applySort : function(){
21641 if(this.sortInfo && !this.remoteSort){
21642 var s = this.sortInfo, f = s.field;
21643 var st = this.fields.get(f).sortType;
21644 var fn = function(r1, r2){
21645 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21646 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21648 this.data.sort(s.direction, fn);
21649 if(this.snapshot && this.snapshot != this.data){
21650 this.snapshot.sort(s.direction, fn);
21656 * Sets the default sort column and order to be used by the next load operation.
21657 * @param {String} fieldName The name of the field to sort by.
21658 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21660 setDefaultSort : function(field, dir){
21661 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21665 * Sort the Records.
21666 * If remote sorting is used, the sort is performed on the server, and the cache is
21667 * reloaded. If local sorting is used, the cache is sorted internally.
21668 * @param {String} fieldName The name of the field to sort by.
21669 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21671 sort : function(fieldName, dir){
21672 var f = this.fields.get(fieldName);
21674 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21676 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21677 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21682 this.sortToggle[f.name] = dir;
21683 this.sortInfo = {field: f.name, direction: dir};
21684 if(!this.remoteSort){
21686 this.fireEvent("datachanged", this);
21688 this.load(this.lastOptions);
21693 * Calls the specified function for each of the Records in the cache.
21694 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21695 * Returning <em>false</em> aborts and exits the iteration.
21696 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21698 each : function(fn, scope){
21699 this.data.each(fn, scope);
21703 * Gets all records modified since the last commit. Modified records are persisted across load operations
21704 * (e.g., during paging).
21705 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21707 getModifiedRecords : function(){
21708 return this.modified;
21712 createFilterFn : function(property, value, anyMatch){
21713 if(!value.exec){ // not a regex
21714 value = String(value);
21715 if(value.length == 0){
21718 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21720 return function(r){
21721 return value.test(r.data[property]);
21726 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21727 * @param {String} property A field on your records
21728 * @param {Number} start The record index to start at (defaults to 0)
21729 * @param {Number} end The last record index to include (defaults to length - 1)
21730 * @return {Number} The sum
21732 sum : function(property, start, end){
21733 var rs = this.data.items, v = 0;
21734 start = start || 0;
21735 end = (end || end === 0) ? end : rs.length-1;
21737 for(var i = start; i <= end; i++){
21738 v += (rs[i].data[property] || 0);
21744 * Filter the records by a specified property.
21745 * @param {String} field A field on your records
21746 * @param {String/RegExp} value Either a string that the field
21747 * should start with or a RegExp to test against the field
21748 * @param {Boolean} anyMatch True to match any part not just the beginning
21750 filter : function(property, value, anyMatch){
21751 var fn = this.createFilterFn(property, value, anyMatch);
21752 return fn ? this.filterBy(fn) : this.clearFilter();
21756 * Filter by a function. The specified function will be called with each
21757 * record in this data source. If the function returns true the record is included,
21758 * otherwise it is filtered.
21759 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21760 * @param {Object} scope (optional) The scope of the function (defaults to this)
21762 filterBy : function(fn, scope){
21763 this.snapshot = this.snapshot || this.data;
21764 this.data = this.queryBy(fn, scope||this);
21765 this.fireEvent("datachanged", this);
21769 * Query the records by a specified property.
21770 * @param {String} field A field on your records
21771 * @param {String/RegExp} value Either a string that the field
21772 * should start with or a RegExp to test against the field
21773 * @param {Boolean} anyMatch True to match any part not just the beginning
21774 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21776 query : function(property, value, anyMatch){
21777 var fn = this.createFilterFn(property, value, anyMatch);
21778 return fn ? this.queryBy(fn) : this.data.clone();
21782 * Query by a function. The specified function will be called with each
21783 * record in this data source. If the function returns true the record is included
21785 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21786 * @param {Object} scope (optional) The scope of the function (defaults to this)
21787 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21789 queryBy : function(fn, scope){
21790 var data = this.snapshot || this.data;
21791 return data.filterBy(fn, scope||this);
21795 * Collects unique values for a particular dataIndex from this store.
21796 * @param {String} dataIndex The property to collect
21797 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21798 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21799 * @return {Array} An array of the unique values
21801 collect : function(dataIndex, allowNull, bypassFilter){
21802 var d = (bypassFilter === true && this.snapshot) ?
21803 this.snapshot.items : this.data.items;
21804 var v, sv, r = [], l = {};
21805 for(var i = 0, len = d.length; i < len; i++){
21806 v = d[i].data[dataIndex];
21808 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21817 * Revert to a view of the Record cache with no filtering applied.
21818 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21820 clearFilter : function(suppressEvent){
21821 if(this.snapshot && this.snapshot != this.data){
21822 this.data = this.snapshot;
21823 delete this.snapshot;
21824 if(suppressEvent !== true){
21825 this.fireEvent("datachanged", this);
21831 afterEdit : function(record){
21832 if(this.modified.indexOf(record) == -1){
21833 this.modified.push(record);
21835 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21839 afterReject : function(record){
21840 this.modified.remove(record);
21841 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21845 afterCommit : function(record){
21846 this.modified.remove(record);
21847 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21851 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21852 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21854 commitChanges : function(){
21855 var m = this.modified.slice(0);
21856 this.modified = [];
21857 for(var i = 0, len = m.length; i < len; i++){
21863 * Cancel outstanding changes on all changed records.
21865 rejectChanges : function(){
21866 var m = this.modified.slice(0);
21867 this.modified = [];
21868 for(var i = 0, len = m.length; i < len; i++){
21873 onMetaChange : function(meta, rtype, o){
21874 this.recordType = rtype;
21875 this.fields = rtype.prototype.fields;
21876 delete this.snapshot;
21877 this.sortInfo = meta.sortInfo || this.sortInfo;
21878 this.modified = [];
21879 this.fireEvent('metachange', this, this.reader.meta);
21882 moveIndex : function(data, type)
21884 var index = this.indexOf(data);
21886 var newIndex = index + type;
21890 this.insert(newIndex, data);
21895 * Ext JS Library 1.1.1
21896 * Copyright(c) 2006-2007, Ext JS, LLC.
21898 * Originally Released Under LGPL - original licence link has changed is not relivant.
21901 * <script type="text/javascript">
21905 * @class Roo.data.SimpleStore
21906 * @extends Roo.data.Store
21907 * Small helper class to make creating Stores from Array data easier.
21908 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21909 * @cfg {Array} fields An array of field definition objects, or field name strings.
21910 * @cfg {Array} data The multi-dimensional array of data
21912 * @param {Object} config
21914 Roo.data.SimpleStore = function(config){
21915 Roo.data.SimpleStore.superclass.constructor.call(this, {
21917 reader: new Roo.data.ArrayReader({
21920 Roo.data.Record.create(config.fields)
21922 proxy : new Roo.data.MemoryProxy(config.data)
21926 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21928 * Ext JS Library 1.1.1
21929 * Copyright(c) 2006-2007, Ext JS, LLC.
21931 * Originally Released Under LGPL - original licence link has changed is not relivant.
21934 * <script type="text/javascript">
21939 * @extends Roo.data.Store
21940 * @class Roo.data.JsonStore
21941 * Small helper class to make creating Stores for JSON data easier. <br/>
21943 var store = new Roo.data.JsonStore({
21944 url: 'get-images.php',
21946 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21949 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21950 * JsonReader and HttpProxy (unless inline data is provided).</b>
21951 * @cfg {Array} fields An array of field definition objects, or field name strings.
21953 * @param {Object} config
21955 Roo.data.JsonStore = function(c){
21956 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21957 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21958 reader: new Roo.data.JsonReader(c, c.fields)
21961 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21963 * Ext JS Library 1.1.1
21964 * Copyright(c) 2006-2007, Ext JS, LLC.
21966 * Originally Released Under LGPL - original licence link has changed is not relivant.
21969 * <script type="text/javascript">
21973 Roo.data.Field = function(config){
21974 if(typeof config == "string"){
21975 config = {name: config};
21977 Roo.apply(this, config);
21980 this.type = "auto";
21983 var st = Roo.data.SortTypes;
21984 // named sortTypes are supported, here we look them up
21985 if(typeof this.sortType == "string"){
21986 this.sortType = st[this.sortType];
21989 // set default sortType for strings and dates
21990 if(!this.sortType){
21993 this.sortType = st.asUCString;
21996 this.sortType = st.asDate;
21999 this.sortType = st.none;
22004 var stripRe = /[\$,%]/g;
22006 // prebuilt conversion function for this field, instead of
22007 // switching every time we're reading a value
22009 var cv, dateFormat = this.dateFormat;
22014 cv = function(v){ return v; };
22017 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22021 return v !== undefined && v !== null && v !== '' ?
22022 parseInt(String(v).replace(stripRe, ""), 10) : '';
22027 return v !== undefined && v !== null && v !== '' ?
22028 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22033 cv = function(v){ return v === true || v === "true" || v == 1; };
22040 if(v instanceof Date){
22044 if(dateFormat == "timestamp"){
22045 return new Date(v*1000);
22047 return Date.parseDate(v, dateFormat);
22049 var parsed = Date.parse(v);
22050 return parsed ? new Date(parsed) : null;
22059 Roo.data.Field.prototype = {
22067 * Ext JS Library 1.1.1
22068 * Copyright(c) 2006-2007, Ext JS, LLC.
22070 * Originally Released Under LGPL - original licence link has changed is not relivant.
22073 * <script type="text/javascript">
22076 // Base class for reading structured data from a data source. This class is intended to be
22077 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22080 * @class Roo.data.DataReader
22081 * Base class for reading structured data from a data source. This class is intended to be
22082 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22085 Roo.data.DataReader = function(meta, recordType){
22089 this.recordType = recordType instanceof Array ?
22090 Roo.data.Record.create(recordType) : recordType;
22093 Roo.data.DataReader.prototype = {
22095 * Create an empty record
22096 * @param {Object} data (optional) - overlay some values
22097 * @return {Roo.data.Record} record created.
22099 newRow : function(d) {
22101 this.recordType.prototype.fields.each(function(c) {
22103 case 'int' : da[c.name] = 0; break;
22104 case 'date' : da[c.name] = new Date(); break;
22105 case 'float' : da[c.name] = 0.0; break;
22106 case 'boolean' : da[c.name] = false; break;
22107 default : da[c.name] = ""; break;
22111 return new this.recordType(Roo.apply(da, d));
22116 * Ext JS Library 1.1.1
22117 * Copyright(c) 2006-2007, Ext JS, LLC.
22119 * Originally Released Under LGPL - original licence link has changed is not relivant.
22122 * <script type="text/javascript">
22126 * @class Roo.data.DataProxy
22127 * @extends Roo.data.Observable
22128 * This class is an abstract base class for implementations which provide retrieval of
22129 * unformatted data objects.<br>
22131 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22132 * (of the appropriate type which knows how to parse the data object) to provide a block of
22133 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22135 * Custom implementations must implement the load method as described in
22136 * {@link Roo.data.HttpProxy#load}.
22138 Roo.data.DataProxy = function(){
22141 * @event beforeload
22142 * Fires before a network request is made to retrieve a data object.
22143 * @param {Object} This DataProxy object.
22144 * @param {Object} params The params parameter to the load function.
22149 * Fires before the load method's callback is called.
22150 * @param {Object} This DataProxy object.
22151 * @param {Object} o The data object.
22152 * @param {Object} arg The callback argument object passed to the load function.
22156 * @event loadexception
22157 * Fires if an Exception occurs during data retrieval.
22158 * @param {Object} This DataProxy object.
22159 * @param {Object} o The data object.
22160 * @param {Object} arg The callback argument object passed to the load function.
22161 * @param {Object} e The Exception.
22163 loadexception : true
22165 Roo.data.DataProxy.superclass.constructor.call(this);
22168 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22171 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22175 * Ext JS Library 1.1.1
22176 * Copyright(c) 2006-2007, Ext JS, LLC.
22178 * Originally Released Under LGPL - original licence link has changed is not relivant.
22181 * <script type="text/javascript">
22184 * @class Roo.data.MemoryProxy
22185 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22186 * to the Reader when its load method is called.
22188 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22190 Roo.data.MemoryProxy = function(data){
22194 Roo.data.MemoryProxy.superclass.constructor.call(this);
22198 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22200 * Load data from the requested source (in this case an in-memory
22201 * data object passed to the constructor), read the data object into
22202 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22203 * process that block using the passed callback.
22204 * @param {Object} params This parameter is not used by the MemoryProxy class.
22205 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22206 * object into a block of Roo.data.Records.
22207 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22208 * The function must be passed <ul>
22209 * <li>The Record block object</li>
22210 * <li>The "arg" argument from the load function</li>
22211 * <li>A boolean success indicator</li>
22213 * @param {Object} scope The scope in which to call the callback
22214 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22216 load : function(params, reader, callback, scope, arg){
22217 params = params || {};
22220 result = reader.readRecords(this.data);
22222 this.fireEvent("loadexception", this, arg, null, e);
22223 callback.call(scope, null, arg, false);
22226 callback.call(scope, result, arg, true);
22230 update : function(params, records){
22235 * Ext JS Library 1.1.1
22236 * Copyright(c) 2006-2007, Ext JS, LLC.
22238 * Originally Released Under LGPL - original licence link has changed is not relivant.
22241 * <script type="text/javascript">
22244 * @class Roo.data.HttpProxy
22245 * @extends Roo.data.DataProxy
22246 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22247 * configured to reference a certain URL.<br><br>
22249 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22250 * from which the running page was served.<br><br>
22252 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22254 * Be aware that to enable the browser to parse an XML document, the server must set
22255 * the Content-Type header in the HTTP response to "text/xml".
22257 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22258 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22259 * will be used to make the request.
22261 Roo.data.HttpProxy = function(conn){
22262 Roo.data.HttpProxy.superclass.constructor.call(this);
22263 // is conn a conn config or a real conn?
22265 this.useAjax = !conn || !conn.events;
22269 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22270 // thse are take from connection...
22273 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22276 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22277 * extra parameters to each request made by this object. (defaults to undefined)
22280 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22281 * to each request made by this object. (defaults to undefined)
22284 * @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)
22287 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22290 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22296 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22300 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22301 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22302 * a finer-grained basis than the DataProxy events.
22304 getConnection : function(){
22305 return this.useAjax ? Roo.Ajax : this.conn;
22309 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22310 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22311 * process that block using the passed callback.
22312 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22313 * for the request to the remote server.
22314 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22315 * object into a block of Roo.data.Records.
22316 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22317 * The function must be passed <ul>
22318 * <li>The Record block object</li>
22319 * <li>The "arg" argument from the load function</li>
22320 * <li>A boolean success indicator</li>
22322 * @param {Object} scope The scope in which to call the callback
22323 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22325 load : function(params, reader, callback, scope, arg){
22326 if(this.fireEvent("beforeload", this, params) !== false){
22328 params : params || {},
22330 callback : callback,
22335 callback : this.loadResponse,
22339 Roo.applyIf(o, this.conn);
22340 if(this.activeRequest){
22341 Roo.Ajax.abort(this.activeRequest);
22343 this.activeRequest = Roo.Ajax.request(o);
22345 this.conn.request(o);
22348 callback.call(scope||this, null, arg, false);
22353 loadResponse : function(o, success, response){
22354 delete this.activeRequest;
22356 this.fireEvent("loadexception", this, o, response);
22357 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22362 result = o.reader.read(response);
22364 this.fireEvent("loadexception", this, o, response, e);
22365 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22369 this.fireEvent("load", this, o, o.request.arg);
22370 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22374 update : function(dataSet){
22379 updateResponse : function(dataSet){
22384 * Ext JS Library 1.1.1
22385 * Copyright(c) 2006-2007, Ext JS, LLC.
22387 * Originally Released Under LGPL - original licence link has changed is not relivant.
22390 * <script type="text/javascript">
22394 * @class Roo.data.ScriptTagProxy
22395 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22396 * other than the originating domain of the running page.<br><br>
22398 * <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
22399 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22401 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22402 * source code that is used as the source inside a <script> tag.<br><br>
22404 * In order for the browser to process the returned data, the server must wrap the data object
22405 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22406 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22407 * depending on whether the callback name was passed:
22410 boolean scriptTag = false;
22411 String cb = request.getParameter("callback");
22414 response.setContentType("text/javascript");
22416 response.setContentType("application/x-json");
22418 Writer out = response.getWriter();
22420 out.write(cb + "(");
22422 out.print(dataBlock.toJsonString());
22429 * @param {Object} config A configuration object.
22431 Roo.data.ScriptTagProxy = function(config){
22432 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22433 Roo.apply(this, config);
22434 this.head = document.getElementsByTagName("head")[0];
22437 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22439 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22441 * @cfg {String} url The URL from which to request the data object.
22444 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22448 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22449 * the server the name of the callback function set up by the load call to process the returned data object.
22450 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22451 * javascript output which calls this named function passing the data object as its only parameter.
22453 callbackParam : "callback",
22455 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22456 * name to the request.
22461 * Load data from the configured URL, read the data object into
22462 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22463 * process that block using the passed callback.
22464 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22465 * for the request to the remote server.
22466 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22467 * object into a block of Roo.data.Records.
22468 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22469 * The function must be passed <ul>
22470 * <li>The Record block object</li>
22471 * <li>The "arg" argument from the load function</li>
22472 * <li>A boolean success indicator</li>
22474 * @param {Object} scope The scope in which to call the callback
22475 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22477 load : function(params, reader, callback, scope, arg){
22478 if(this.fireEvent("beforeload", this, params) !== false){
22480 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22482 var url = this.url;
22483 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22485 url += "&_dc=" + (new Date().getTime());
22487 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22490 cb : "stcCallback"+transId,
22491 scriptId : "stcScript"+transId,
22495 callback : callback,
22501 window[trans.cb] = function(o){
22502 conn.handleResponse(o, trans);
22505 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22507 if(this.autoAbort !== false){
22511 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22513 var script = document.createElement("script");
22514 script.setAttribute("src", url);
22515 script.setAttribute("type", "text/javascript");
22516 script.setAttribute("id", trans.scriptId);
22517 this.head.appendChild(script);
22519 this.trans = trans;
22521 callback.call(scope||this, null, arg, false);
22526 isLoading : function(){
22527 return this.trans ? true : false;
22531 * Abort the current server request.
22533 abort : function(){
22534 if(this.isLoading()){
22535 this.destroyTrans(this.trans);
22540 destroyTrans : function(trans, isLoaded){
22541 this.head.removeChild(document.getElementById(trans.scriptId));
22542 clearTimeout(trans.timeoutId);
22544 window[trans.cb] = undefined;
22546 delete window[trans.cb];
22549 // if hasn't been loaded, wait for load to remove it to prevent script error
22550 window[trans.cb] = function(){
22551 window[trans.cb] = undefined;
22553 delete window[trans.cb];
22560 handleResponse : function(o, trans){
22561 this.trans = false;
22562 this.destroyTrans(trans, true);
22565 result = trans.reader.readRecords(o);
22567 this.fireEvent("loadexception", this, o, trans.arg, e);
22568 trans.callback.call(trans.scope||window, null, trans.arg, false);
22571 this.fireEvent("load", this, o, trans.arg);
22572 trans.callback.call(trans.scope||window, result, trans.arg, true);
22576 handleFailure : function(trans){
22577 this.trans = false;
22578 this.destroyTrans(trans, false);
22579 this.fireEvent("loadexception", this, null, trans.arg);
22580 trans.callback.call(trans.scope||window, null, trans.arg, false);
22584 * Ext JS Library 1.1.1
22585 * Copyright(c) 2006-2007, Ext JS, LLC.
22587 * Originally Released Under LGPL - original licence link has changed is not relivant.
22590 * <script type="text/javascript">
22594 * @class Roo.data.JsonReader
22595 * @extends Roo.data.DataReader
22596 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22597 * based on mappings in a provided Roo.data.Record constructor.
22599 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22600 * in the reply previously.
22605 var RecordDef = Roo.data.Record.create([
22606 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22607 {name: 'occupation'} // This field will use "occupation" as the mapping.
22609 var myReader = new Roo.data.JsonReader({
22610 totalProperty: "results", // The property which contains the total dataset size (optional)
22611 root: "rows", // The property which contains an Array of row objects
22612 id: "id" // The property within each row object that provides an ID for the record (optional)
22616 * This would consume a JSON file like this:
22618 { 'results': 2, 'rows': [
22619 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22620 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22623 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22624 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22625 * paged from the remote server.
22626 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22627 * @cfg {String} root name of the property which contains the Array of row objects.
22628 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22629 * @cfg {Array} fields Array of field definition objects
22631 * Create a new JsonReader
22632 * @param {Object} meta Metadata configuration options
22633 * @param {Object} recordType Either an Array of field definition objects,
22634 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22636 Roo.data.JsonReader = function(meta, recordType){
22639 // set some defaults:
22640 Roo.applyIf(meta, {
22641 totalProperty: 'total',
22642 successProperty : 'success',
22647 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22649 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22652 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22653 * Used by Store query builder to append _requestMeta to params.
22656 metaFromRemote : false,
22658 * This method is only used by a DataProxy which has retrieved data from a remote server.
22659 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22660 * @return {Object} data A data block which is used by an Roo.data.Store object as
22661 * a cache of Roo.data.Records.
22663 read : function(response){
22664 var json = response.responseText;
22666 var o = /* eval:var:o */ eval("("+json+")");
22668 throw {message: "JsonReader.read: Json object not found"};
22674 this.metaFromRemote = true;
22675 this.meta = o.metaData;
22676 this.recordType = Roo.data.Record.create(o.metaData.fields);
22677 this.onMetaChange(this.meta, this.recordType, o);
22679 return this.readRecords(o);
22682 // private function a store will implement
22683 onMetaChange : function(meta, recordType, o){
22690 simpleAccess: function(obj, subsc) {
22697 getJsonAccessor: function(){
22699 return function(expr) {
22701 return(re.test(expr))
22702 ? new Function("obj", "return obj." + expr)
22707 return Roo.emptyFn;
22712 * Create a data block containing Roo.data.Records from an XML document.
22713 * @param {Object} o An object which contains an Array of row objects in the property specified
22714 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22715 * which contains the total size of the dataset.
22716 * @return {Object} data A data block which is used by an Roo.data.Store object as
22717 * a cache of Roo.data.Records.
22719 readRecords : function(o){
22721 * After any data loads, the raw JSON data is available for further custom processing.
22725 var s = this.meta, Record = this.recordType,
22726 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22728 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22730 if(s.totalProperty) {
22731 this.getTotal = this.getJsonAccessor(s.totalProperty);
22733 if(s.successProperty) {
22734 this.getSuccess = this.getJsonAccessor(s.successProperty);
22736 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22738 var g = this.getJsonAccessor(s.id);
22739 this.getId = function(rec) {
22741 return (r === undefined || r === "") ? null : r;
22744 this.getId = function(){return null;};
22747 for(var jj = 0; jj < fl; jj++){
22749 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22750 this.ef[jj] = this.getJsonAccessor(map);
22754 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22755 if(s.totalProperty){
22756 var vt = parseInt(this.getTotal(o), 10);
22761 if(s.successProperty){
22762 var vs = this.getSuccess(o);
22763 if(vs === false || vs === 'false'){
22768 for(var i = 0; i < c; i++){
22771 var id = this.getId(n);
22772 for(var j = 0; j < fl; j++){
22774 var v = this.ef[j](n);
22776 Roo.log('missing convert for ' + f.name);
22780 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22782 var record = new Record(values, id);
22784 records[i] = record;
22790 totalRecords : totalRecords
22795 * Ext JS Library 1.1.1
22796 * Copyright(c) 2006-2007, Ext JS, LLC.
22798 * Originally Released Under LGPL - original licence link has changed is not relivant.
22801 * <script type="text/javascript">
22805 * @class Roo.data.XmlReader
22806 * @extends Roo.data.DataReader
22807 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22808 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22810 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22811 * header in the HTTP response must be set to "text/xml".</em>
22815 var RecordDef = Roo.data.Record.create([
22816 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22817 {name: 'occupation'} // This field will use "occupation" as the mapping.
22819 var myReader = new Roo.data.XmlReader({
22820 totalRecords: "results", // The element which contains the total dataset size (optional)
22821 record: "row", // The repeated element which contains row information
22822 id: "id" // The element within the row that provides an ID for the record (optional)
22826 * This would consume an XML file like this:
22830 <results>2</results>
22833 <name>Bill</name>
22834 <occupation>Gardener</occupation>
22838 <name>Ben</name>
22839 <occupation>Horticulturalist</occupation>
22843 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22844 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22845 * paged from the remote server.
22846 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22847 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22848 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22849 * a record identifier value.
22851 * Create a new XmlReader
22852 * @param {Object} meta Metadata configuration options
22853 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22854 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22855 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22857 Roo.data.XmlReader = function(meta, recordType){
22859 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22861 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22863 * This method is only used by a DataProxy which has retrieved data from a remote server.
22864 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22865 * to contain a method called 'responseXML' that returns an XML document object.
22866 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22867 * a cache of Roo.data.Records.
22869 read : function(response){
22870 var doc = response.responseXML;
22872 throw {message: "XmlReader.read: XML Document not available"};
22874 return this.readRecords(doc);
22878 * Create a data block containing Roo.data.Records from an XML document.
22879 * @param {Object} doc A parsed XML document.
22880 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22881 * a cache of Roo.data.Records.
22883 readRecords : function(doc){
22885 * After any data loads/reads, the raw XML Document is available for further custom processing.
22886 * @type XMLDocument
22888 this.xmlData = doc;
22889 var root = doc.documentElement || doc;
22890 var q = Roo.DomQuery;
22891 var recordType = this.recordType, fields = recordType.prototype.fields;
22892 var sid = this.meta.id;
22893 var totalRecords = 0, success = true;
22894 if(this.meta.totalRecords){
22895 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22898 if(this.meta.success){
22899 var sv = q.selectValue(this.meta.success, root, true);
22900 success = sv !== false && sv !== 'false';
22903 var ns = q.select(this.meta.record, root);
22904 for(var i = 0, len = ns.length; i < len; i++) {
22907 var id = sid ? q.selectValue(sid, n) : undefined;
22908 for(var j = 0, jlen = fields.length; j < jlen; j++){
22909 var f = fields.items[j];
22910 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22912 values[f.name] = v;
22914 var record = new recordType(values, id);
22916 records[records.length] = record;
22922 totalRecords : totalRecords || records.length
22927 * Ext JS Library 1.1.1
22928 * Copyright(c) 2006-2007, Ext JS, LLC.
22930 * Originally Released Under LGPL - original licence link has changed is not relivant.
22933 * <script type="text/javascript">
22937 * @class Roo.data.ArrayReader
22938 * @extends Roo.data.DataReader
22939 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22940 * Each element of that Array represents a row of data fields. The
22941 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22942 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22946 var RecordDef = Roo.data.Record.create([
22947 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22948 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22950 var myReader = new Roo.data.ArrayReader({
22951 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22955 * This would consume an Array like this:
22957 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22959 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22961 * Create a new JsonReader
22962 * @param {Object} meta Metadata configuration options.
22963 * @param {Object} recordType Either an Array of field definition objects
22964 * as specified to {@link Roo.data.Record#create},
22965 * or an {@link Roo.data.Record} object
22966 * created using {@link Roo.data.Record#create}.
22968 Roo.data.ArrayReader = function(meta, recordType){
22969 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22972 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22974 * Create a data block containing Roo.data.Records from an XML document.
22975 * @param {Object} o An Array of row objects which represents the dataset.
22976 * @return {Object} data A data block which is used by an Roo.data.Store object as
22977 * a cache of Roo.data.Records.
22979 readRecords : function(o){
22980 var sid = this.meta ? this.meta.id : null;
22981 var recordType = this.recordType, fields = recordType.prototype.fields;
22984 for(var i = 0; i < root.length; i++){
22987 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22988 for(var j = 0, jlen = fields.length; j < jlen; j++){
22989 var f = fields.items[j];
22990 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22991 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22993 values[f.name] = v;
22995 var record = new recordType(values, id);
22997 records[records.length] = record;
23001 totalRecords : records.length
23006 * Ext JS Library 1.1.1
23007 * Copyright(c) 2006-2007, Ext JS, LLC.
23009 * Originally Released Under LGPL - original licence link has changed is not relivant.
23012 * <script type="text/javascript">
23017 * @class Roo.data.Tree
23018 * @extends Roo.util.Observable
23019 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23020 * in the tree have most standard DOM functionality.
23022 * @param {Node} root (optional) The root node
23024 Roo.data.Tree = function(root){
23025 this.nodeHash = {};
23027 * The root node for this tree
23032 this.setRootNode(root);
23037 * Fires when a new child node is appended to a node in this tree.
23038 * @param {Tree} tree The owner tree
23039 * @param {Node} parent The parent node
23040 * @param {Node} node The newly appended node
23041 * @param {Number} index The index of the newly appended node
23046 * Fires when a child node is removed from a node in this tree.
23047 * @param {Tree} tree The owner tree
23048 * @param {Node} parent The parent node
23049 * @param {Node} node The child node removed
23054 * Fires when a node is moved to a new location in the tree
23055 * @param {Tree} tree The owner tree
23056 * @param {Node} node The node moved
23057 * @param {Node} oldParent The old parent of this node
23058 * @param {Node} newParent The new parent of this node
23059 * @param {Number} index The index it was moved to
23064 * Fires when a new child node is inserted in a node in this tree.
23065 * @param {Tree} tree The owner tree
23066 * @param {Node} parent The parent node
23067 * @param {Node} node The child node inserted
23068 * @param {Node} refNode The child node the node was inserted before
23072 * @event beforeappend
23073 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23074 * @param {Tree} tree The owner tree
23075 * @param {Node} parent The parent node
23076 * @param {Node} node The child node to be appended
23078 "beforeappend" : true,
23080 * @event beforeremove
23081 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23082 * @param {Tree} tree The owner tree
23083 * @param {Node} parent The parent node
23084 * @param {Node} node The child node to be removed
23086 "beforeremove" : true,
23088 * @event beforemove
23089 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23090 * @param {Tree} tree The owner tree
23091 * @param {Node} node The node being moved
23092 * @param {Node} oldParent The parent of the node
23093 * @param {Node} newParent The new parent the node is moving to
23094 * @param {Number} index The index it is being moved to
23096 "beforemove" : true,
23098 * @event beforeinsert
23099 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23100 * @param {Tree} tree The owner tree
23101 * @param {Node} parent The parent node
23102 * @param {Node} node The child node to be inserted
23103 * @param {Node} refNode The child node the node is being inserted before
23105 "beforeinsert" : true
23108 Roo.data.Tree.superclass.constructor.call(this);
23111 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23112 pathSeparator: "/",
23114 proxyNodeEvent : function(){
23115 return this.fireEvent.apply(this, arguments);
23119 * Returns the root node for this tree.
23122 getRootNode : function(){
23127 * Sets the root node for this tree.
23128 * @param {Node} node
23131 setRootNode : function(node){
23133 node.ownerTree = this;
23134 node.isRoot = true;
23135 this.registerNode(node);
23140 * Gets a node in this tree by its id.
23141 * @param {String} id
23144 getNodeById : function(id){
23145 return this.nodeHash[id];
23148 registerNode : function(node){
23149 this.nodeHash[node.id] = node;
23152 unregisterNode : function(node){
23153 delete this.nodeHash[node.id];
23156 toString : function(){
23157 return "[Tree"+(this.id?" "+this.id:"")+"]";
23162 * @class Roo.data.Node
23163 * @extends Roo.util.Observable
23164 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23165 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23167 * @param {Object} attributes The attributes/config for the node
23169 Roo.data.Node = function(attributes){
23171 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23174 this.attributes = attributes || {};
23175 this.leaf = this.attributes.leaf;
23177 * The node id. @type String
23179 this.id = this.attributes.id;
23181 this.id = Roo.id(null, "ynode-");
23182 this.attributes.id = this.id;
23187 * All child nodes of this node. @type Array
23189 this.childNodes = [];
23190 if(!this.childNodes.indexOf){ // indexOf is a must
23191 this.childNodes.indexOf = function(o){
23192 for(var i = 0, len = this.length; i < len; i++){
23201 * The parent node for this node. @type Node
23203 this.parentNode = null;
23205 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23207 this.firstChild = null;
23209 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23211 this.lastChild = null;
23213 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23215 this.previousSibling = null;
23217 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23219 this.nextSibling = null;
23224 * Fires when a new child node is appended
23225 * @param {Tree} tree The owner tree
23226 * @param {Node} this This node
23227 * @param {Node} node The newly appended node
23228 * @param {Number} index The index of the newly appended node
23233 * Fires when a child node is removed
23234 * @param {Tree} tree The owner tree
23235 * @param {Node} this This node
23236 * @param {Node} node The removed node
23241 * Fires when this node is moved to a new location in the tree
23242 * @param {Tree} tree The owner tree
23243 * @param {Node} this This node
23244 * @param {Node} oldParent The old parent of this node
23245 * @param {Node} newParent The new parent of this node
23246 * @param {Number} index The index it was moved to
23251 * Fires when a new child node is inserted.
23252 * @param {Tree} tree The owner tree
23253 * @param {Node} this This node
23254 * @param {Node} node The child node inserted
23255 * @param {Node} refNode The child node the node was inserted before
23259 * @event beforeappend
23260 * Fires before a new child is appended, return false to cancel the append.
23261 * @param {Tree} tree The owner tree
23262 * @param {Node} this This node
23263 * @param {Node} node The child node to be appended
23265 "beforeappend" : true,
23267 * @event beforeremove
23268 * Fires before a child is removed, return false to cancel the remove.
23269 * @param {Tree} tree The owner tree
23270 * @param {Node} this This node
23271 * @param {Node} node The child node to be removed
23273 "beforeremove" : true,
23275 * @event beforemove
23276 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23277 * @param {Tree} tree The owner tree
23278 * @param {Node} this This node
23279 * @param {Node} oldParent The parent of this node
23280 * @param {Node} newParent The new parent this node is moving to
23281 * @param {Number} index The index it is being moved to
23283 "beforemove" : true,
23285 * @event beforeinsert
23286 * Fires before a new child is inserted, return false to cancel the insert.
23287 * @param {Tree} tree The owner tree
23288 * @param {Node} this This node
23289 * @param {Node} node The child node to be inserted
23290 * @param {Node} refNode The child node the node is being inserted before
23292 "beforeinsert" : true
23294 this.listeners = this.attributes.listeners;
23295 Roo.data.Node.superclass.constructor.call(this);
23298 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23299 fireEvent : function(evtName){
23300 // first do standard event for this node
23301 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23304 // then bubble it up to the tree if the event wasn't cancelled
23305 var ot = this.getOwnerTree();
23307 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23315 * Returns true if this node is a leaf
23316 * @return {Boolean}
23318 isLeaf : function(){
23319 return this.leaf === true;
23323 setFirstChild : function(node){
23324 this.firstChild = node;
23328 setLastChild : function(node){
23329 this.lastChild = node;
23334 * Returns true if this node is the last child of its parent
23335 * @return {Boolean}
23337 isLast : function(){
23338 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23342 * Returns true if this node is the first child of its parent
23343 * @return {Boolean}
23345 isFirst : function(){
23346 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23349 hasChildNodes : function(){
23350 return !this.isLeaf() && this.childNodes.length > 0;
23354 * Insert node(s) as the last child node of this node.
23355 * @param {Node/Array} node The node or Array of nodes to append
23356 * @return {Node} The appended node if single append, or null if an array was passed
23358 appendChild : function(node){
23360 if(node instanceof Array){
23362 }else if(arguments.length > 1){
23365 // if passed an array or multiple args do them one by one
23367 for(var i = 0, len = multi.length; i < len; i++) {
23368 this.appendChild(multi[i]);
23371 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23374 var index = this.childNodes.length;
23375 var oldParent = node.parentNode;
23376 // it's a move, make sure we move it cleanly
23378 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23381 oldParent.removeChild(node);
23383 index = this.childNodes.length;
23385 this.setFirstChild(node);
23387 this.childNodes.push(node);
23388 node.parentNode = this;
23389 var ps = this.childNodes[index-1];
23391 node.previousSibling = ps;
23392 ps.nextSibling = node;
23394 node.previousSibling = null;
23396 node.nextSibling = null;
23397 this.setLastChild(node);
23398 node.setOwnerTree(this.getOwnerTree());
23399 this.fireEvent("append", this.ownerTree, this, node, index);
23401 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23408 * Removes a child node from this node.
23409 * @param {Node} node The node to remove
23410 * @return {Node} The removed node
23412 removeChild : function(node){
23413 var index = this.childNodes.indexOf(node);
23417 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23421 // remove it from childNodes collection
23422 this.childNodes.splice(index, 1);
23425 if(node.previousSibling){
23426 node.previousSibling.nextSibling = node.nextSibling;
23428 if(node.nextSibling){
23429 node.nextSibling.previousSibling = node.previousSibling;
23432 // update child refs
23433 if(this.firstChild == node){
23434 this.setFirstChild(node.nextSibling);
23436 if(this.lastChild == node){
23437 this.setLastChild(node.previousSibling);
23440 node.setOwnerTree(null);
23441 // clear any references from the node
23442 node.parentNode = null;
23443 node.previousSibling = null;
23444 node.nextSibling = null;
23445 this.fireEvent("remove", this.ownerTree, this, node);
23450 * Inserts the first node before the second node in this nodes childNodes collection.
23451 * @param {Node} node The node to insert
23452 * @param {Node} refNode The node to insert before (if null the node is appended)
23453 * @return {Node} The inserted node
23455 insertBefore : function(node, refNode){
23456 if(!refNode){ // like standard Dom, refNode can be null for append
23457 return this.appendChild(node);
23460 if(node == refNode){
23464 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23467 var index = this.childNodes.indexOf(refNode);
23468 var oldParent = node.parentNode;
23469 var refIndex = index;
23471 // when moving internally, indexes will change after remove
23472 if(oldParent == this && this.childNodes.indexOf(node) < index){
23476 // it's a move, make sure we move it cleanly
23478 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23481 oldParent.removeChild(node);
23484 this.setFirstChild(node);
23486 this.childNodes.splice(refIndex, 0, node);
23487 node.parentNode = this;
23488 var ps = this.childNodes[refIndex-1];
23490 node.previousSibling = ps;
23491 ps.nextSibling = node;
23493 node.previousSibling = null;
23495 node.nextSibling = refNode;
23496 refNode.previousSibling = node;
23497 node.setOwnerTree(this.getOwnerTree());
23498 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23500 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23506 * Returns the child node at the specified index.
23507 * @param {Number} index
23510 item : function(index){
23511 return this.childNodes[index];
23515 * Replaces one child node in this node with another.
23516 * @param {Node} newChild The replacement node
23517 * @param {Node} oldChild The node to replace
23518 * @return {Node} The replaced node
23520 replaceChild : function(newChild, oldChild){
23521 this.insertBefore(newChild, oldChild);
23522 this.removeChild(oldChild);
23527 * Returns the index of a child node
23528 * @param {Node} node
23529 * @return {Number} The index of the node or -1 if it was not found
23531 indexOf : function(child){
23532 return this.childNodes.indexOf(child);
23536 * Returns the tree this node is in.
23539 getOwnerTree : function(){
23540 // if it doesn't have one, look for one
23541 if(!this.ownerTree){
23545 this.ownerTree = p.ownerTree;
23551 return this.ownerTree;
23555 * Returns depth of this node (the root node has a depth of 0)
23558 getDepth : function(){
23561 while(p.parentNode){
23569 setOwnerTree : function(tree){
23570 // if it's move, we need to update everyone
23571 if(tree != this.ownerTree){
23572 if(this.ownerTree){
23573 this.ownerTree.unregisterNode(this);
23575 this.ownerTree = tree;
23576 var cs = this.childNodes;
23577 for(var i = 0, len = cs.length; i < len; i++) {
23578 cs[i].setOwnerTree(tree);
23581 tree.registerNode(this);
23587 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23588 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23589 * @return {String} The path
23591 getPath : function(attr){
23592 attr = attr || "id";
23593 var p = this.parentNode;
23594 var b = [this.attributes[attr]];
23596 b.unshift(p.attributes[attr]);
23599 var sep = this.getOwnerTree().pathSeparator;
23600 return sep + b.join(sep);
23604 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23605 * function call will be the scope provided or the current node. The arguments to the function
23606 * will be the args provided or the current node. If the function returns false at any point,
23607 * the bubble is stopped.
23608 * @param {Function} fn The function to call
23609 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23610 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23612 bubble : function(fn, scope, args){
23615 if(fn.call(scope || p, args || p) === false){
23623 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23624 * function call will be the scope provided or the current node. The arguments to the function
23625 * will be the args provided or the current node. If the function returns false at any point,
23626 * the cascade is stopped on that branch.
23627 * @param {Function} fn The function to call
23628 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23629 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23631 cascade : function(fn, scope, args){
23632 if(fn.call(scope || this, args || this) !== false){
23633 var cs = this.childNodes;
23634 for(var i = 0, len = cs.length; i < len; i++) {
23635 cs[i].cascade(fn, scope, args);
23641 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23642 * function call will be the scope provided or the current node. The arguments to the function
23643 * will be the args provided or the current node. If the function returns false at any point,
23644 * the iteration stops.
23645 * @param {Function} fn The function to call
23646 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23647 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23649 eachChild : function(fn, scope, args){
23650 var cs = this.childNodes;
23651 for(var i = 0, len = cs.length; i < len; i++) {
23652 if(fn.call(scope || this, args || cs[i]) === false){
23659 * Finds the first child that has the attribute with the specified value.
23660 * @param {String} attribute The attribute name
23661 * @param {Mixed} value The value to search for
23662 * @return {Node} The found child or null if none was found
23664 findChild : function(attribute, value){
23665 var cs = this.childNodes;
23666 for(var i = 0, len = cs.length; i < len; i++) {
23667 if(cs[i].attributes[attribute] == value){
23675 * Finds the first child by a custom function. The child matches if the function passed
23677 * @param {Function} fn
23678 * @param {Object} scope (optional)
23679 * @return {Node} The found child or null if none was found
23681 findChildBy : function(fn, scope){
23682 var cs = this.childNodes;
23683 for(var i = 0, len = cs.length; i < len; i++) {
23684 if(fn.call(scope||cs[i], cs[i]) === true){
23692 * Sorts this nodes children using the supplied sort function
23693 * @param {Function} fn
23694 * @param {Object} scope (optional)
23696 sort : function(fn, scope){
23697 var cs = this.childNodes;
23698 var len = cs.length;
23700 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23702 for(var i = 0; i < len; i++){
23704 n.previousSibling = cs[i-1];
23705 n.nextSibling = cs[i+1];
23707 this.setFirstChild(n);
23710 this.setLastChild(n);
23717 * Returns true if this node is an ancestor (at any point) of the passed node.
23718 * @param {Node} node
23719 * @return {Boolean}
23721 contains : function(node){
23722 return node.isAncestor(this);
23726 * Returns true if the passed node is an ancestor (at any point) of this node.
23727 * @param {Node} node
23728 * @return {Boolean}
23730 isAncestor : function(node){
23731 var p = this.parentNode;
23741 toString : function(){
23742 return "[Node"+(this.id?" "+this.id:"")+"]";
23746 * Ext JS Library 1.1.1
23747 * Copyright(c) 2006-2007, Ext JS, LLC.
23749 * Originally Released Under LGPL - original licence link has changed is not relivant.
23752 * <script type="text/javascript">
23757 * @extends Roo.Element
23758 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23759 * automatic maintaining of shadow/shim positions.
23760 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23761 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23762 * you can pass a string with a CSS class name. False turns off the shadow.
23763 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23764 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23765 * @cfg {String} cls CSS class to add to the element
23766 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23767 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23769 * @param {Object} config An object with config options.
23770 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23773 Roo.Layer = function(config, existingEl){
23774 config = config || {};
23775 var dh = Roo.DomHelper;
23776 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23778 this.dom = Roo.getDom(existingEl);
23781 var o = config.dh || {tag: "div", cls: "x-layer"};
23782 this.dom = dh.append(pel, o);
23785 this.addClass(config.cls);
23787 this.constrain = config.constrain !== false;
23788 this.visibilityMode = Roo.Element.VISIBILITY;
23790 this.id = this.dom.id = config.id;
23792 this.id = Roo.id(this.dom);
23794 this.zindex = config.zindex || this.getZIndex();
23795 this.position("absolute", this.zindex);
23797 this.shadowOffset = config.shadowOffset || 4;
23798 this.shadow = new Roo.Shadow({
23799 offset : this.shadowOffset,
23800 mode : config.shadow
23803 this.shadowOffset = 0;
23805 this.useShim = config.shim !== false && Roo.useShims;
23806 this.useDisplay = config.useDisplay;
23810 var supr = Roo.Element.prototype;
23812 // shims are shared among layer to keep from having 100 iframes
23815 Roo.extend(Roo.Layer, Roo.Element, {
23817 getZIndex : function(){
23818 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23821 getShim : function(){
23828 var shim = shims.shift();
23830 shim = this.createShim();
23831 shim.enableDisplayMode('block');
23832 shim.dom.style.display = 'none';
23833 shim.dom.style.visibility = 'visible';
23835 var pn = this.dom.parentNode;
23836 if(shim.dom.parentNode != pn){
23837 pn.insertBefore(shim.dom, this.dom);
23839 shim.setStyle('z-index', this.getZIndex()-2);
23844 hideShim : function(){
23846 this.shim.setDisplayed(false);
23847 shims.push(this.shim);
23852 disableShadow : function(){
23854 this.shadowDisabled = true;
23855 this.shadow.hide();
23856 this.lastShadowOffset = this.shadowOffset;
23857 this.shadowOffset = 0;
23861 enableShadow : function(show){
23863 this.shadowDisabled = false;
23864 this.shadowOffset = this.lastShadowOffset;
23865 delete this.lastShadowOffset;
23873 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23874 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23875 sync : function(doShow){
23876 var sw = this.shadow;
23877 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23878 var sh = this.getShim();
23880 var w = this.getWidth(),
23881 h = this.getHeight();
23883 var l = this.getLeft(true),
23884 t = this.getTop(true);
23886 if(sw && !this.shadowDisabled){
23887 if(doShow && !sw.isVisible()){
23890 sw.realign(l, t, w, h);
23896 // fit the shim behind the shadow, so it is shimmed too
23897 var a = sw.adjusts, s = sh.dom.style;
23898 s.left = (Math.min(l, l+a.l))+"px";
23899 s.top = (Math.min(t, t+a.t))+"px";
23900 s.width = (w+a.w)+"px";
23901 s.height = (h+a.h)+"px";
23908 sh.setLeftTop(l, t);
23915 destroy : function(){
23918 this.shadow.hide();
23920 this.removeAllListeners();
23921 var pn = this.dom.parentNode;
23923 pn.removeChild(this.dom);
23925 Roo.Element.uncache(this.id);
23928 remove : function(){
23933 beginUpdate : function(){
23934 this.updating = true;
23938 endUpdate : function(){
23939 this.updating = false;
23944 hideUnders : function(negOffset){
23946 this.shadow.hide();
23952 constrainXY : function(){
23953 if(this.constrain){
23954 var vw = Roo.lib.Dom.getViewWidth(),
23955 vh = Roo.lib.Dom.getViewHeight();
23956 var s = Roo.get(document).getScroll();
23958 var xy = this.getXY();
23959 var x = xy[0], y = xy[1];
23960 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23961 // only move it if it needs it
23963 // first validate right/bottom
23964 if((x + w) > vw+s.left){
23965 x = vw - w - this.shadowOffset;
23968 if((y + h) > vh+s.top){
23969 y = vh - h - this.shadowOffset;
23972 // then make sure top/left isn't negative
23983 var ay = this.avoidY;
23984 if(y <= ay && (y+h) >= ay){
23990 supr.setXY.call(this, xy);
23996 isVisible : function(){
23997 return this.visible;
24001 showAction : function(){
24002 this.visible = true; // track visibility to prevent getStyle calls
24003 if(this.useDisplay === true){
24004 this.setDisplayed("");
24005 }else if(this.lastXY){
24006 supr.setXY.call(this, this.lastXY);
24007 }else if(this.lastLT){
24008 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24013 hideAction : function(){
24014 this.visible = false;
24015 if(this.useDisplay === true){
24016 this.setDisplayed(false);
24018 this.setLeftTop(-10000,-10000);
24022 // overridden Element method
24023 setVisible : function(v, a, d, c, e){
24028 var cb = function(){
24033 }.createDelegate(this);
24034 supr.setVisible.call(this, true, true, d, cb, e);
24037 this.hideUnders(true);
24046 }.createDelegate(this);
24048 supr.setVisible.call(this, v, a, d, cb, e);
24057 storeXY : function(xy){
24058 delete this.lastLT;
24062 storeLeftTop : function(left, top){
24063 delete this.lastXY;
24064 this.lastLT = [left, top];
24068 beforeFx : function(){
24069 this.beforeAction();
24070 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24074 afterFx : function(){
24075 Roo.Layer.superclass.afterFx.apply(this, arguments);
24076 this.sync(this.isVisible());
24080 beforeAction : function(){
24081 if(!this.updating && this.shadow){
24082 this.shadow.hide();
24086 // overridden Element method
24087 setLeft : function(left){
24088 this.storeLeftTop(left, this.getTop(true));
24089 supr.setLeft.apply(this, arguments);
24093 setTop : function(top){
24094 this.storeLeftTop(this.getLeft(true), top);
24095 supr.setTop.apply(this, arguments);
24099 setLeftTop : function(left, top){
24100 this.storeLeftTop(left, top);
24101 supr.setLeftTop.apply(this, arguments);
24105 setXY : function(xy, a, d, c, e){
24107 this.beforeAction();
24109 var cb = this.createCB(c);
24110 supr.setXY.call(this, xy, a, d, cb, e);
24117 createCB : function(c){
24128 // overridden Element method
24129 setX : function(x, a, d, c, e){
24130 this.setXY([x, this.getY()], a, d, c, e);
24133 // overridden Element method
24134 setY : function(y, a, d, c, e){
24135 this.setXY([this.getX(), y], a, d, c, e);
24138 // overridden Element method
24139 setSize : function(w, h, a, d, c, e){
24140 this.beforeAction();
24141 var cb = this.createCB(c);
24142 supr.setSize.call(this, w, h, a, d, cb, e);
24148 // overridden Element method
24149 setWidth : function(w, a, d, c, e){
24150 this.beforeAction();
24151 var cb = this.createCB(c);
24152 supr.setWidth.call(this, w, a, d, cb, e);
24158 // overridden Element method
24159 setHeight : function(h, a, d, c, e){
24160 this.beforeAction();
24161 var cb = this.createCB(c);
24162 supr.setHeight.call(this, h, a, d, cb, e);
24168 // overridden Element method
24169 setBounds : function(x, y, w, h, a, d, c, e){
24170 this.beforeAction();
24171 var cb = this.createCB(c);
24173 this.storeXY([x, y]);
24174 supr.setXY.call(this, [x, y]);
24175 supr.setSize.call(this, w, h, a, d, cb, e);
24178 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24184 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24185 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24186 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24187 * @param {Number} zindex The new z-index to set
24188 * @return {this} The Layer
24190 setZIndex : function(zindex){
24191 this.zindex = zindex;
24192 this.setStyle("z-index", zindex + 2);
24194 this.shadow.setZIndex(zindex + 1);
24197 this.shim.setStyle("z-index", zindex);
24203 * Ext JS Library 1.1.1
24204 * Copyright(c) 2006-2007, Ext JS, LLC.
24206 * Originally Released Under LGPL - original licence link has changed is not relivant.
24209 * <script type="text/javascript">
24214 * @class Roo.Shadow
24215 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24216 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24217 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24219 * Create a new Shadow
24220 * @param {Object} config The config object
24222 Roo.Shadow = function(config){
24223 Roo.apply(this, config);
24224 if(typeof this.mode != "string"){
24225 this.mode = this.defaultMode;
24227 var o = this.offset, a = {h: 0};
24228 var rad = Math.floor(this.offset/2);
24229 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24235 a.l -= this.offset + rad;
24236 a.t -= this.offset + rad;
24247 a.l -= (this.offset - rad);
24248 a.t -= this.offset + rad;
24250 a.w -= (this.offset - rad)*2;
24261 a.l -= (this.offset - rad);
24262 a.t -= (this.offset - rad);
24264 a.w -= (this.offset + rad + 1);
24265 a.h -= (this.offset + rad);
24274 Roo.Shadow.prototype = {
24276 * @cfg {String} mode
24277 * The shadow display mode. Supports the following options:<br />
24278 * sides: Shadow displays on both sides and bottom only<br />
24279 * frame: Shadow displays equally on all four sides<br />
24280 * drop: Traditional bottom-right drop shadow (default)
24283 * @cfg {String} offset
24284 * The number of pixels to offset the shadow from the element (defaults to 4)
24289 defaultMode: "drop",
24292 * Displays the shadow under the target element
24293 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24295 show : function(target){
24296 target = Roo.get(target);
24298 this.el = Roo.Shadow.Pool.pull();
24299 if(this.el.dom.nextSibling != target.dom){
24300 this.el.insertBefore(target);
24303 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24305 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24308 target.getLeft(true),
24309 target.getTop(true),
24313 this.el.dom.style.display = "block";
24317 * Returns true if the shadow is visible, else false
24319 isVisible : function(){
24320 return this.el ? true : false;
24324 * Direct alignment when values are already available. Show must be called at least once before
24325 * calling this method to ensure it is initialized.
24326 * @param {Number} left The target element left position
24327 * @param {Number} top The target element top position
24328 * @param {Number} width The target element width
24329 * @param {Number} height The target element height
24331 realign : function(l, t, w, h){
24335 var a = this.adjusts, d = this.el.dom, s = d.style;
24337 s.left = (l+a.l)+"px";
24338 s.top = (t+a.t)+"px";
24339 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24341 if(s.width != sws || s.height != shs){
24345 var cn = d.childNodes;
24346 var sww = Math.max(0, (sw-12))+"px";
24347 cn[0].childNodes[1].style.width = sww;
24348 cn[1].childNodes[1].style.width = sww;
24349 cn[2].childNodes[1].style.width = sww;
24350 cn[1].style.height = Math.max(0, (sh-12))+"px";
24356 * Hides this shadow
24360 this.el.dom.style.display = "none";
24361 Roo.Shadow.Pool.push(this.el);
24367 * Adjust the z-index of this shadow
24368 * @param {Number} zindex The new z-index
24370 setZIndex : function(z){
24373 this.el.setStyle("z-index", z);
24378 // Private utility class that manages the internal Shadow cache
24379 Roo.Shadow.Pool = function(){
24381 var markup = Roo.isIE ?
24382 '<div class="x-ie-shadow"></div>' :
24383 '<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>';
24386 var sh = p.shift();
24388 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24389 sh.autoBoxAdjust = false;
24394 push : function(sh){
24400 * Ext JS Library 1.1.1
24401 * Copyright(c) 2006-2007, Ext JS, LLC.
24403 * Originally Released Under LGPL - original licence link has changed is not relivant.
24406 * <script type="text/javascript">
24411 * @class Roo.SplitBar
24412 * @extends Roo.util.Observable
24413 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24417 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24418 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24419 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24420 split.minSize = 100;
24421 split.maxSize = 600;
24422 split.animate = true;
24423 split.on('moved', splitterMoved);
24426 * Create a new SplitBar
24427 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24428 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24429 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24430 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24431 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24432 position of the SplitBar).
24434 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24437 this.el = Roo.get(dragElement, true);
24438 this.el.dom.unselectable = "on";
24440 this.resizingEl = Roo.get(resizingElement, true);
24444 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24445 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24448 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24451 * The minimum size of the resizing element. (Defaults to 0)
24457 * The maximum size of the resizing element. (Defaults to 2000)
24460 this.maxSize = 2000;
24463 * Whether to animate the transition to the new size
24466 this.animate = false;
24469 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24472 this.useShim = false;
24477 if(!existingProxy){
24479 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24481 this.proxy = Roo.get(existingProxy).dom;
24484 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24487 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24490 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24493 this.dragSpecs = {};
24496 * @private The adapter to use to positon and resize elements
24498 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24499 this.adapter.init(this);
24501 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24503 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24504 this.el.addClass("x-splitbar-h");
24507 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24508 this.el.addClass("x-splitbar-v");
24514 * Fires when the splitter is moved (alias for {@link #event-moved})
24515 * @param {Roo.SplitBar} this
24516 * @param {Number} newSize the new width or height
24521 * Fires when the splitter is moved
24522 * @param {Roo.SplitBar} this
24523 * @param {Number} newSize the new width or height
24527 * @event beforeresize
24528 * Fires before the splitter is dragged
24529 * @param {Roo.SplitBar} this
24531 "beforeresize" : true,
24533 "beforeapply" : true
24536 Roo.util.Observable.call(this);
24539 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24540 onStartProxyDrag : function(x, y){
24541 this.fireEvent("beforeresize", this);
24543 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24545 o.enableDisplayMode("block");
24546 // all splitbars share the same overlay
24547 Roo.SplitBar.prototype.overlay = o;
24549 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24550 this.overlay.show();
24551 Roo.get(this.proxy).setDisplayed("block");
24552 var size = this.adapter.getElementSize(this);
24553 this.activeMinSize = this.getMinimumSize();;
24554 this.activeMaxSize = this.getMaximumSize();;
24555 var c1 = size - this.activeMinSize;
24556 var c2 = Math.max(this.activeMaxSize - size, 0);
24557 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24558 this.dd.resetConstraints();
24559 this.dd.setXConstraint(
24560 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24561 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24563 this.dd.setYConstraint(0, 0);
24565 this.dd.resetConstraints();
24566 this.dd.setXConstraint(0, 0);
24567 this.dd.setYConstraint(
24568 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24569 this.placement == Roo.SplitBar.TOP ? c2 : c1
24572 this.dragSpecs.startSize = size;
24573 this.dragSpecs.startPoint = [x, y];
24574 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24578 * @private Called after the drag operation by the DDProxy
24580 onEndProxyDrag : function(e){
24581 Roo.get(this.proxy).setDisplayed(false);
24582 var endPoint = Roo.lib.Event.getXY(e);
24584 this.overlay.hide();
24587 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24588 newSize = this.dragSpecs.startSize +
24589 (this.placement == Roo.SplitBar.LEFT ?
24590 endPoint[0] - this.dragSpecs.startPoint[0] :
24591 this.dragSpecs.startPoint[0] - endPoint[0]
24594 newSize = this.dragSpecs.startSize +
24595 (this.placement == Roo.SplitBar.TOP ?
24596 endPoint[1] - this.dragSpecs.startPoint[1] :
24597 this.dragSpecs.startPoint[1] - endPoint[1]
24600 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24601 if(newSize != this.dragSpecs.startSize){
24602 if(this.fireEvent('beforeapply', this, newSize) !== false){
24603 this.adapter.setElementSize(this, newSize);
24604 this.fireEvent("moved", this, newSize);
24605 this.fireEvent("resize", this, newSize);
24611 * Get the adapter this SplitBar uses
24612 * @return The adapter object
24614 getAdapter : function(){
24615 return this.adapter;
24619 * Set the adapter this SplitBar uses
24620 * @param {Object} adapter A SplitBar adapter object
24622 setAdapter : function(adapter){
24623 this.adapter = adapter;
24624 this.adapter.init(this);
24628 * Gets the minimum size for the resizing element
24629 * @return {Number} The minimum size
24631 getMinimumSize : function(){
24632 return this.minSize;
24636 * Sets the minimum size for the resizing element
24637 * @param {Number} minSize The minimum size
24639 setMinimumSize : function(minSize){
24640 this.minSize = minSize;
24644 * Gets the maximum size for the resizing element
24645 * @return {Number} The maximum size
24647 getMaximumSize : function(){
24648 return this.maxSize;
24652 * Sets the maximum size for the resizing element
24653 * @param {Number} maxSize The maximum size
24655 setMaximumSize : function(maxSize){
24656 this.maxSize = maxSize;
24660 * Sets the initialize size for the resizing element
24661 * @param {Number} size The initial size
24663 setCurrentSize : function(size){
24664 var oldAnimate = this.animate;
24665 this.animate = false;
24666 this.adapter.setElementSize(this, size);
24667 this.animate = oldAnimate;
24671 * Destroy this splitbar.
24672 * @param {Boolean} removeEl True to remove the element
24674 destroy : function(removeEl){
24676 this.shim.remove();
24679 this.proxy.parentNode.removeChild(this.proxy);
24687 * @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.
24689 Roo.SplitBar.createProxy = function(dir){
24690 var proxy = new Roo.Element(document.createElement("div"));
24691 proxy.unselectable();
24692 var cls = 'x-splitbar-proxy';
24693 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24694 document.body.appendChild(proxy.dom);
24699 * @class Roo.SplitBar.BasicLayoutAdapter
24700 * Default Adapter. It assumes the splitter and resizing element are not positioned
24701 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24703 Roo.SplitBar.BasicLayoutAdapter = function(){
24706 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24707 // do nothing for now
24708 init : function(s){
24712 * Called before drag operations to get the current size of the resizing element.
24713 * @param {Roo.SplitBar} s The SplitBar using this adapter
24715 getElementSize : function(s){
24716 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24717 return s.resizingEl.getWidth();
24719 return s.resizingEl.getHeight();
24724 * Called after drag operations to set the size of the resizing element.
24725 * @param {Roo.SplitBar} s The SplitBar using this adapter
24726 * @param {Number} newSize The new size to set
24727 * @param {Function} onComplete A function to be invoked when resizing is complete
24729 setElementSize : function(s, newSize, onComplete){
24730 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24732 s.resizingEl.setWidth(newSize);
24734 onComplete(s, newSize);
24737 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24742 s.resizingEl.setHeight(newSize);
24744 onComplete(s, newSize);
24747 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24754 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24755 * @extends Roo.SplitBar.BasicLayoutAdapter
24756 * Adapter that moves the splitter element to align with the resized sizing element.
24757 * Used with an absolute positioned SplitBar.
24758 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24759 * document.body, make sure you assign an id to the body element.
24761 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24762 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24763 this.container = Roo.get(container);
24766 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24767 init : function(s){
24768 this.basic.init(s);
24771 getElementSize : function(s){
24772 return this.basic.getElementSize(s);
24775 setElementSize : function(s, newSize, onComplete){
24776 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24779 moveSplitter : function(s){
24780 var yes = Roo.SplitBar;
24781 switch(s.placement){
24783 s.el.setX(s.resizingEl.getRight());
24786 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24789 s.el.setY(s.resizingEl.getBottom());
24792 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24799 * Orientation constant - Create a vertical SplitBar
24803 Roo.SplitBar.VERTICAL = 1;
24806 * Orientation constant - Create a horizontal SplitBar
24810 Roo.SplitBar.HORIZONTAL = 2;
24813 * Placement constant - The resizing element is to the left of the splitter element
24817 Roo.SplitBar.LEFT = 1;
24820 * Placement constant - The resizing element is to the right of the splitter element
24824 Roo.SplitBar.RIGHT = 2;
24827 * Placement constant - The resizing element is positioned above the splitter element
24831 Roo.SplitBar.TOP = 3;
24834 * Placement constant - The resizing element is positioned under splitter element
24838 Roo.SplitBar.BOTTOM = 4;
24841 * Ext JS Library 1.1.1
24842 * Copyright(c) 2006-2007, Ext JS, LLC.
24844 * Originally Released Under LGPL - original licence link has changed is not relivant.
24847 * <script type="text/javascript">
24852 * @extends Roo.util.Observable
24853 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24854 * This class also supports single and multi selection modes. <br>
24855 * Create a data model bound view:
24857 var store = new Roo.data.Store(...);
24859 var view = new Roo.View({
24861 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24863 singleSelect: true,
24864 selectedClass: "ydataview-selected",
24868 // listen for node click?
24869 view.on("click", function(vw, index, node, e){
24870 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24874 dataModel.load("foobar.xml");
24876 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24878 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24879 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24881 * Note: old style constructor is still suported (container, template, config)
24884 * Create a new View
24885 * @param {Object} config The config object
24888 Roo.View = function(config, depreciated_tpl, depreciated_config){
24890 this.parent = false;
24892 if (typeof(depreciated_tpl) == 'undefined') {
24893 // new way.. - universal constructor.
24894 Roo.apply(this, config);
24895 this.el = Roo.get(this.el);
24898 this.el = Roo.get(config);
24899 this.tpl = depreciated_tpl;
24900 Roo.apply(this, depreciated_config);
24902 this.wrapEl = this.el.wrap().wrap();
24903 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24906 if(typeof(this.tpl) == "string"){
24907 this.tpl = new Roo.Template(this.tpl);
24909 // support xtype ctors..
24910 this.tpl = new Roo.factory(this.tpl, Roo);
24914 this.tpl.compile();
24919 * @event beforeclick
24920 * Fires before a click is processed. Returns false to cancel the default action.
24921 * @param {Roo.View} this
24922 * @param {Number} index The index of the target node
24923 * @param {HTMLElement} node The target node
24924 * @param {Roo.EventObject} e The raw event object
24926 "beforeclick" : true,
24929 * Fires when a template node is clicked.
24930 * @param {Roo.View} this
24931 * @param {Number} index The index of the target node
24932 * @param {HTMLElement} node The target node
24933 * @param {Roo.EventObject} e The raw event object
24938 * Fires when a template node is double clicked.
24939 * @param {Roo.View} this
24940 * @param {Number} index The index of the target node
24941 * @param {HTMLElement} node The target node
24942 * @param {Roo.EventObject} e The raw event object
24946 * @event contextmenu
24947 * Fires when a template node is right clicked.
24948 * @param {Roo.View} this
24949 * @param {Number} index The index of the target node
24950 * @param {HTMLElement} node The target node
24951 * @param {Roo.EventObject} e The raw event object
24953 "contextmenu" : true,
24955 * @event selectionchange
24956 * Fires when the selected nodes change.
24957 * @param {Roo.View} this
24958 * @param {Array} selections Array of the selected nodes
24960 "selectionchange" : true,
24963 * @event beforeselect
24964 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24965 * @param {Roo.View} this
24966 * @param {HTMLElement} node The node to be selected
24967 * @param {Array} selections Array of currently selected nodes
24969 "beforeselect" : true,
24971 * @event preparedata
24972 * Fires on every row to render, to allow you to change the data.
24973 * @param {Roo.View} this
24974 * @param {Object} data to be rendered (change this)
24976 "preparedata" : true
24984 "click": this.onClick,
24985 "dblclick": this.onDblClick,
24986 "contextmenu": this.onContextMenu,
24990 this.selections = [];
24992 this.cmp = new Roo.CompositeElementLite([]);
24994 this.store = Roo.factory(this.store, Roo.data);
24995 this.setStore(this.store, true);
24998 if ( this.footer && this.footer.xtype) {
25000 var fctr = this.wrapEl.appendChild(document.createElement("div"));
25002 this.footer.dataSource = this.store;
25003 this.footer.container = fctr;
25004 this.footer = Roo.factory(this.footer, Roo);
25005 fctr.insertFirst(this.el);
25007 // this is a bit insane - as the paging toolbar seems to detach the el..
25008 // dom.parentNode.parentNode.parentNode
25009 // they get detached?
25013 Roo.View.superclass.constructor.call(this);
25018 Roo.extend(Roo.View, Roo.util.Observable, {
25021 * @cfg {Roo.data.Store} store Data store to load data from.
25026 * @cfg {String|Roo.Element} el The container element.
25031 * @cfg {String|Roo.Template} tpl The template used by this View
25035 * @cfg {String} dataName the named area of the template to use as the data area
25036 * Works with domtemplates roo-name="name"
25040 * @cfg {String} selectedClass The css class to add to selected nodes
25042 selectedClass : "x-view-selected",
25044 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25049 * @cfg {String} text to display on mask (default Loading)
25053 * @cfg {Boolean} multiSelect Allow multiple selection
25055 multiSelect : false,
25057 * @cfg {Boolean} singleSelect Allow single selection
25059 singleSelect: false,
25062 * @cfg {Boolean} toggleSelect - selecting
25064 toggleSelect : false,
25067 * @cfg {Boolean} tickable - selecting
25072 * Returns the element this view is bound to.
25073 * @return {Roo.Element}
25075 getEl : function(){
25076 return this.wrapEl;
25082 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25084 refresh : function(){
25085 //Roo.log('refresh');
25088 // if we are using something like 'domtemplate', then
25089 // the what gets used is:
25090 // t.applySubtemplate(NAME, data, wrapping data..)
25091 // the outer template then get' applied with
25092 // the store 'extra data'
25093 // and the body get's added to the
25094 // roo-name="data" node?
25095 // <span class='roo-tpl-{name}'></span> ?????
25099 this.clearSelections();
25100 this.el.update("");
25102 var records = this.store.getRange();
25103 if(records.length < 1) {
25105 // is this valid?? = should it render a template??
25107 this.el.update(this.emptyText);
25111 if (this.dataName) {
25112 this.el.update(t.apply(this.store.meta)); //????
25113 el = this.el.child('.roo-tpl-' + this.dataName);
25116 for(var i = 0, len = records.length; i < len; i++){
25117 var data = this.prepareData(records[i].data, i, records[i]);
25118 this.fireEvent("preparedata", this, data, i, records[i]);
25120 var d = Roo.apply({}, data);
25123 Roo.apply(d, {'roo-id' : Roo.id()});
25127 Roo.each(this.parent.item, function(item){
25128 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25131 Roo.apply(d, {'roo-data-checked' : 'checked'});
25135 html[html.length] = Roo.util.Format.trim(
25137 t.applySubtemplate(this.dataName, d, this.store.meta) :
25144 el.update(html.join(""));
25145 this.nodes = el.dom.childNodes;
25146 this.updateIndexes(0);
25151 * Function to override to reformat the data that is sent to
25152 * the template for each node.
25153 * DEPRICATED - use the preparedata event handler.
25154 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25155 * a JSON object for an UpdateManager bound view).
25157 prepareData : function(data, index, record)
25159 this.fireEvent("preparedata", this, data, index, record);
25163 onUpdate : function(ds, record){
25164 // Roo.log('on update');
25165 this.clearSelections();
25166 var index = this.store.indexOf(record);
25167 var n = this.nodes[index];
25168 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25169 n.parentNode.removeChild(n);
25170 this.updateIndexes(index, index);
25176 onAdd : function(ds, records, index)
25178 //Roo.log(['on Add', ds, records, index] );
25179 this.clearSelections();
25180 if(this.nodes.length == 0){
25184 var n = this.nodes[index];
25185 for(var i = 0, len = records.length; i < len; i++){
25186 var d = this.prepareData(records[i].data, i, records[i]);
25188 this.tpl.insertBefore(n, d);
25191 this.tpl.append(this.el, d);
25194 this.updateIndexes(index);
25197 onRemove : function(ds, record, index){
25198 // Roo.log('onRemove');
25199 this.clearSelections();
25200 var el = this.dataName ?
25201 this.el.child('.roo-tpl-' + this.dataName) :
25204 el.dom.removeChild(this.nodes[index]);
25205 this.updateIndexes(index);
25209 * Refresh an individual node.
25210 * @param {Number} index
25212 refreshNode : function(index){
25213 this.onUpdate(this.store, this.store.getAt(index));
25216 updateIndexes : function(startIndex, endIndex){
25217 var ns = this.nodes;
25218 startIndex = startIndex || 0;
25219 endIndex = endIndex || ns.length - 1;
25220 for(var i = startIndex; i <= endIndex; i++){
25221 ns[i].nodeIndex = i;
25226 * Changes the data store this view uses and refresh the view.
25227 * @param {Store} store
25229 setStore : function(store, initial){
25230 if(!initial && this.store){
25231 this.store.un("datachanged", this.refresh);
25232 this.store.un("add", this.onAdd);
25233 this.store.un("remove", this.onRemove);
25234 this.store.un("update", this.onUpdate);
25235 this.store.un("clear", this.refresh);
25236 this.store.un("beforeload", this.onBeforeLoad);
25237 this.store.un("load", this.onLoad);
25238 this.store.un("loadexception", this.onLoad);
25242 store.on("datachanged", this.refresh, this);
25243 store.on("add", this.onAdd, this);
25244 store.on("remove", this.onRemove, this);
25245 store.on("update", this.onUpdate, this);
25246 store.on("clear", this.refresh, this);
25247 store.on("beforeload", this.onBeforeLoad, this);
25248 store.on("load", this.onLoad, this);
25249 store.on("loadexception", this.onLoad, this);
25257 * onbeforeLoad - masks the loading area.
25260 onBeforeLoad : function(store,opts)
25262 //Roo.log('onBeforeLoad');
25264 this.el.update("");
25266 this.el.mask(this.mask ? this.mask : "Loading" );
25268 onLoad : function ()
25275 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25276 * @param {HTMLElement} node
25277 * @return {HTMLElement} The template node
25279 findItemFromChild : function(node){
25280 var el = this.dataName ?
25281 this.el.child('.roo-tpl-' + this.dataName,true) :
25284 if(!node || node.parentNode == el){
25287 var p = node.parentNode;
25288 while(p && p != el){
25289 if(p.parentNode == el){
25298 onClick : function(e){
25299 var item = this.findItemFromChild(e.getTarget());
25301 var index = this.indexOf(item);
25302 if(this.onItemClick(item, index, e) !== false){
25303 this.fireEvent("click", this, index, item, e);
25306 this.clearSelections();
25311 onContextMenu : function(e){
25312 var item = this.findItemFromChild(e.getTarget());
25314 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25319 onDblClick : function(e){
25320 var item = this.findItemFromChild(e.getTarget());
25322 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25326 onItemClick : function(item, index, e)
25328 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25331 if (this.toggleSelect) {
25332 var m = this.isSelected(item) ? 'unselect' : 'select';
25335 _t[m](item, true, false);
25338 if(this.multiSelect || this.singleSelect){
25339 if(this.multiSelect && e.shiftKey && this.lastSelection){
25340 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25342 this.select(item, this.multiSelect && e.ctrlKey);
25343 this.lastSelection = item;
25346 if(!this.tickable){
25347 e.preventDefault();
25355 * Get the number of selected nodes.
25358 getSelectionCount : function(){
25359 return this.selections.length;
25363 * Get the currently selected nodes.
25364 * @return {Array} An array of HTMLElements
25366 getSelectedNodes : function(){
25367 return this.selections;
25371 * Get the indexes of the selected nodes.
25374 getSelectedIndexes : function(){
25375 var indexes = [], s = this.selections;
25376 for(var i = 0, len = s.length; i < len; i++){
25377 indexes.push(s[i].nodeIndex);
25383 * Clear all selections
25384 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25386 clearSelections : function(suppressEvent){
25387 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25388 this.cmp.elements = this.selections;
25389 this.cmp.removeClass(this.selectedClass);
25390 this.selections = [];
25391 if(!suppressEvent){
25392 this.fireEvent("selectionchange", this, this.selections);
25398 * Returns true if the passed node is selected
25399 * @param {HTMLElement/Number} node The node or node index
25400 * @return {Boolean}
25402 isSelected : function(node){
25403 var s = this.selections;
25407 node = this.getNode(node);
25408 return s.indexOf(node) !== -1;
25413 * @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
25414 * @param {Boolean} keepExisting (optional) true to keep existing selections
25415 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25417 select : function(nodeInfo, keepExisting, suppressEvent){
25418 if(nodeInfo instanceof Array){
25420 this.clearSelections(true);
25422 for(var i = 0, len = nodeInfo.length; i < len; i++){
25423 this.select(nodeInfo[i], true, true);
25427 var node = this.getNode(nodeInfo);
25428 if(!node || this.isSelected(node)){
25429 return; // already selected.
25432 this.clearSelections(true);
25435 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25436 Roo.fly(node).addClass(this.selectedClass);
25437 this.selections.push(node);
25438 if(!suppressEvent){
25439 this.fireEvent("selectionchange", this, this.selections);
25447 * @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
25448 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25449 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25451 unselect : function(nodeInfo, keepExisting, suppressEvent)
25453 if(nodeInfo instanceof Array){
25454 Roo.each(this.selections, function(s) {
25455 this.unselect(s, nodeInfo);
25459 var node = this.getNode(nodeInfo);
25460 if(!node || !this.isSelected(node)){
25461 //Roo.log("not selected");
25462 return; // not selected.
25466 Roo.each(this.selections, function(s) {
25468 Roo.fly(node).removeClass(this.selectedClass);
25475 this.selections= ns;
25476 this.fireEvent("selectionchange", this, this.selections);
25480 * Gets a template node.
25481 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25482 * @return {HTMLElement} The node or null if it wasn't found
25484 getNode : function(nodeInfo){
25485 if(typeof nodeInfo == "string"){
25486 return document.getElementById(nodeInfo);
25487 }else if(typeof nodeInfo == "number"){
25488 return this.nodes[nodeInfo];
25494 * Gets a range template nodes.
25495 * @param {Number} startIndex
25496 * @param {Number} endIndex
25497 * @return {Array} An array of nodes
25499 getNodes : function(start, end){
25500 var ns = this.nodes;
25501 start = start || 0;
25502 end = typeof end == "undefined" ? ns.length - 1 : end;
25505 for(var i = start; i <= end; i++){
25509 for(var i = start; i >= end; i--){
25517 * Finds the index of the passed node
25518 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25519 * @return {Number} The index of the node or -1
25521 indexOf : function(node){
25522 node = this.getNode(node);
25523 if(typeof node.nodeIndex == "number"){
25524 return node.nodeIndex;
25526 var ns = this.nodes;
25527 for(var i = 0, len = ns.length; i < len; i++){
25537 * Ext JS Library 1.1.1
25538 * Copyright(c) 2006-2007, Ext JS, LLC.
25540 * Originally Released Under LGPL - original licence link has changed is not relivant.
25543 * <script type="text/javascript">
25547 * @class Roo.JsonView
25548 * @extends Roo.View
25549 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25551 var view = new Roo.JsonView({
25552 container: "my-element",
25553 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25558 // listen for node click?
25559 view.on("click", function(vw, index, node, e){
25560 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25563 // direct load of JSON data
25564 view.load("foobar.php");
25566 // Example from my blog list
25567 var tpl = new Roo.Template(
25568 '<div class="entry">' +
25569 '<a class="entry-title" href="{link}">{title}</a>' +
25570 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25571 "</div><hr />"
25574 var moreView = new Roo.JsonView({
25575 container : "entry-list",
25579 moreView.on("beforerender", this.sortEntries, this);
25581 url: "/blog/get-posts.php",
25582 params: "allposts=true",
25583 text: "Loading Blog Entries..."
25587 * Note: old code is supported with arguments : (container, template, config)
25591 * Create a new JsonView
25593 * @param {Object} config The config object
25596 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25599 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25601 var um = this.el.getUpdateManager();
25602 um.setRenderer(this);
25603 um.on("update", this.onLoad, this);
25604 um.on("failure", this.onLoadException, this);
25607 * @event beforerender
25608 * Fires before rendering of the downloaded JSON data.
25609 * @param {Roo.JsonView} this
25610 * @param {Object} data The JSON data loaded
25614 * Fires when data is loaded.
25615 * @param {Roo.JsonView} this
25616 * @param {Object} data The JSON data loaded
25617 * @param {Object} response The raw Connect response object
25620 * @event loadexception
25621 * Fires when loading fails.
25622 * @param {Roo.JsonView} this
25623 * @param {Object} response The raw Connect response object
25626 'beforerender' : true,
25628 'loadexception' : true
25631 Roo.extend(Roo.JsonView, Roo.View, {
25633 * @type {String} The root property in the loaded JSON object that contains the data
25638 * Refreshes the view.
25640 refresh : function(){
25641 this.clearSelections();
25642 this.el.update("");
25644 var o = this.jsonData;
25645 if(o && o.length > 0){
25646 for(var i = 0, len = o.length; i < len; i++){
25647 var data = this.prepareData(o[i], i, o);
25648 html[html.length] = this.tpl.apply(data);
25651 html.push(this.emptyText);
25653 this.el.update(html.join(""));
25654 this.nodes = this.el.dom.childNodes;
25655 this.updateIndexes(0);
25659 * 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.
25660 * @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:
25663 url: "your-url.php",
25664 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25665 callback: yourFunction,
25666 scope: yourObject, //(optional scope)
25669 text: "Loading...",
25674 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25675 * 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.
25676 * @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}
25677 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25678 * @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.
25681 var um = this.el.getUpdateManager();
25682 um.update.apply(um, arguments);
25685 render : function(el, response){
25686 this.clearSelections();
25687 this.el.update("");
25690 o = Roo.util.JSON.decode(response.responseText);
25693 o = o[this.jsonRoot];
25698 * The current JSON data or null
25701 this.beforeRender();
25706 * Get the number of records in the current JSON dataset
25709 getCount : function(){
25710 return this.jsonData ? this.jsonData.length : 0;
25714 * Returns the JSON object for the specified node(s)
25715 * @param {HTMLElement/Array} node The node or an array of nodes
25716 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25717 * you get the JSON object for the node
25719 getNodeData : function(node){
25720 if(node instanceof Array){
25722 for(var i = 0, len = node.length; i < len; i++){
25723 data.push(this.getNodeData(node[i]));
25727 return this.jsonData[this.indexOf(node)] || null;
25730 beforeRender : function(){
25731 this.snapshot = this.jsonData;
25733 this.sort.apply(this, this.sortInfo);
25735 this.fireEvent("beforerender", this, this.jsonData);
25738 onLoad : function(el, o){
25739 this.fireEvent("load", this, this.jsonData, o);
25742 onLoadException : function(el, o){
25743 this.fireEvent("loadexception", this, o);
25747 * Filter the data by a specific property.
25748 * @param {String} property A property on your JSON objects
25749 * @param {String/RegExp} value Either string that the property values
25750 * should start with, or a RegExp to test against the property
25752 filter : function(property, value){
25755 var ss = this.snapshot;
25756 if(typeof value == "string"){
25757 var vlen = value.length;
25759 this.clearFilter();
25762 value = value.toLowerCase();
25763 for(var i = 0, len = ss.length; i < len; i++){
25765 if(o[property].substr(0, vlen).toLowerCase() == value){
25769 } else if(value.exec){ // regex?
25770 for(var i = 0, len = ss.length; i < len; i++){
25772 if(value.test(o[property])){
25779 this.jsonData = data;
25785 * Filter by a function. The passed function will be called with each
25786 * object in the current dataset. If the function returns true the value is kept,
25787 * otherwise it is filtered.
25788 * @param {Function} fn
25789 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25791 filterBy : function(fn, scope){
25794 var ss = this.snapshot;
25795 for(var i = 0, len = ss.length; i < len; i++){
25797 if(fn.call(scope || this, o)){
25801 this.jsonData = data;
25807 * Clears the current filter.
25809 clearFilter : function(){
25810 if(this.snapshot && this.jsonData != this.snapshot){
25811 this.jsonData = this.snapshot;
25818 * Sorts the data for this view and refreshes it.
25819 * @param {String} property A property on your JSON objects to sort on
25820 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25821 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25823 sort : function(property, dir, sortType){
25824 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25827 var dsc = dir && dir.toLowerCase() == "desc";
25828 var f = function(o1, o2){
25829 var v1 = sortType ? sortType(o1[p]) : o1[p];
25830 var v2 = sortType ? sortType(o2[p]) : o2[p];
25833 return dsc ? +1 : -1;
25834 } else if(v1 > v2){
25835 return dsc ? -1 : +1;
25840 this.jsonData.sort(f);
25842 if(this.jsonData != this.snapshot){
25843 this.snapshot.sort(f);
25849 * Ext JS Library 1.1.1
25850 * Copyright(c) 2006-2007, Ext JS, LLC.
25852 * Originally Released Under LGPL - original licence link has changed is not relivant.
25855 * <script type="text/javascript">
25860 * @class Roo.ColorPalette
25861 * @extends Roo.Component
25862 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25863 * Here's an example of typical usage:
25865 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25866 cp.render('my-div');
25868 cp.on('select', function(palette, selColor){
25869 // do something with selColor
25873 * Create a new ColorPalette
25874 * @param {Object} config The config object
25876 Roo.ColorPalette = function(config){
25877 Roo.ColorPalette.superclass.constructor.call(this, config);
25881 * Fires when a color is selected
25882 * @param {ColorPalette} this
25883 * @param {String} color The 6-digit color hex code (without the # symbol)
25889 this.on("select", this.handler, this.scope, true);
25892 Roo.extend(Roo.ColorPalette, Roo.Component, {
25894 * @cfg {String} itemCls
25895 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25897 itemCls : "x-color-palette",
25899 * @cfg {String} value
25900 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25901 * the hex codes are case-sensitive.
25904 clickEvent:'click',
25906 ctype: "Roo.ColorPalette",
25909 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25911 allowReselect : false,
25914 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25915 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25916 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25917 * of colors with the width setting until the box is symmetrical.</p>
25918 * <p>You can override individual colors if needed:</p>
25920 var cp = new Roo.ColorPalette();
25921 cp.colors[0] = "FF0000"; // change the first box to red
25924 Or you can provide a custom array of your own for complete control:
25926 var cp = new Roo.ColorPalette();
25927 cp.colors = ["000000", "993300", "333300"];
25932 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25933 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25934 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25935 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25936 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25940 onRender : function(container, position){
25941 var t = new Roo.MasterTemplate(
25942 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25944 var c = this.colors;
25945 for(var i = 0, len = c.length; i < len; i++){
25948 var el = document.createElement("div");
25949 el.className = this.itemCls;
25951 container.dom.insertBefore(el, position);
25952 this.el = Roo.get(el);
25953 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25954 if(this.clickEvent != 'click'){
25955 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25960 afterRender : function(){
25961 Roo.ColorPalette.superclass.afterRender.call(this);
25963 var s = this.value;
25970 handleClick : function(e, t){
25971 e.preventDefault();
25972 if(!this.disabled){
25973 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25974 this.select(c.toUpperCase());
25979 * Selects the specified color in the palette (fires the select event)
25980 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25982 select : function(color){
25983 color = color.replace("#", "");
25984 if(color != this.value || this.allowReselect){
25987 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25989 el.child("a.color-"+color).addClass("x-color-palette-sel");
25990 this.value = color;
25991 this.fireEvent("select", this, color);
25996 * Ext JS Library 1.1.1
25997 * Copyright(c) 2006-2007, Ext JS, LLC.
25999 * Originally Released Under LGPL - original licence link has changed is not relivant.
26002 * <script type="text/javascript">
26006 * @class Roo.DatePicker
26007 * @extends Roo.Component
26008 * Simple date picker class.
26010 * Create a new DatePicker
26011 * @param {Object} config The config object
26013 Roo.DatePicker = function(config){
26014 Roo.DatePicker.superclass.constructor.call(this, config);
26016 this.value = config && config.value ?
26017 config.value.clearTime() : new Date().clearTime();
26022 * Fires when a date is selected
26023 * @param {DatePicker} this
26024 * @param {Date} date The selected date
26028 * @event monthchange
26029 * Fires when the displayed month changes
26030 * @param {DatePicker} this
26031 * @param {Date} date The selected month
26033 'monthchange': true
26037 this.on("select", this.handler, this.scope || this);
26039 // build the disabledDatesRE
26040 if(!this.disabledDatesRE && this.disabledDates){
26041 var dd = this.disabledDates;
26043 for(var i = 0; i < dd.length; i++){
26045 if(i != dd.length-1) re += "|";
26047 this.disabledDatesRE = new RegExp(re + ")");
26051 Roo.extend(Roo.DatePicker, Roo.Component, {
26053 * @cfg {String} todayText
26054 * The text to display on the button that selects the current date (defaults to "Today")
26056 todayText : "Today",
26058 * @cfg {String} okText
26059 * The text to display on the ok button
26061 okText : " OK ", //   to give the user extra clicking room
26063 * @cfg {String} cancelText
26064 * The text to display on the cancel button
26066 cancelText : "Cancel",
26068 * @cfg {String} todayTip
26069 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26071 todayTip : "{0} (Spacebar)",
26073 * @cfg {Date} minDate
26074 * Minimum allowable date (JavaScript date object, defaults to null)
26078 * @cfg {Date} maxDate
26079 * Maximum allowable date (JavaScript date object, defaults to null)
26083 * @cfg {String} minText
26084 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26086 minText : "This date is before the minimum date",
26088 * @cfg {String} maxText
26089 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26091 maxText : "This date is after the maximum date",
26093 * @cfg {String} format
26094 * The default date format string which can be overriden for localization support. The format must be
26095 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26099 * @cfg {Array} disabledDays
26100 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26102 disabledDays : null,
26104 * @cfg {String} disabledDaysText
26105 * The tooltip to display when the date falls on a disabled day (defaults to "")
26107 disabledDaysText : "",
26109 * @cfg {RegExp} disabledDatesRE
26110 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26112 disabledDatesRE : null,
26114 * @cfg {String} disabledDatesText
26115 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26117 disabledDatesText : "",
26119 * @cfg {Boolean} constrainToViewport
26120 * True to constrain the date picker to the viewport (defaults to true)
26122 constrainToViewport : true,
26124 * @cfg {Array} monthNames
26125 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26127 monthNames : Date.monthNames,
26129 * @cfg {Array} dayNames
26130 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26132 dayNames : Date.dayNames,
26134 * @cfg {String} nextText
26135 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26137 nextText: 'Next Month (Control+Right)',
26139 * @cfg {String} prevText
26140 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26142 prevText: 'Previous Month (Control+Left)',
26144 * @cfg {String} monthYearText
26145 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26147 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26149 * @cfg {Number} startDay
26150 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26154 * @cfg {Bool} showClear
26155 * Show a clear button (usefull for date form elements that can be blank.)
26161 * Sets the value of the date field
26162 * @param {Date} value The date to set
26164 setValue : function(value){
26165 var old = this.value;
26167 if (typeof(value) == 'string') {
26169 value = Date.parseDate(value, this.format);
26172 value = new Date();
26175 this.value = value.clearTime(true);
26177 this.update(this.value);
26182 * Gets the current selected value of the date field
26183 * @return {Date} The selected date
26185 getValue : function(){
26190 focus : function(){
26192 this.update(this.activeDate);
26197 onRender : function(container, position){
26200 '<table cellspacing="0">',
26201 '<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>',
26202 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26203 var dn = this.dayNames;
26204 for(var i = 0; i < 7; i++){
26205 var d = this.startDay+i;
26209 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26211 m[m.length] = "</tr></thead><tbody><tr>";
26212 for(var i = 0; i < 42; i++) {
26213 if(i % 7 == 0 && i != 0){
26214 m[m.length] = "</tr><tr>";
26216 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26218 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26219 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26221 var el = document.createElement("div");
26222 el.className = "x-date-picker";
26223 el.innerHTML = m.join("");
26225 container.dom.insertBefore(el, position);
26227 this.el = Roo.get(el);
26228 this.eventEl = Roo.get(el.firstChild);
26230 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26231 handler: this.showPrevMonth,
26233 preventDefault:true,
26237 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26238 handler: this.showNextMonth,
26240 preventDefault:true,
26244 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26246 this.monthPicker = this.el.down('div.x-date-mp');
26247 this.monthPicker.enableDisplayMode('block');
26249 var kn = new Roo.KeyNav(this.eventEl, {
26250 "left" : function(e){
26252 this.showPrevMonth() :
26253 this.update(this.activeDate.add("d", -1));
26256 "right" : function(e){
26258 this.showNextMonth() :
26259 this.update(this.activeDate.add("d", 1));
26262 "up" : function(e){
26264 this.showNextYear() :
26265 this.update(this.activeDate.add("d", -7));
26268 "down" : function(e){
26270 this.showPrevYear() :
26271 this.update(this.activeDate.add("d", 7));
26274 "pageUp" : function(e){
26275 this.showNextMonth();
26278 "pageDown" : function(e){
26279 this.showPrevMonth();
26282 "enter" : function(e){
26283 e.stopPropagation();
26290 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26292 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26294 this.el.unselectable();
26296 this.cells = this.el.select("table.x-date-inner tbody td");
26297 this.textNodes = this.el.query("table.x-date-inner tbody span");
26299 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26301 tooltip: this.monthYearText
26304 this.mbtn.on('click', this.showMonthPicker, this);
26305 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26308 var today = (new Date()).dateFormat(this.format);
26310 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26311 if (this.showClear) {
26312 baseTb.add( new Roo.Toolbar.Fill());
26315 text: String.format(this.todayText, today),
26316 tooltip: String.format(this.todayTip, today),
26317 handler: this.selectToday,
26321 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26324 if (this.showClear) {
26326 baseTb.add( new Roo.Toolbar.Fill());
26329 cls: 'x-btn-icon x-btn-clear',
26330 handler: function() {
26332 this.fireEvent("select", this, '');
26342 this.update(this.value);
26345 createMonthPicker : function(){
26346 if(!this.monthPicker.dom.firstChild){
26347 var buf = ['<table border="0" cellspacing="0">'];
26348 for(var i = 0; i < 6; i++){
26350 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26351 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26353 '<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>' :
26354 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26358 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26360 '</button><button type="button" class="x-date-mp-cancel">',
26362 '</button></td></tr>',
26365 this.monthPicker.update(buf.join(''));
26366 this.monthPicker.on('click', this.onMonthClick, this);
26367 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26369 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26370 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26372 this.mpMonths.each(function(m, a, i){
26375 m.dom.xmonth = 5 + Math.round(i * .5);
26377 m.dom.xmonth = Math.round((i-1) * .5);
26383 showMonthPicker : function(){
26384 this.createMonthPicker();
26385 var size = this.el.getSize();
26386 this.monthPicker.setSize(size);
26387 this.monthPicker.child('table').setSize(size);
26389 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26390 this.updateMPMonth(this.mpSelMonth);
26391 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26392 this.updateMPYear(this.mpSelYear);
26394 this.monthPicker.slideIn('t', {duration:.2});
26397 updateMPYear : function(y){
26399 var ys = this.mpYears.elements;
26400 for(var i = 1; i <= 10; i++){
26401 var td = ys[i-1], y2;
26403 y2 = y + Math.round(i * .5);
26404 td.firstChild.innerHTML = y2;
26407 y2 = y - (5-Math.round(i * .5));
26408 td.firstChild.innerHTML = y2;
26411 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26415 updateMPMonth : function(sm){
26416 this.mpMonths.each(function(m, a, i){
26417 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26421 selectMPMonth: function(m){
26425 onMonthClick : function(e, t){
26427 var el = new Roo.Element(t), pn;
26428 if(el.is('button.x-date-mp-cancel')){
26429 this.hideMonthPicker();
26431 else if(el.is('button.x-date-mp-ok')){
26432 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26433 this.hideMonthPicker();
26435 else if(pn = el.up('td.x-date-mp-month', 2)){
26436 this.mpMonths.removeClass('x-date-mp-sel');
26437 pn.addClass('x-date-mp-sel');
26438 this.mpSelMonth = pn.dom.xmonth;
26440 else if(pn = el.up('td.x-date-mp-year', 2)){
26441 this.mpYears.removeClass('x-date-mp-sel');
26442 pn.addClass('x-date-mp-sel');
26443 this.mpSelYear = pn.dom.xyear;
26445 else if(el.is('a.x-date-mp-prev')){
26446 this.updateMPYear(this.mpyear-10);
26448 else if(el.is('a.x-date-mp-next')){
26449 this.updateMPYear(this.mpyear+10);
26453 onMonthDblClick : function(e, t){
26455 var el = new Roo.Element(t), pn;
26456 if(pn = el.up('td.x-date-mp-month', 2)){
26457 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26458 this.hideMonthPicker();
26460 else if(pn = el.up('td.x-date-mp-year', 2)){
26461 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26462 this.hideMonthPicker();
26466 hideMonthPicker : function(disableAnim){
26467 if(this.monthPicker){
26468 if(disableAnim === true){
26469 this.monthPicker.hide();
26471 this.monthPicker.slideOut('t', {duration:.2});
26477 showPrevMonth : function(e){
26478 this.update(this.activeDate.add("mo", -1));
26482 showNextMonth : function(e){
26483 this.update(this.activeDate.add("mo", 1));
26487 showPrevYear : function(){
26488 this.update(this.activeDate.add("y", -1));
26492 showNextYear : function(){
26493 this.update(this.activeDate.add("y", 1));
26497 handleMouseWheel : function(e){
26498 var delta = e.getWheelDelta();
26500 this.showPrevMonth();
26502 } else if(delta < 0){
26503 this.showNextMonth();
26509 handleDateClick : function(e, t){
26511 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26512 this.setValue(new Date(t.dateValue));
26513 this.fireEvent("select", this, this.value);
26518 selectToday : function(){
26519 this.setValue(new Date().clearTime());
26520 this.fireEvent("select", this, this.value);
26524 update : function(date)
26526 var vd = this.activeDate;
26527 this.activeDate = date;
26529 var t = date.getTime();
26530 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26531 this.cells.removeClass("x-date-selected");
26532 this.cells.each(function(c){
26533 if(c.dom.firstChild.dateValue == t){
26534 c.addClass("x-date-selected");
26535 setTimeout(function(){
26536 try{c.dom.firstChild.focus();}catch(e){}
26545 var days = date.getDaysInMonth();
26546 var firstOfMonth = date.getFirstDateOfMonth();
26547 var startingPos = firstOfMonth.getDay()-this.startDay;
26549 if(startingPos <= this.startDay){
26553 var pm = date.add("mo", -1);
26554 var prevStart = pm.getDaysInMonth()-startingPos;
26556 var cells = this.cells.elements;
26557 var textEls = this.textNodes;
26558 days += startingPos;
26560 // convert everything to numbers so it's fast
26561 var day = 86400000;
26562 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26563 var today = new Date().clearTime().getTime();
26564 var sel = date.clearTime().getTime();
26565 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26566 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26567 var ddMatch = this.disabledDatesRE;
26568 var ddText = this.disabledDatesText;
26569 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26570 var ddaysText = this.disabledDaysText;
26571 var format = this.format;
26573 var setCellClass = function(cal, cell){
26575 var t = d.getTime();
26576 cell.firstChild.dateValue = t;
26578 cell.className += " x-date-today";
26579 cell.title = cal.todayText;
26582 cell.className += " x-date-selected";
26583 setTimeout(function(){
26584 try{cell.firstChild.focus();}catch(e){}
26589 cell.className = " x-date-disabled";
26590 cell.title = cal.minText;
26594 cell.className = " x-date-disabled";
26595 cell.title = cal.maxText;
26599 if(ddays.indexOf(d.getDay()) != -1){
26600 cell.title = ddaysText;
26601 cell.className = " x-date-disabled";
26604 if(ddMatch && format){
26605 var fvalue = d.dateFormat(format);
26606 if(ddMatch.test(fvalue)){
26607 cell.title = ddText.replace("%0", fvalue);
26608 cell.className = " x-date-disabled";
26614 for(; i < startingPos; i++) {
26615 textEls[i].innerHTML = (++prevStart);
26616 d.setDate(d.getDate()+1);
26617 cells[i].className = "x-date-prevday";
26618 setCellClass(this, cells[i]);
26620 for(; i < days; i++){
26621 intDay = i - startingPos + 1;
26622 textEls[i].innerHTML = (intDay);
26623 d.setDate(d.getDate()+1);
26624 cells[i].className = "x-date-active";
26625 setCellClass(this, cells[i]);
26628 for(; i < 42; i++) {
26629 textEls[i].innerHTML = (++extraDays);
26630 d.setDate(d.getDate()+1);
26631 cells[i].className = "x-date-nextday";
26632 setCellClass(this, cells[i]);
26635 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26636 this.fireEvent('monthchange', this, date);
26638 if(!this.internalRender){
26639 var main = this.el.dom.firstChild;
26640 var w = main.offsetWidth;
26641 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26642 Roo.fly(main).setWidth(w);
26643 this.internalRender = true;
26644 // opera does not respect the auto grow header center column
26645 // then, after it gets a width opera refuses to recalculate
26646 // without a second pass
26647 if(Roo.isOpera && !this.secondPass){
26648 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26649 this.secondPass = true;
26650 this.update.defer(10, this, [date]);
26658 * Ext JS Library 1.1.1
26659 * Copyright(c) 2006-2007, Ext JS, LLC.
26661 * Originally Released Under LGPL - original licence link has changed is not relivant.
26664 * <script type="text/javascript">
26667 * @class Roo.TabPanel
26668 * @extends Roo.util.Observable
26669 * A lightweight tab container.
26673 // basic tabs 1, built from existing content
26674 var tabs = new Roo.TabPanel("tabs1");
26675 tabs.addTab("script", "View Script");
26676 tabs.addTab("markup", "View Markup");
26677 tabs.activate("script");
26679 // more advanced tabs, built from javascript
26680 var jtabs = new Roo.TabPanel("jtabs");
26681 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26683 // set up the UpdateManager
26684 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26685 var updater = tab2.getUpdateManager();
26686 updater.setDefaultUrl("ajax1.htm");
26687 tab2.on('activate', updater.refresh, updater, true);
26689 // Use setUrl for Ajax loading
26690 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26691 tab3.setUrl("ajax2.htm", null, true);
26694 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26697 jtabs.activate("jtabs-1");
26700 * Create a new TabPanel.
26701 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26702 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26704 Roo.TabPanel = function(container, config){
26706 * The container element for this TabPanel.
26707 * @type Roo.Element
26709 this.el = Roo.get(container, true);
26711 if(typeof config == "boolean"){
26712 this.tabPosition = config ? "bottom" : "top";
26714 Roo.apply(this, config);
26717 if(this.tabPosition == "bottom"){
26718 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26719 this.el.addClass("x-tabs-bottom");
26721 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26722 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26723 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26725 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26727 if(this.tabPosition != "bottom"){
26728 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26729 * @type Roo.Element
26731 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26732 this.el.addClass("x-tabs-top");
26736 this.bodyEl.setStyle("position", "relative");
26738 this.active = null;
26739 this.activateDelegate = this.activate.createDelegate(this);
26744 * Fires when the active tab changes
26745 * @param {Roo.TabPanel} this
26746 * @param {Roo.TabPanelItem} activePanel The new active tab
26750 * @event beforetabchange
26751 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26752 * @param {Roo.TabPanel} this
26753 * @param {Object} e Set cancel to true on this object to cancel the tab change
26754 * @param {Roo.TabPanelItem} tab The tab being changed to
26756 "beforetabchange" : true
26759 Roo.EventManager.onWindowResize(this.onResize, this);
26760 this.cpad = this.el.getPadding("lr");
26761 this.hiddenCount = 0;
26764 // toolbar on the tabbar support...
26765 if (this.toolbar) {
26766 var tcfg = this.toolbar;
26767 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26768 this.toolbar = new Roo.Toolbar(tcfg);
26769 if (Roo.isSafari) {
26770 var tbl = tcfg.container.child('table', true);
26771 tbl.setAttribute('width', '100%');
26778 Roo.TabPanel.superclass.constructor.call(this);
26781 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26783 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26785 tabPosition : "top",
26787 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26789 currentTabWidth : 0,
26791 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26795 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26799 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26801 preferredTabWidth : 175,
26803 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26805 resizeTabs : false,
26807 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26809 monitorResize : true,
26811 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26816 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26817 * @param {String} id The id of the div to use <b>or create</b>
26818 * @param {String} text The text for the tab
26819 * @param {String} content (optional) Content to put in the TabPanelItem body
26820 * @param {Boolean} closable (optional) True to create a close icon on the tab
26821 * @return {Roo.TabPanelItem} The created TabPanelItem
26823 addTab : function(id, text, content, closable){
26824 var item = new Roo.TabPanelItem(this, id, text, closable);
26825 this.addTabItem(item);
26827 item.setContent(content);
26833 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26834 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26835 * @return {Roo.TabPanelItem}
26837 getTab : function(id){
26838 return this.items[id];
26842 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26843 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26845 hideTab : function(id){
26846 var t = this.items[id];
26849 this.hiddenCount++;
26850 this.autoSizeTabs();
26855 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26856 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26858 unhideTab : function(id){
26859 var t = this.items[id];
26861 t.setHidden(false);
26862 this.hiddenCount--;
26863 this.autoSizeTabs();
26868 * Adds an existing {@link Roo.TabPanelItem}.
26869 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26871 addTabItem : function(item){
26872 this.items[item.id] = item;
26873 this.items.push(item);
26874 if(this.resizeTabs){
26875 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26876 this.autoSizeTabs();
26883 * Removes a {@link Roo.TabPanelItem}.
26884 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26886 removeTab : function(id){
26887 var items = this.items;
26888 var tab = items[id];
26889 if(!tab) { return; }
26890 var index = items.indexOf(tab);
26891 if(this.active == tab && items.length > 1){
26892 var newTab = this.getNextAvailable(index);
26897 this.stripEl.dom.removeChild(tab.pnode.dom);
26898 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26899 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26901 items.splice(index, 1);
26902 delete this.items[tab.id];
26903 tab.fireEvent("close", tab);
26904 tab.purgeListeners();
26905 this.autoSizeTabs();
26908 getNextAvailable : function(start){
26909 var items = this.items;
26911 // look for a next tab that will slide over to
26912 // replace the one being removed
26913 while(index < items.length){
26914 var item = items[++index];
26915 if(item && !item.isHidden()){
26919 // if one isn't found select the previous tab (on the left)
26922 var item = items[--index];
26923 if(item && !item.isHidden()){
26931 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26932 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26934 disableTab : function(id){
26935 var tab = this.items[id];
26936 if(tab && this.active != tab){
26942 * Enables a {@link Roo.TabPanelItem} that is disabled.
26943 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26945 enableTab : function(id){
26946 var tab = this.items[id];
26951 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26952 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26953 * @return {Roo.TabPanelItem} The TabPanelItem.
26955 activate : function(id){
26956 var tab = this.items[id];
26960 if(tab == this.active || tab.disabled){
26964 this.fireEvent("beforetabchange", this, e, tab);
26965 if(e.cancel !== true && !tab.disabled){
26967 this.active.hide();
26969 this.active = this.items[id];
26970 this.active.show();
26971 this.fireEvent("tabchange", this, this.active);
26977 * Gets the active {@link Roo.TabPanelItem}.
26978 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26980 getActiveTab : function(){
26981 return this.active;
26985 * Updates the tab body element to fit the height of the container element
26986 * for overflow scrolling
26987 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26989 syncHeight : function(targetHeight){
26990 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26991 var bm = this.bodyEl.getMargins();
26992 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26993 this.bodyEl.setHeight(newHeight);
26997 onResize : function(){
26998 if(this.monitorResize){
26999 this.autoSizeTabs();
27004 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
27006 beginUpdate : function(){
27007 this.updating = true;
27011 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27013 endUpdate : function(){
27014 this.updating = false;
27015 this.autoSizeTabs();
27019 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27021 autoSizeTabs : function(){
27022 var count = this.items.length;
27023 var vcount = count - this.hiddenCount;
27024 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27025 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27026 var availWidth = Math.floor(w / vcount);
27027 var b = this.stripBody;
27028 if(b.getWidth() > w){
27029 var tabs = this.items;
27030 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27031 if(availWidth < this.minTabWidth){
27032 /*if(!this.sleft){ // incomplete scrolling code
27033 this.createScrollButtons();
27036 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27039 if(this.currentTabWidth < this.preferredTabWidth){
27040 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27046 * Returns the number of tabs in this TabPanel.
27049 getCount : function(){
27050 return this.items.length;
27054 * Resizes all the tabs to the passed width
27055 * @param {Number} The new width
27057 setTabWidth : function(width){
27058 this.currentTabWidth = width;
27059 for(var i = 0, len = this.items.length; i < len; i++) {
27060 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27065 * Destroys this TabPanel
27066 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27068 destroy : function(removeEl){
27069 Roo.EventManager.removeResizeListener(this.onResize, this);
27070 for(var i = 0, len = this.items.length; i < len; i++){
27071 this.items[i].purgeListeners();
27073 if(removeEl === true){
27074 this.el.update("");
27081 * @class Roo.TabPanelItem
27082 * @extends Roo.util.Observable
27083 * Represents an individual item (tab plus body) in a TabPanel.
27084 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27085 * @param {String} id The id of this TabPanelItem
27086 * @param {String} text The text for the tab of this TabPanelItem
27087 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27089 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27091 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27092 * @type Roo.TabPanel
27094 this.tabPanel = tabPanel;
27096 * The id for this TabPanelItem
27101 this.disabled = false;
27105 this.loaded = false;
27106 this.closable = closable;
27109 * The body element for this TabPanelItem.
27110 * @type Roo.Element
27112 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27113 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27114 this.bodyEl.setStyle("display", "block");
27115 this.bodyEl.setStyle("zoom", "1");
27118 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27120 this.el = Roo.get(els.el, true);
27121 this.inner = Roo.get(els.inner, true);
27122 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27123 this.pnode = Roo.get(els.el.parentNode, true);
27124 this.el.on("mousedown", this.onTabMouseDown, this);
27125 this.el.on("click", this.onTabClick, this);
27128 var c = Roo.get(els.close, true);
27129 c.dom.title = this.closeText;
27130 c.addClassOnOver("close-over");
27131 c.on("click", this.closeClick, this);
27137 * Fires when this tab becomes the active tab.
27138 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27139 * @param {Roo.TabPanelItem} this
27143 * @event beforeclose
27144 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27145 * @param {Roo.TabPanelItem} this
27146 * @param {Object} e Set cancel to true on this object to cancel the close.
27148 "beforeclose": true,
27151 * Fires when this tab is closed.
27152 * @param {Roo.TabPanelItem} this
27156 * @event deactivate
27157 * Fires when this tab is no longer the active tab.
27158 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27159 * @param {Roo.TabPanelItem} this
27161 "deactivate" : true
27163 this.hidden = false;
27165 Roo.TabPanelItem.superclass.constructor.call(this);
27168 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27169 purgeListeners : function(){
27170 Roo.util.Observable.prototype.purgeListeners.call(this);
27171 this.el.removeAllListeners();
27174 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27177 this.pnode.addClass("on");
27180 this.tabPanel.stripWrap.repaint();
27182 this.fireEvent("activate", this.tabPanel, this);
27186 * Returns true if this tab is the active tab.
27187 * @return {Boolean}
27189 isActive : function(){
27190 return this.tabPanel.getActiveTab() == this;
27194 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27197 this.pnode.removeClass("on");
27199 this.fireEvent("deactivate", this.tabPanel, this);
27202 hideAction : function(){
27203 this.bodyEl.hide();
27204 this.bodyEl.setStyle("position", "absolute");
27205 this.bodyEl.setLeft("-20000px");
27206 this.bodyEl.setTop("-20000px");
27209 showAction : function(){
27210 this.bodyEl.setStyle("position", "relative");
27211 this.bodyEl.setTop("");
27212 this.bodyEl.setLeft("");
27213 this.bodyEl.show();
27217 * Set the tooltip for the tab.
27218 * @param {String} tooltip The tab's tooltip
27220 setTooltip : function(text){
27221 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27222 this.textEl.dom.qtip = text;
27223 this.textEl.dom.removeAttribute('title');
27225 this.textEl.dom.title = text;
27229 onTabClick : function(e){
27230 e.preventDefault();
27231 this.tabPanel.activate(this.id);
27234 onTabMouseDown : function(e){
27235 e.preventDefault();
27236 this.tabPanel.activate(this.id);
27239 getWidth : function(){
27240 return this.inner.getWidth();
27243 setWidth : function(width){
27244 var iwidth = width - this.pnode.getPadding("lr");
27245 this.inner.setWidth(iwidth);
27246 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27247 this.pnode.setWidth(width);
27251 * Show or hide the tab
27252 * @param {Boolean} hidden True to hide or false to show.
27254 setHidden : function(hidden){
27255 this.hidden = hidden;
27256 this.pnode.setStyle("display", hidden ? "none" : "");
27260 * Returns true if this tab is "hidden"
27261 * @return {Boolean}
27263 isHidden : function(){
27264 return this.hidden;
27268 * Returns the text for this tab
27271 getText : function(){
27275 autoSize : function(){
27276 //this.el.beginMeasure();
27277 this.textEl.setWidth(1);
27279 * #2804 [new] Tabs in Roojs
27280 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27282 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27283 //this.el.endMeasure();
27287 * Sets the text for the tab (Note: this also sets the tooltip text)
27288 * @param {String} text The tab's text and tooltip
27290 setText : function(text){
27292 this.textEl.update(text);
27293 this.setTooltip(text);
27294 if(!this.tabPanel.resizeTabs){
27299 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27301 activate : function(){
27302 this.tabPanel.activate(this.id);
27306 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27308 disable : function(){
27309 if(this.tabPanel.active != this){
27310 this.disabled = true;
27311 this.pnode.addClass("disabled");
27316 * Enables this TabPanelItem if it was previously disabled.
27318 enable : function(){
27319 this.disabled = false;
27320 this.pnode.removeClass("disabled");
27324 * Sets the content for this TabPanelItem.
27325 * @param {String} content The content
27326 * @param {Boolean} loadScripts true to look for and load scripts
27328 setContent : function(content, loadScripts){
27329 this.bodyEl.update(content, loadScripts);
27333 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27334 * @return {Roo.UpdateManager} The UpdateManager
27336 getUpdateManager : function(){
27337 return this.bodyEl.getUpdateManager();
27341 * Set a URL to be used to load the content for this TabPanelItem.
27342 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27343 * @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)
27344 * @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)
27345 * @return {Roo.UpdateManager} The UpdateManager
27347 setUrl : function(url, params, loadOnce){
27348 if(this.refreshDelegate){
27349 this.un('activate', this.refreshDelegate);
27351 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27352 this.on("activate", this.refreshDelegate);
27353 return this.bodyEl.getUpdateManager();
27357 _handleRefresh : function(url, params, loadOnce){
27358 if(!loadOnce || !this.loaded){
27359 var updater = this.bodyEl.getUpdateManager();
27360 updater.update(url, params, this._setLoaded.createDelegate(this));
27365 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27366 * Will fail silently if the setUrl method has not been called.
27367 * This does not activate the panel, just updates its content.
27369 refresh : function(){
27370 if(this.refreshDelegate){
27371 this.loaded = false;
27372 this.refreshDelegate();
27377 _setLoaded : function(){
27378 this.loaded = true;
27382 closeClick : function(e){
27385 this.fireEvent("beforeclose", this, o);
27386 if(o.cancel !== true){
27387 this.tabPanel.removeTab(this.id);
27391 * The text displayed in the tooltip for the close icon.
27394 closeText : "Close this tab"
27398 Roo.TabPanel.prototype.createStrip = function(container){
27399 var strip = document.createElement("div");
27400 strip.className = "x-tabs-wrap";
27401 container.appendChild(strip);
27405 Roo.TabPanel.prototype.createStripList = function(strip){
27406 // div wrapper for retard IE
27407 // returns the "tr" element.
27408 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27409 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27410 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27411 return strip.firstChild.firstChild.firstChild.firstChild;
27414 Roo.TabPanel.prototype.createBody = function(container){
27415 var body = document.createElement("div");
27416 Roo.id(body, "tab-body");
27417 Roo.fly(body).addClass("x-tabs-body");
27418 container.appendChild(body);
27422 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27423 var body = Roo.getDom(id);
27425 body = document.createElement("div");
27428 Roo.fly(body).addClass("x-tabs-item-body");
27429 bodyEl.insertBefore(body, bodyEl.firstChild);
27433 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27434 var td = document.createElement("td");
27435 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27436 //stripEl.appendChild(td);
27438 td.className = "x-tabs-closable";
27439 if(!this.closeTpl){
27440 this.closeTpl = new Roo.Template(
27441 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27442 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27443 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27446 var el = this.closeTpl.overwrite(td, {"text": text});
27447 var close = el.getElementsByTagName("div")[0];
27448 var inner = el.getElementsByTagName("em")[0];
27449 return {"el": el, "close": close, "inner": inner};
27452 this.tabTpl = new Roo.Template(
27453 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27454 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27457 var el = this.tabTpl.overwrite(td, {"text": text});
27458 var inner = el.getElementsByTagName("em")[0];
27459 return {"el": el, "inner": inner};
27463 * Ext JS Library 1.1.1
27464 * Copyright(c) 2006-2007, Ext JS, LLC.
27466 * Originally Released Under LGPL - original licence link has changed is not relivant.
27469 * <script type="text/javascript">
27473 * @class Roo.Button
27474 * @extends Roo.util.Observable
27475 * Simple Button class
27476 * @cfg {String} text The button text
27477 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27478 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27479 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27480 * @cfg {Object} scope The scope of the handler
27481 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27482 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27483 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27484 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27485 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27486 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27487 applies if enableToggle = true)
27488 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27489 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27490 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27492 * Create a new button
27493 * @param {Object} config The config object
27495 Roo.Button = function(renderTo, config)
27499 renderTo = config.renderTo || false;
27502 Roo.apply(this, config);
27506 * Fires when this button is clicked
27507 * @param {Button} this
27508 * @param {EventObject} e The click event
27513 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27514 * @param {Button} this
27515 * @param {Boolean} pressed
27520 * Fires when the mouse hovers over the button
27521 * @param {Button} this
27522 * @param {Event} e The event object
27524 'mouseover' : true,
27527 * Fires when the mouse exits the button
27528 * @param {Button} this
27529 * @param {Event} e The event object
27534 * Fires when the button is rendered
27535 * @param {Button} this
27540 this.menu = Roo.menu.MenuMgr.get(this.menu);
27542 // register listeners first!! - so render can be captured..
27543 Roo.util.Observable.call(this);
27545 this.render(renderTo);
27551 Roo.extend(Roo.Button, Roo.util.Observable, {
27557 * Read-only. True if this button is hidden
27562 * Read-only. True if this button is disabled
27567 * Read-only. True if this button is pressed (only if enableToggle = true)
27573 * @cfg {Number} tabIndex
27574 * The DOM tabIndex for this button (defaults to undefined)
27576 tabIndex : undefined,
27579 * @cfg {Boolean} enableToggle
27580 * True to enable pressed/not pressed toggling (defaults to false)
27582 enableToggle: false,
27584 * @cfg {Mixed} menu
27585 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27589 * @cfg {String} menuAlign
27590 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27592 menuAlign : "tl-bl?",
27595 * @cfg {String} iconCls
27596 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27598 iconCls : undefined,
27600 * @cfg {String} type
27601 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27606 menuClassTarget: 'tr',
27609 * @cfg {String} clickEvent
27610 * The type of event to map to the button's event handler (defaults to 'click')
27612 clickEvent : 'click',
27615 * @cfg {Boolean} handleMouseEvents
27616 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27618 handleMouseEvents : true,
27621 * @cfg {String} tooltipType
27622 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27624 tooltipType : 'qtip',
27627 * @cfg {String} cls
27628 * A CSS class to apply to the button's main element.
27632 * @cfg {Roo.Template} template (Optional)
27633 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27634 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27635 * require code modifications if required elements (e.g. a button) aren't present.
27639 render : function(renderTo){
27641 if(this.hideParent){
27642 this.parentEl = Roo.get(renderTo);
27644 if(!this.dhconfig){
27645 if(!this.template){
27646 if(!Roo.Button.buttonTemplate){
27647 // hideous table template
27648 Roo.Button.buttonTemplate = new Roo.Template(
27649 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27650 '<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>',
27651 "</tr></tbody></table>");
27653 this.template = Roo.Button.buttonTemplate;
27655 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27656 var btnEl = btn.child("button:first");
27657 btnEl.on('focus', this.onFocus, this);
27658 btnEl.on('blur', this.onBlur, this);
27660 btn.addClass(this.cls);
27663 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27666 btnEl.addClass(this.iconCls);
27668 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27671 if(this.tabIndex !== undefined){
27672 btnEl.dom.tabIndex = this.tabIndex;
27675 if(typeof this.tooltip == 'object'){
27676 Roo.QuickTips.tips(Roo.apply({
27680 btnEl.dom[this.tooltipType] = this.tooltip;
27684 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27688 this.el.dom.id = this.el.id = this.id;
27691 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27692 this.menu.on("show", this.onMenuShow, this);
27693 this.menu.on("hide", this.onMenuHide, this);
27695 btn.addClass("x-btn");
27696 if(Roo.isIE && !Roo.isIE7){
27697 this.autoWidth.defer(1, this);
27701 if(this.handleMouseEvents){
27702 btn.on("mouseover", this.onMouseOver, this);
27703 btn.on("mouseout", this.onMouseOut, this);
27704 btn.on("mousedown", this.onMouseDown, this);
27706 btn.on(this.clickEvent, this.onClick, this);
27707 //btn.on("mouseup", this.onMouseUp, this);
27714 Roo.ButtonToggleMgr.register(this);
27716 this.el.addClass("x-btn-pressed");
27719 var repeater = new Roo.util.ClickRepeater(btn,
27720 typeof this.repeat == "object" ? this.repeat : {}
27722 repeater.on("click", this.onClick, this);
27725 this.fireEvent('render', this);
27729 * Returns the button's underlying element
27730 * @return {Roo.Element} The element
27732 getEl : function(){
27737 * Destroys this Button and removes any listeners.
27739 destroy : function(){
27740 Roo.ButtonToggleMgr.unregister(this);
27741 this.el.removeAllListeners();
27742 this.purgeListeners();
27747 autoWidth : function(){
27749 this.el.setWidth("auto");
27750 if(Roo.isIE7 && Roo.isStrict){
27751 var ib = this.el.child('button');
27752 if(ib && ib.getWidth() > 20){
27754 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27759 this.el.beginMeasure();
27761 if(this.el.getWidth() < this.minWidth){
27762 this.el.setWidth(this.minWidth);
27765 this.el.endMeasure();
27772 * Assigns this button's click handler
27773 * @param {Function} handler The function to call when the button is clicked
27774 * @param {Object} scope (optional) Scope for the function passed in
27776 setHandler : function(handler, scope){
27777 this.handler = handler;
27778 this.scope = scope;
27782 * Sets this button's text
27783 * @param {String} text The button text
27785 setText : function(text){
27788 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27794 * Gets the text for this button
27795 * @return {String} The button text
27797 getText : function(){
27805 this.hidden = false;
27807 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27815 this.hidden = true;
27817 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27822 * Convenience function for boolean show/hide
27823 * @param {Boolean} visible True to show, false to hide
27825 setVisible: function(visible){
27834 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27835 * @param {Boolean} state (optional) Force a particular state
27837 toggle : function(state){
27838 state = state === undefined ? !this.pressed : state;
27839 if(state != this.pressed){
27841 this.el.addClass("x-btn-pressed");
27842 this.pressed = true;
27843 this.fireEvent("toggle", this, true);
27845 this.el.removeClass("x-btn-pressed");
27846 this.pressed = false;
27847 this.fireEvent("toggle", this, false);
27849 if(this.toggleHandler){
27850 this.toggleHandler.call(this.scope || this, this, state);
27858 focus : function(){
27859 this.el.child('button:first').focus();
27863 * Disable this button
27865 disable : function(){
27867 this.el.addClass("x-btn-disabled");
27869 this.disabled = true;
27873 * Enable this button
27875 enable : function(){
27877 this.el.removeClass("x-btn-disabled");
27879 this.disabled = false;
27883 * Convenience function for boolean enable/disable
27884 * @param {Boolean} enabled True to enable, false to disable
27886 setDisabled : function(v){
27887 this[v !== true ? "enable" : "disable"]();
27891 onClick : function(e)
27894 e.preventDefault();
27899 if(!this.disabled){
27900 if(this.enableToggle){
27903 if(this.menu && !this.menu.isVisible()){
27904 this.menu.show(this.el, this.menuAlign);
27906 this.fireEvent("click", this, e);
27908 this.el.removeClass("x-btn-over");
27909 this.handler.call(this.scope || this, this, e);
27914 onMouseOver : function(e){
27915 if(!this.disabled){
27916 this.el.addClass("x-btn-over");
27917 this.fireEvent('mouseover', this, e);
27921 onMouseOut : function(e){
27922 if(!e.within(this.el, true)){
27923 this.el.removeClass("x-btn-over");
27924 this.fireEvent('mouseout', this, e);
27928 onFocus : function(e){
27929 if(!this.disabled){
27930 this.el.addClass("x-btn-focus");
27934 onBlur : function(e){
27935 this.el.removeClass("x-btn-focus");
27938 onMouseDown : function(e){
27939 if(!this.disabled && e.button == 0){
27940 this.el.addClass("x-btn-click");
27941 Roo.get(document).on('mouseup', this.onMouseUp, this);
27945 onMouseUp : function(e){
27947 this.el.removeClass("x-btn-click");
27948 Roo.get(document).un('mouseup', this.onMouseUp, this);
27952 onMenuShow : function(e){
27953 this.el.addClass("x-btn-menu-active");
27956 onMenuHide : function(e){
27957 this.el.removeClass("x-btn-menu-active");
27961 // Private utility class used by Button
27962 Roo.ButtonToggleMgr = function(){
27965 function toggleGroup(btn, state){
27967 var g = groups[btn.toggleGroup];
27968 for(var i = 0, l = g.length; i < l; i++){
27970 g[i].toggle(false);
27977 register : function(btn){
27978 if(!btn.toggleGroup){
27981 var g = groups[btn.toggleGroup];
27983 g = groups[btn.toggleGroup] = [];
27986 btn.on("toggle", toggleGroup);
27989 unregister : function(btn){
27990 if(!btn.toggleGroup){
27993 var g = groups[btn.toggleGroup];
27996 btn.un("toggle", toggleGroup);
28002 * Ext JS Library 1.1.1
28003 * Copyright(c) 2006-2007, Ext JS, LLC.
28005 * Originally Released Under LGPL - original licence link has changed is not relivant.
28008 * <script type="text/javascript">
28012 * @class Roo.SplitButton
28013 * @extends Roo.Button
28014 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28015 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28016 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28017 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28018 * @cfg {String} arrowTooltip The title attribute of the arrow
28020 * Create a new menu button
28021 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28022 * @param {Object} config The config object
28024 Roo.SplitButton = function(renderTo, config){
28025 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28027 * @event arrowclick
28028 * Fires when this button's arrow is clicked
28029 * @param {SplitButton} this
28030 * @param {EventObject} e The click event
28032 this.addEvents({"arrowclick":true});
28035 Roo.extend(Roo.SplitButton, Roo.Button, {
28036 render : function(renderTo){
28037 // this is one sweet looking template!
28038 var tpl = new Roo.Template(
28039 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28040 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28041 '<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>',
28042 "</tbody></table></td><td>",
28043 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28044 '<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>',
28045 "</tbody></table></td></tr></table>"
28047 var btn = tpl.append(renderTo, [this.text, this.type], true);
28048 var btnEl = btn.child("button");
28050 btn.addClass(this.cls);
28053 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28056 btnEl.addClass(this.iconCls);
28058 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28062 if(this.handleMouseEvents){
28063 btn.on("mouseover", this.onMouseOver, this);
28064 btn.on("mouseout", this.onMouseOut, this);
28065 btn.on("mousedown", this.onMouseDown, this);
28066 btn.on("mouseup", this.onMouseUp, this);
28068 btn.on(this.clickEvent, this.onClick, this);
28070 if(typeof this.tooltip == 'object'){
28071 Roo.QuickTips.tips(Roo.apply({
28075 btnEl.dom[this.tooltipType] = this.tooltip;
28078 if(this.arrowTooltip){
28079 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28088 this.el.addClass("x-btn-pressed");
28090 if(Roo.isIE && !Roo.isIE7){
28091 this.autoWidth.defer(1, this);
28096 this.menu.on("show", this.onMenuShow, this);
28097 this.menu.on("hide", this.onMenuHide, this);
28099 this.fireEvent('render', this);
28103 autoWidth : function(){
28105 var tbl = this.el.child("table:first");
28106 var tbl2 = this.el.child("table:last");
28107 this.el.setWidth("auto");
28108 tbl.setWidth("auto");
28109 if(Roo.isIE7 && Roo.isStrict){
28110 var ib = this.el.child('button:first');
28111 if(ib && ib.getWidth() > 20){
28113 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28118 this.el.beginMeasure();
28120 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28121 tbl.setWidth(this.minWidth-tbl2.getWidth());
28124 this.el.endMeasure();
28127 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28131 * Sets this button's click handler
28132 * @param {Function} handler The function to call when the button is clicked
28133 * @param {Object} scope (optional) Scope for the function passed above
28135 setHandler : function(handler, scope){
28136 this.handler = handler;
28137 this.scope = scope;
28141 * Sets this button's arrow click handler
28142 * @param {Function} handler The function to call when the arrow is clicked
28143 * @param {Object} scope (optional) Scope for the function passed above
28145 setArrowHandler : function(handler, scope){
28146 this.arrowHandler = handler;
28147 this.scope = scope;
28153 focus : function(){
28155 this.el.child("button:first").focus();
28160 onClick : function(e){
28161 e.preventDefault();
28162 if(!this.disabled){
28163 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28164 if(this.menu && !this.menu.isVisible()){
28165 this.menu.show(this.el, this.menuAlign);
28167 this.fireEvent("arrowclick", this, e);
28168 if(this.arrowHandler){
28169 this.arrowHandler.call(this.scope || this, this, e);
28172 this.fireEvent("click", this, e);
28174 this.handler.call(this.scope || this, this, e);
28180 onMouseDown : function(e){
28181 if(!this.disabled){
28182 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28186 onMouseUp : function(e){
28187 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28192 // backwards compat
28193 Roo.MenuButton = Roo.SplitButton;/*
28195 * Ext JS Library 1.1.1
28196 * Copyright(c) 2006-2007, Ext JS, LLC.
28198 * Originally Released Under LGPL - original licence link has changed is not relivant.
28201 * <script type="text/javascript">
28205 * @class Roo.Toolbar
28206 * Basic Toolbar class.
28208 * Creates a new Toolbar
28209 * @param {Object} container The config object
28211 Roo.Toolbar = function(container, buttons, config)
28213 /// old consturctor format still supported..
28214 if(container instanceof Array){ // omit the container for later rendering
28215 buttons = container;
28219 if (typeof(container) == 'object' && container.xtype) {
28220 config = container;
28221 container = config.container;
28222 buttons = config.buttons || []; // not really - use items!!
28225 if (config && config.items) {
28226 xitems = config.items;
28227 delete config.items;
28229 Roo.apply(this, config);
28230 this.buttons = buttons;
28233 this.render(container);
28235 this.xitems = xitems;
28236 Roo.each(xitems, function(b) {
28242 Roo.Toolbar.prototype = {
28244 * @cfg {Array} items
28245 * array of button configs or elements to add (will be converted to a MixedCollection)
28249 * @cfg {String/HTMLElement/Element} container
28250 * The id or element that will contain the toolbar
28253 render : function(ct){
28254 this.el = Roo.get(ct);
28256 this.el.addClass(this.cls);
28258 // using a table allows for vertical alignment
28259 // 100% width is needed by Safari...
28260 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28261 this.tr = this.el.child("tr", true);
28263 this.items = new Roo.util.MixedCollection(false, function(o){
28264 return o.id || ("item" + (++autoId));
28267 this.add.apply(this, this.buttons);
28268 delete this.buttons;
28273 * Adds element(s) to the toolbar -- this function takes a variable number of
28274 * arguments of mixed type and adds them to the toolbar.
28275 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28277 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28278 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28279 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28280 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28281 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28282 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28283 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28284 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28285 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28287 * @param {Mixed} arg2
28288 * @param {Mixed} etc.
28291 var a = arguments, l = a.length;
28292 for(var i = 0; i < l; i++){
28297 _add : function(el) {
28300 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28303 if (el.applyTo){ // some kind of form field
28304 return this.addField(el);
28306 if (el.render){ // some kind of Toolbar.Item
28307 return this.addItem(el);
28309 if (typeof el == "string"){ // string
28310 if(el == "separator" || el == "-"){
28311 return this.addSeparator();
28314 return this.addSpacer();
28317 return this.addFill();
28319 return this.addText(el);
28322 if(el.tagName){ // element
28323 return this.addElement(el);
28325 if(typeof el == "object"){ // must be button config?
28326 return this.addButton(el);
28328 // and now what?!?!
28334 * Add an Xtype element
28335 * @param {Object} xtype Xtype Object
28336 * @return {Object} created Object
28338 addxtype : function(e){
28339 return this.add(e);
28343 * Returns the Element for this toolbar.
28344 * @return {Roo.Element}
28346 getEl : function(){
28352 * @return {Roo.Toolbar.Item} The separator item
28354 addSeparator : function(){
28355 return this.addItem(new Roo.Toolbar.Separator());
28359 * Adds a spacer element
28360 * @return {Roo.Toolbar.Spacer} The spacer item
28362 addSpacer : function(){
28363 return this.addItem(new Roo.Toolbar.Spacer());
28367 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28368 * @return {Roo.Toolbar.Fill} The fill item
28370 addFill : function(){
28371 return this.addItem(new Roo.Toolbar.Fill());
28375 * Adds any standard HTML element to the toolbar
28376 * @param {String/HTMLElement/Element} el The element or id of the element to add
28377 * @return {Roo.Toolbar.Item} The element's item
28379 addElement : function(el){
28380 return this.addItem(new Roo.Toolbar.Item(el));
28383 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28384 * @type Roo.util.MixedCollection
28389 * Adds any Toolbar.Item or subclass
28390 * @param {Roo.Toolbar.Item} item
28391 * @return {Roo.Toolbar.Item} The item
28393 addItem : function(item){
28394 var td = this.nextBlock();
28396 this.items.add(item);
28401 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28402 * @param {Object/Array} config A button config or array of configs
28403 * @return {Roo.Toolbar.Button/Array}
28405 addButton : function(config){
28406 if(config instanceof Array){
28408 for(var i = 0, len = config.length; i < len; i++) {
28409 buttons.push(this.addButton(config[i]));
28414 if(!(config instanceof Roo.Toolbar.Button)){
28416 new Roo.Toolbar.SplitButton(config) :
28417 new Roo.Toolbar.Button(config);
28419 var td = this.nextBlock();
28426 * Adds text to the toolbar
28427 * @param {String} text The text to add
28428 * @return {Roo.Toolbar.Item} The element's item
28430 addText : function(text){
28431 return this.addItem(new Roo.Toolbar.TextItem(text));
28435 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28436 * @param {Number} index The index where the item is to be inserted
28437 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28438 * @return {Roo.Toolbar.Button/Item}
28440 insertButton : function(index, item){
28441 if(item instanceof Array){
28443 for(var i = 0, len = item.length; i < len; i++) {
28444 buttons.push(this.insertButton(index + i, item[i]));
28448 if (!(item instanceof Roo.Toolbar.Button)){
28449 item = new Roo.Toolbar.Button(item);
28451 var td = document.createElement("td");
28452 this.tr.insertBefore(td, this.tr.childNodes[index]);
28454 this.items.insert(index, item);
28459 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28460 * @param {Object} config
28461 * @return {Roo.Toolbar.Item} The element's item
28463 addDom : function(config, returnEl){
28464 var td = this.nextBlock();
28465 Roo.DomHelper.overwrite(td, config);
28466 var ti = new Roo.Toolbar.Item(td.firstChild);
28468 this.items.add(ti);
28473 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28474 * @type Roo.util.MixedCollection
28479 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28480 * Note: the field should not have been rendered yet. For a field that has already been
28481 * rendered, use {@link #addElement}.
28482 * @param {Roo.form.Field} field
28483 * @return {Roo.ToolbarItem}
28487 addField : function(field) {
28488 if (!this.fields) {
28490 this.fields = new Roo.util.MixedCollection(false, function(o){
28491 return o.id || ("item" + (++autoId));
28496 var td = this.nextBlock();
28498 var ti = new Roo.Toolbar.Item(td.firstChild);
28500 this.items.add(ti);
28501 this.fields.add(field);
28512 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28513 this.el.child('div').hide();
28521 this.el.child('div').show();
28525 nextBlock : function(){
28526 var td = document.createElement("td");
28527 this.tr.appendChild(td);
28532 destroy : function(){
28533 if(this.items){ // rendered?
28534 Roo.destroy.apply(Roo, this.items.items);
28536 if(this.fields){ // rendered?
28537 Roo.destroy.apply(Roo, this.fields.items);
28539 Roo.Element.uncache(this.el, this.tr);
28544 * @class Roo.Toolbar.Item
28545 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28547 * Creates a new Item
28548 * @param {HTMLElement} el
28550 Roo.Toolbar.Item = function(el){
28552 if (typeof (el.xtype) != 'undefined') {
28557 this.el = Roo.getDom(el);
28558 this.id = Roo.id(this.el);
28559 this.hidden = false;
28564 * Fires when the button is rendered
28565 * @param {Button} this
28569 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28571 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28572 //Roo.Toolbar.Item.prototype = {
28575 * Get this item's HTML Element
28576 * @return {HTMLElement}
28578 getEl : function(){
28583 render : function(td){
28586 td.appendChild(this.el);
28588 this.fireEvent('render', this);
28592 * Removes and destroys this item.
28594 destroy : function(){
28595 this.td.parentNode.removeChild(this.td);
28602 this.hidden = false;
28603 this.td.style.display = "";
28610 this.hidden = true;
28611 this.td.style.display = "none";
28615 * Convenience function for boolean show/hide.
28616 * @param {Boolean} visible true to show/false to hide
28618 setVisible: function(visible){
28627 * Try to focus this item.
28629 focus : function(){
28630 Roo.fly(this.el).focus();
28634 * Disables this item.
28636 disable : function(){
28637 Roo.fly(this.td).addClass("x-item-disabled");
28638 this.disabled = true;
28639 this.el.disabled = true;
28643 * Enables this item.
28645 enable : function(){
28646 Roo.fly(this.td).removeClass("x-item-disabled");
28647 this.disabled = false;
28648 this.el.disabled = false;
28654 * @class Roo.Toolbar.Separator
28655 * @extends Roo.Toolbar.Item
28656 * A simple toolbar separator class
28658 * Creates a new Separator
28660 Roo.Toolbar.Separator = function(cfg){
28662 var s = document.createElement("span");
28663 s.className = "ytb-sep";
28668 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28670 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28671 enable:Roo.emptyFn,
28672 disable:Roo.emptyFn,
28677 * @class Roo.Toolbar.Spacer
28678 * @extends Roo.Toolbar.Item
28679 * A simple element that adds extra horizontal space to a toolbar.
28681 * Creates a new Spacer
28683 Roo.Toolbar.Spacer = function(cfg){
28684 var s = document.createElement("div");
28685 s.className = "ytb-spacer";
28689 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28691 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28692 enable:Roo.emptyFn,
28693 disable:Roo.emptyFn,
28698 * @class Roo.Toolbar.Fill
28699 * @extends Roo.Toolbar.Spacer
28700 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28702 * Creates a new Spacer
28704 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28706 render : function(td){
28707 td.style.width = '100%';
28708 Roo.Toolbar.Fill.superclass.render.call(this, td);
28713 * @class Roo.Toolbar.TextItem
28714 * @extends Roo.Toolbar.Item
28715 * A simple class that renders text directly into a toolbar.
28717 * Creates a new TextItem
28718 * @param {String} text
28720 Roo.Toolbar.TextItem = function(cfg){
28721 var text = cfg || "";
28722 if (typeof(cfg) == 'object') {
28723 text = cfg.text || "";
28727 var s = document.createElement("span");
28728 s.className = "ytb-text";
28729 s.innerHTML = text;
28734 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28736 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28739 enable:Roo.emptyFn,
28740 disable:Roo.emptyFn,
28745 * @class Roo.Toolbar.Button
28746 * @extends Roo.Button
28747 * A button that renders into a toolbar.
28749 * Creates a new Button
28750 * @param {Object} config A standard {@link Roo.Button} config object
28752 Roo.Toolbar.Button = function(config){
28753 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28755 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28756 render : function(td){
28758 Roo.Toolbar.Button.superclass.render.call(this, td);
28762 * Removes and destroys this button
28764 destroy : function(){
28765 Roo.Toolbar.Button.superclass.destroy.call(this);
28766 this.td.parentNode.removeChild(this.td);
28770 * Shows this button
28773 this.hidden = false;
28774 this.td.style.display = "";
28778 * Hides this button
28781 this.hidden = true;
28782 this.td.style.display = "none";
28786 * Disables this item
28788 disable : function(){
28789 Roo.fly(this.td).addClass("x-item-disabled");
28790 this.disabled = true;
28794 * Enables this item
28796 enable : function(){
28797 Roo.fly(this.td).removeClass("x-item-disabled");
28798 this.disabled = false;
28801 // backwards compat
28802 Roo.ToolbarButton = Roo.Toolbar.Button;
28805 * @class Roo.Toolbar.SplitButton
28806 * @extends Roo.SplitButton
28807 * A menu button that renders into a toolbar.
28809 * Creates a new SplitButton
28810 * @param {Object} config A standard {@link Roo.SplitButton} config object
28812 Roo.Toolbar.SplitButton = function(config){
28813 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28815 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28816 render : function(td){
28818 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28822 * Removes and destroys this button
28824 destroy : function(){
28825 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28826 this.td.parentNode.removeChild(this.td);
28830 * Shows this button
28833 this.hidden = false;
28834 this.td.style.display = "";
28838 * Hides this button
28841 this.hidden = true;
28842 this.td.style.display = "none";
28846 // backwards compat
28847 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28849 * Ext JS Library 1.1.1
28850 * Copyright(c) 2006-2007, Ext JS, LLC.
28852 * Originally Released Under LGPL - original licence link has changed is not relivant.
28855 * <script type="text/javascript">
28859 * @class Roo.PagingToolbar
28860 * @extends Roo.Toolbar
28861 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28863 * Create a new PagingToolbar
28864 * @param {Object} config The config object
28866 Roo.PagingToolbar = function(el, ds, config)
28868 // old args format still supported... - xtype is prefered..
28869 if (typeof(el) == 'object' && el.xtype) {
28870 // created from xtype...
28872 ds = el.dataSource;
28873 el = config.container;
28876 if (config.items) {
28877 items = config.items;
28881 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28884 this.renderButtons(this.el);
28887 // supprot items array.
28889 Roo.each(items, function(e) {
28890 this.add(Roo.factory(e));
28895 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28897 * @cfg {Roo.data.Store} dataSource
28898 * The underlying data store providing the paged data
28901 * @cfg {String/HTMLElement/Element} container
28902 * container The id or element that will contain the toolbar
28905 * @cfg {Boolean} displayInfo
28906 * True to display the displayMsg (defaults to false)
28909 * @cfg {Number} pageSize
28910 * The number of records to display per page (defaults to 20)
28914 * @cfg {String} displayMsg
28915 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28917 displayMsg : 'Displaying {0} - {1} of {2}',
28919 * @cfg {String} emptyMsg
28920 * The message to display when no records are found (defaults to "No data to display")
28922 emptyMsg : 'No data to display',
28924 * Customizable piece of the default paging text (defaults to "Page")
28927 beforePageText : "Page",
28929 * Customizable piece of the default paging text (defaults to "of %0")
28932 afterPageText : "of {0}",
28934 * Customizable piece of the default paging text (defaults to "First Page")
28937 firstText : "First Page",
28939 * Customizable piece of the default paging text (defaults to "Previous Page")
28942 prevText : "Previous Page",
28944 * Customizable piece of the default paging text (defaults to "Next Page")
28947 nextText : "Next Page",
28949 * Customizable piece of the default paging text (defaults to "Last Page")
28952 lastText : "Last Page",
28954 * Customizable piece of the default paging text (defaults to "Refresh")
28957 refreshText : "Refresh",
28960 renderButtons : function(el){
28961 Roo.PagingToolbar.superclass.render.call(this, el);
28962 this.first = this.addButton({
28963 tooltip: this.firstText,
28964 cls: "x-btn-icon x-grid-page-first",
28966 handler: this.onClick.createDelegate(this, ["first"])
28968 this.prev = this.addButton({
28969 tooltip: this.prevText,
28970 cls: "x-btn-icon x-grid-page-prev",
28972 handler: this.onClick.createDelegate(this, ["prev"])
28974 //this.addSeparator();
28975 this.add(this.beforePageText);
28976 this.field = Roo.get(this.addDom({
28981 cls: "x-grid-page-number"
28983 this.field.on("keydown", this.onPagingKeydown, this);
28984 this.field.on("focus", function(){this.dom.select();});
28985 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28986 this.field.setHeight(18);
28987 //this.addSeparator();
28988 this.next = this.addButton({
28989 tooltip: this.nextText,
28990 cls: "x-btn-icon x-grid-page-next",
28992 handler: this.onClick.createDelegate(this, ["next"])
28994 this.last = this.addButton({
28995 tooltip: this.lastText,
28996 cls: "x-btn-icon x-grid-page-last",
28998 handler: this.onClick.createDelegate(this, ["last"])
29000 //this.addSeparator();
29001 this.loading = this.addButton({
29002 tooltip: this.refreshText,
29003 cls: "x-btn-icon x-grid-loading",
29004 handler: this.onClick.createDelegate(this, ["refresh"])
29007 if(this.displayInfo){
29008 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29013 updateInfo : function(){
29014 if(this.displayEl){
29015 var count = this.ds.getCount();
29016 var msg = count == 0 ?
29020 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29022 this.displayEl.update(msg);
29027 onLoad : function(ds, r, o){
29028 this.cursor = o.params ? o.params.start : 0;
29029 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29031 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29032 this.field.dom.value = ap;
29033 this.first.setDisabled(ap == 1);
29034 this.prev.setDisabled(ap == 1);
29035 this.next.setDisabled(ap == ps);
29036 this.last.setDisabled(ap == ps);
29037 this.loading.enable();
29042 getPageData : function(){
29043 var total = this.ds.getTotalCount();
29046 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29047 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29052 onLoadError : function(){
29053 this.loading.enable();
29057 onPagingKeydown : function(e){
29058 var k = e.getKey();
29059 var d = this.getPageData();
29061 var v = this.field.dom.value, pageNum;
29062 if(!v || isNaN(pageNum = parseInt(v, 10))){
29063 this.field.dom.value = d.activePage;
29066 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29067 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29070 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))
29072 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29073 this.field.dom.value = pageNum;
29074 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29077 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29079 var v = this.field.dom.value, pageNum;
29080 var increment = (e.shiftKey) ? 10 : 1;
29081 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29083 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29084 this.field.dom.value = d.activePage;
29087 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29089 this.field.dom.value = parseInt(v, 10) + increment;
29090 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29091 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29098 beforeLoad : function(){
29100 this.loading.disable();
29105 onClick : function(which){
29109 ds.load({params:{start: 0, limit: this.pageSize}});
29112 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29115 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29118 var total = ds.getTotalCount();
29119 var extra = total % this.pageSize;
29120 var lastStart = extra ? (total - extra) : total-this.pageSize;
29121 ds.load({params:{start: lastStart, limit: this.pageSize}});
29124 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29130 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29131 * @param {Roo.data.Store} store The data store to unbind
29133 unbind : function(ds){
29134 ds.un("beforeload", this.beforeLoad, this);
29135 ds.un("load", this.onLoad, this);
29136 ds.un("loadexception", this.onLoadError, this);
29137 ds.un("remove", this.updateInfo, this);
29138 ds.un("add", this.updateInfo, this);
29139 this.ds = undefined;
29143 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29144 * @param {Roo.data.Store} store The data store to bind
29146 bind : function(ds){
29147 ds.on("beforeload", this.beforeLoad, this);
29148 ds.on("load", this.onLoad, this);
29149 ds.on("loadexception", this.onLoadError, this);
29150 ds.on("remove", this.updateInfo, this);
29151 ds.on("add", this.updateInfo, this);
29156 * Ext JS Library 1.1.1
29157 * Copyright(c) 2006-2007, Ext JS, LLC.
29159 * Originally Released Under LGPL - original licence link has changed is not relivant.
29162 * <script type="text/javascript">
29166 * @class Roo.Resizable
29167 * @extends Roo.util.Observable
29168 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29169 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29170 * 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
29171 * the element will be wrapped for you automatically.</p>
29172 * <p>Here is the list of valid resize handles:</p>
29175 ------ -------------------
29184 'hd' horizontal drag
29187 * <p>Here's an example showing the creation of a typical Resizable:</p>
29189 var resizer = new Roo.Resizable("element-id", {
29197 resizer.on("resize", myHandler);
29199 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29200 * resizer.east.setDisplayed(false);</p>
29201 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29202 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29203 * resize operation's new size (defaults to [0, 0])
29204 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29205 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29206 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29207 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29208 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29209 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29210 * @cfg {Number} width The width of the element in pixels (defaults to null)
29211 * @cfg {Number} height The height of the element in pixels (defaults to null)
29212 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29213 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29214 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29215 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29216 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29217 * in favor of the handles config option (defaults to false)
29218 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29219 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29220 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29221 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29222 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29223 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29224 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29225 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29226 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29227 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29228 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29230 * Create a new resizable component
29231 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29232 * @param {Object} config configuration options
29234 Roo.Resizable = function(el, config)
29236 this.el = Roo.get(el);
29238 if(config && config.wrap){
29239 config.resizeChild = this.el;
29240 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29241 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29242 this.el.setStyle("overflow", "hidden");
29243 this.el.setPositioning(config.resizeChild.getPositioning());
29244 config.resizeChild.clearPositioning();
29245 if(!config.width || !config.height){
29246 var csize = config.resizeChild.getSize();
29247 this.el.setSize(csize.width, csize.height);
29249 if(config.pinned && !config.adjustments){
29250 config.adjustments = "auto";
29254 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29255 this.proxy.unselectable();
29256 this.proxy.enableDisplayMode('block');
29258 Roo.apply(this, config);
29261 this.disableTrackOver = true;
29262 this.el.addClass("x-resizable-pinned");
29264 // if the element isn't positioned, make it relative
29265 var position = this.el.getStyle("position");
29266 if(position != "absolute" && position != "fixed"){
29267 this.el.setStyle("position", "relative");
29269 if(!this.handles){ // no handles passed, must be legacy style
29270 this.handles = 's,e,se';
29271 if(this.multiDirectional){
29272 this.handles += ',n,w';
29275 if(this.handles == "all"){
29276 this.handles = "n s e w ne nw se sw";
29278 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29279 var ps = Roo.Resizable.positions;
29280 for(var i = 0, len = hs.length; i < len; i++){
29281 if(hs[i] && ps[hs[i]]){
29282 var pos = ps[hs[i]];
29283 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29287 this.corner = this.southeast;
29289 // updateBox = the box can move..
29290 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29291 this.updateBox = true;
29294 this.activeHandle = null;
29296 if(this.resizeChild){
29297 if(typeof this.resizeChild == "boolean"){
29298 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29300 this.resizeChild = Roo.get(this.resizeChild, true);
29304 if(this.adjustments == "auto"){
29305 var rc = this.resizeChild;
29306 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29307 if(rc && (hw || hn)){
29308 rc.position("relative");
29309 rc.setLeft(hw ? hw.el.getWidth() : 0);
29310 rc.setTop(hn ? hn.el.getHeight() : 0);
29312 this.adjustments = [
29313 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29314 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29318 if(this.draggable){
29319 this.dd = this.dynamic ?
29320 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29321 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29327 * @event beforeresize
29328 * Fired before resize is allowed. Set enabled to false to cancel resize.
29329 * @param {Roo.Resizable} this
29330 * @param {Roo.EventObject} e The mousedown event
29332 "beforeresize" : true,
29335 * Fired a resizing.
29336 * @param {Roo.Resizable} this
29337 * @param {Number} x The new x position
29338 * @param {Number} y The new y position
29339 * @param {Number} w The new w width
29340 * @param {Number} h The new h hight
29341 * @param {Roo.EventObject} e The mouseup event
29346 * Fired after a resize.
29347 * @param {Roo.Resizable} this
29348 * @param {Number} width The new width
29349 * @param {Number} height The new height
29350 * @param {Roo.EventObject} e The mouseup event
29355 if(this.width !== null && this.height !== null){
29356 this.resizeTo(this.width, this.height);
29358 this.updateChildSize();
29361 this.el.dom.style.zoom = 1;
29363 Roo.Resizable.superclass.constructor.call(this);
29366 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29367 resizeChild : false,
29368 adjustments : [0, 0],
29378 multiDirectional : false,
29379 disableTrackOver : false,
29380 easing : 'easeOutStrong',
29381 widthIncrement : 0,
29382 heightIncrement : 0,
29386 preserveRatio : false,
29387 transparent: false,
29393 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29395 constrainTo: undefined,
29397 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29399 resizeRegion: undefined,
29403 * Perform a manual resize
29404 * @param {Number} width
29405 * @param {Number} height
29407 resizeTo : function(width, height){
29408 this.el.setSize(width, height);
29409 this.updateChildSize();
29410 this.fireEvent("resize", this, width, height, null);
29414 startSizing : function(e, handle){
29415 this.fireEvent("beforeresize", this, e);
29416 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29419 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29420 this.overlay.unselectable();
29421 this.overlay.enableDisplayMode("block");
29422 this.overlay.on("mousemove", this.onMouseMove, this);
29423 this.overlay.on("mouseup", this.onMouseUp, this);
29425 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29427 this.resizing = true;
29428 this.startBox = this.el.getBox();
29429 this.startPoint = e.getXY();
29430 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29431 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29433 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29434 this.overlay.show();
29436 if(this.constrainTo) {
29437 var ct = Roo.get(this.constrainTo);
29438 this.resizeRegion = ct.getRegion().adjust(
29439 ct.getFrameWidth('t'),
29440 ct.getFrameWidth('l'),
29441 -ct.getFrameWidth('b'),
29442 -ct.getFrameWidth('r')
29446 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29448 this.proxy.setBox(this.startBox);
29450 this.proxy.setStyle('visibility', 'visible');
29456 onMouseDown : function(handle, e){
29459 this.activeHandle = handle;
29460 this.startSizing(e, handle);
29465 onMouseUp : function(e){
29466 var size = this.resizeElement();
29467 this.resizing = false;
29469 this.overlay.hide();
29471 this.fireEvent("resize", this, size.width, size.height, e);
29475 updateChildSize : function(){
29477 if(this.resizeChild){
29479 var child = this.resizeChild;
29480 var adj = this.adjustments;
29481 if(el.dom.offsetWidth){
29482 var b = el.getSize(true);
29483 child.setSize(b.width+adj[0], b.height+adj[1]);
29485 // Second call here for IE
29486 // The first call enables instant resizing and
29487 // the second call corrects scroll bars if they
29490 setTimeout(function(){
29491 if(el.dom.offsetWidth){
29492 var b = el.getSize(true);
29493 child.setSize(b.width+adj[0], b.height+adj[1]);
29501 snap : function(value, inc, min){
29502 if(!inc || !value) return value;
29503 var newValue = value;
29504 var m = value % inc;
29507 newValue = value + (inc-m);
29509 newValue = value - m;
29512 return Math.max(min, newValue);
29516 resizeElement : function(){
29517 var box = this.proxy.getBox();
29518 if(this.updateBox){
29519 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29521 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29523 this.updateChildSize();
29531 constrain : function(v, diff, m, mx){
29534 }else if(v - diff > mx){
29541 onMouseMove : function(e){
29544 try{// try catch so if something goes wrong the user doesn't get hung
29546 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29550 //var curXY = this.startPoint;
29551 var curSize = this.curSize || this.startBox;
29552 var x = this.startBox.x, y = this.startBox.y;
29553 var ox = x, oy = y;
29554 var w = curSize.width, h = curSize.height;
29555 var ow = w, oh = h;
29556 var mw = this.minWidth, mh = this.minHeight;
29557 var mxw = this.maxWidth, mxh = this.maxHeight;
29558 var wi = this.widthIncrement;
29559 var hi = this.heightIncrement;
29561 var eventXY = e.getXY();
29562 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29563 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29565 var pos = this.activeHandle.position;
29570 w = Math.min(Math.max(mw, w), mxw);
29575 h = Math.min(Math.max(mh, h), mxh);
29580 w = Math.min(Math.max(mw, w), mxw);
29581 h = Math.min(Math.max(mh, h), mxh);
29584 diffY = this.constrain(h, diffY, mh, mxh);
29591 var adiffX = Math.abs(diffX);
29592 var sub = (adiffX % wi); // how much
29593 if (sub > (wi/2)) { // far enough to snap
29594 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29596 // remove difference..
29597 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29601 x = Math.max(this.minX, x);
29604 diffX = this.constrain(w, diffX, mw, mxw);
29610 w = Math.min(Math.max(mw, w), mxw);
29611 diffY = this.constrain(h, diffY, mh, mxh);
29616 diffX = this.constrain(w, diffX, mw, mxw);
29617 diffY = this.constrain(h, diffY, mh, mxh);
29624 diffX = this.constrain(w, diffX, mw, mxw);
29626 h = Math.min(Math.max(mh, h), mxh);
29632 var sw = this.snap(w, wi, mw);
29633 var sh = this.snap(h, hi, mh);
29634 if(sw != w || sh != h){
29657 if(this.preserveRatio){
29662 h = Math.min(Math.max(mh, h), mxh);
29667 w = Math.min(Math.max(mw, w), mxw);
29672 w = Math.min(Math.max(mw, w), mxw);
29678 w = Math.min(Math.max(mw, w), mxw);
29684 h = Math.min(Math.max(mh, h), mxh);
29692 h = Math.min(Math.max(mh, h), mxh);
29702 h = Math.min(Math.max(mh, h), mxh);
29710 if (pos == 'hdrag') {
29713 this.proxy.setBounds(x, y, w, h);
29715 this.resizeElement();
29719 this.fireEvent("resizing", this, x, y, w, h, e);
29723 handleOver : function(){
29725 this.el.addClass("x-resizable-over");
29730 handleOut : function(){
29731 if(!this.resizing){
29732 this.el.removeClass("x-resizable-over");
29737 * Returns the element this component is bound to.
29738 * @return {Roo.Element}
29740 getEl : function(){
29745 * Returns the resizeChild element (or null).
29746 * @return {Roo.Element}
29748 getResizeChild : function(){
29749 return this.resizeChild;
29751 groupHandler : function()
29756 * Destroys this resizable. If the element was wrapped and
29757 * removeEl is not true then the element remains.
29758 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29760 destroy : function(removeEl){
29761 this.proxy.remove();
29763 this.overlay.removeAllListeners();
29764 this.overlay.remove();
29766 var ps = Roo.Resizable.positions;
29768 if(typeof ps[k] != "function" && this[ps[k]]){
29769 var h = this[ps[k]];
29770 h.el.removeAllListeners();
29775 this.el.update("");
29782 // hash to map config positions to true positions
29783 Roo.Resizable.positions = {
29784 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29789 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29791 // only initialize the template if resizable is used
29792 var tpl = Roo.DomHelper.createTemplate(
29793 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29796 Roo.Resizable.Handle.prototype.tpl = tpl;
29798 this.position = pos;
29800 // show north drag fro topdra
29801 var handlepos = pos == 'hdrag' ? 'north' : pos;
29803 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29804 if (pos == 'hdrag') {
29805 this.el.setStyle('cursor', 'pointer');
29807 this.el.unselectable();
29809 this.el.setOpacity(0);
29811 this.el.on("mousedown", this.onMouseDown, this);
29812 if(!disableTrackOver){
29813 this.el.on("mouseover", this.onMouseOver, this);
29814 this.el.on("mouseout", this.onMouseOut, this);
29819 Roo.Resizable.Handle.prototype = {
29820 afterResize : function(rz){
29825 onMouseDown : function(e){
29826 this.rz.onMouseDown(this, e);
29829 onMouseOver : function(e){
29830 this.rz.handleOver(this, e);
29833 onMouseOut : function(e){
29834 this.rz.handleOut(this, e);
29838 * Ext JS Library 1.1.1
29839 * Copyright(c) 2006-2007, Ext JS, LLC.
29841 * Originally Released Under LGPL - original licence link has changed is not relivant.
29844 * <script type="text/javascript">
29848 * @class Roo.Editor
29849 * @extends Roo.Component
29850 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29852 * Create a new Editor
29853 * @param {Roo.form.Field} field The Field object (or descendant)
29854 * @param {Object} config The config object
29856 Roo.Editor = function(field, config){
29857 Roo.Editor.superclass.constructor.call(this, config);
29858 this.field = field;
29861 * @event beforestartedit
29862 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29863 * false from the handler of this event.
29864 * @param {Editor} this
29865 * @param {Roo.Element} boundEl The underlying element bound to this editor
29866 * @param {Mixed} value The field value being set
29868 "beforestartedit" : true,
29871 * Fires when this editor is displayed
29872 * @param {Roo.Element} boundEl The underlying element bound to this editor
29873 * @param {Mixed} value The starting field value
29875 "startedit" : true,
29877 * @event beforecomplete
29878 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29879 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29880 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29881 * event will not fire since no edit actually occurred.
29882 * @param {Editor} this
29883 * @param {Mixed} value The current field value
29884 * @param {Mixed} startValue The original field value
29886 "beforecomplete" : true,
29889 * Fires after editing is complete and any changed value has been written to the underlying field.
29890 * @param {Editor} this
29891 * @param {Mixed} value The current field value
29892 * @param {Mixed} startValue The original field value
29896 * @event specialkey
29897 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29898 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29899 * @param {Roo.form.Field} this
29900 * @param {Roo.EventObject} e The event object
29902 "specialkey" : true
29906 Roo.extend(Roo.Editor, Roo.Component, {
29908 * @cfg {Boolean/String} autosize
29909 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29910 * or "height" to adopt the height only (defaults to false)
29913 * @cfg {Boolean} revertInvalid
29914 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29915 * validation fails (defaults to true)
29918 * @cfg {Boolean} ignoreNoChange
29919 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29920 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29921 * will never be ignored.
29924 * @cfg {Boolean} hideEl
29925 * False to keep the bound element visible while the editor is displayed (defaults to true)
29928 * @cfg {Mixed} value
29929 * The data value of the underlying field (defaults to "")
29933 * @cfg {String} alignment
29934 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29938 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29939 * for bottom-right shadow (defaults to "frame")
29943 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29947 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29949 completeOnEnter : false,
29951 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29953 cancelOnEsc : false,
29955 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29960 onRender : function(ct, position){
29961 this.el = new Roo.Layer({
29962 shadow: this.shadow,
29968 constrain: this.constrain
29970 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29971 if(this.field.msgTarget != 'title'){
29972 this.field.msgTarget = 'qtip';
29974 this.field.render(this.el);
29976 this.field.el.dom.setAttribute('autocomplete', 'off');
29978 this.field.on("specialkey", this.onSpecialKey, this);
29979 if(this.swallowKeys){
29980 this.field.el.swallowEvent(['keydown','keypress']);
29983 this.field.on("blur", this.onBlur, this);
29984 if(this.field.grow){
29985 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29989 onSpecialKey : function(field, e)
29991 //Roo.log('editor onSpecialKey');
29992 if(this.completeOnEnter && e.getKey() == e.ENTER){
29994 this.completeEdit();
29997 // do not fire special key otherwise it might hide close the editor...
29998 if(e.getKey() == e.ENTER){
30001 if(this.cancelOnEsc && e.getKey() == e.ESC){
30005 this.fireEvent('specialkey', field, e);
30010 * Starts the editing process and shows the editor.
30011 * @param {String/HTMLElement/Element} el The element to edit
30012 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30013 * to the innerHTML of el.
30015 startEdit : function(el, value){
30017 this.completeEdit();
30019 this.boundEl = Roo.get(el);
30020 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30021 if(!this.rendered){
30022 this.render(this.parentEl || document.body);
30024 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30027 this.startValue = v;
30028 this.field.setValue(v);
30030 var sz = this.boundEl.getSize();
30031 switch(this.autoSize){
30033 this.setSize(sz.width, "");
30036 this.setSize("", sz.height);
30039 this.setSize(sz.width, sz.height);
30042 this.el.alignTo(this.boundEl, this.alignment);
30043 this.editing = true;
30045 Roo.QuickTips.disable();
30051 * Sets the height and width of this editor.
30052 * @param {Number} width The new width
30053 * @param {Number} height The new height
30055 setSize : function(w, h){
30056 this.field.setSize(w, h);
30063 * Realigns the editor to the bound field based on the current alignment config value.
30065 realign : function(){
30066 this.el.alignTo(this.boundEl, this.alignment);
30070 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30071 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30073 completeEdit : function(remainVisible){
30077 var v = this.getValue();
30078 if(this.revertInvalid !== false && !this.field.isValid()){
30079 v = this.startValue;
30080 this.cancelEdit(true);
30082 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30083 this.editing = false;
30087 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30088 this.editing = false;
30089 if(this.updateEl && this.boundEl){
30090 this.boundEl.update(v);
30092 if(remainVisible !== true){
30095 this.fireEvent("complete", this, v, this.startValue);
30100 onShow : function(){
30102 if(this.hideEl !== false){
30103 this.boundEl.hide();
30106 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30107 this.fixIEFocus = true;
30108 this.deferredFocus.defer(50, this);
30110 this.field.focus();
30112 this.fireEvent("startedit", this.boundEl, this.startValue);
30115 deferredFocus : function(){
30117 this.field.focus();
30122 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30123 * reverted to the original starting value.
30124 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30125 * cancel (defaults to false)
30127 cancelEdit : function(remainVisible){
30129 this.setValue(this.startValue);
30130 if(remainVisible !== true){
30137 onBlur : function(){
30138 if(this.allowBlur !== true && this.editing){
30139 this.completeEdit();
30144 onHide : function(){
30146 this.completeEdit();
30150 if(this.field.collapse){
30151 this.field.collapse();
30154 if(this.hideEl !== false){
30155 this.boundEl.show();
30158 Roo.QuickTips.enable();
30163 * Sets the data value of the editor
30164 * @param {Mixed} value Any valid value supported by the underlying field
30166 setValue : function(v){
30167 this.field.setValue(v);
30171 * Gets the data value of the editor
30172 * @return {Mixed} The data value
30174 getValue : function(){
30175 return this.field.getValue();
30179 * Ext JS Library 1.1.1
30180 * Copyright(c) 2006-2007, Ext JS, LLC.
30182 * Originally Released Under LGPL - original licence link has changed is not relivant.
30185 * <script type="text/javascript">
30189 * @class Roo.BasicDialog
30190 * @extends Roo.util.Observable
30191 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30193 var dlg = new Roo.BasicDialog("my-dlg", {
30202 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30203 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30204 dlg.addButton('Cancel', dlg.hide, dlg);
30207 <b>A Dialog should always be a direct child of the body element.</b>
30208 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30209 * @cfg {String} title Default text to display in the title bar (defaults to null)
30210 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30211 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30212 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30213 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30214 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30215 * (defaults to null with no animation)
30216 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30217 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30218 * property for valid values (defaults to 'all')
30219 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30220 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30221 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30222 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30223 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30224 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30225 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30226 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30227 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30228 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30229 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30230 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30231 * draggable = true (defaults to false)
30232 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30233 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30234 * shadow (defaults to false)
30235 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30236 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30237 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30238 * @cfg {Array} buttons Array of buttons
30239 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30241 * Create a new BasicDialog.
30242 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30243 * @param {Object} config Configuration options
30245 Roo.BasicDialog = function(el, config){
30246 this.el = Roo.get(el);
30247 var dh = Roo.DomHelper;
30248 if(!this.el && config && config.autoCreate){
30249 if(typeof config.autoCreate == "object"){
30250 if(!config.autoCreate.id){
30251 config.autoCreate.id = el;
30253 this.el = dh.append(document.body,
30254 config.autoCreate, true);
30256 this.el = dh.append(document.body,
30257 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30261 el.setDisplayed(true);
30262 el.hide = this.hideAction;
30264 el.addClass("x-dlg");
30266 Roo.apply(this, config);
30268 this.proxy = el.createProxy("x-dlg-proxy");
30269 this.proxy.hide = this.hideAction;
30270 this.proxy.setOpacity(.5);
30274 el.setWidth(config.width);
30277 el.setHeight(config.height);
30279 this.size = el.getSize();
30280 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30281 this.xy = [config.x,config.y];
30283 this.xy = el.getCenterXY(true);
30285 /** The header element @type Roo.Element */
30286 this.header = el.child("> .x-dlg-hd");
30287 /** The body element @type Roo.Element */
30288 this.body = el.child("> .x-dlg-bd");
30289 /** The footer element @type Roo.Element */
30290 this.footer = el.child("> .x-dlg-ft");
30293 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30296 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30299 this.header.unselectable();
30301 this.header.update(this.title);
30303 // this element allows the dialog to be focused for keyboard event
30304 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30305 this.focusEl.swallowEvent("click", true);
30307 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30309 // wrap the body and footer for special rendering
30310 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30312 this.bwrap.dom.appendChild(this.footer.dom);
30315 this.bg = this.el.createChild({
30316 tag: "div", cls:"x-dlg-bg",
30317 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30319 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30322 if(this.autoScroll !== false && !this.autoTabs){
30323 this.body.setStyle("overflow", "auto");
30326 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30328 if(this.closable !== false){
30329 this.el.addClass("x-dlg-closable");
30330 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30331 this.close.on("click", this.closeClick, this);
30332 this.close.addClassOnOver("x-dlg-close-over");
30334 if(this.collapsible !== false){
30335 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30336 this.collapseBtn.on("click", this.collapseClick, this);
30337 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30338 this.header.on("dblclick", this.collapseClick, this);
30340 if(this.resizable !== false){
30341 this.el.addClass("x-dlg-resizable");
30342 this.resizer = new Roo.Resizable(el, {
30343 minWidth: this.minWidth || 80,
30344 minHeight:this.minHeight || 80,
30345 handles: this.resizeHandles || "all",
30348 this.resizer.on("beforeresize", this.beforeResize, this);
30349 this.resizer.on("resize", this.onResize, this);
30351 if(this.draggable !== false){
30352 el.addClass("x-dlg-draggable");
30353 if (!this.proxyDrag) {
30354 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30357 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30359 dd.setHandleElId(this.header.id);
30360 dd.endDrag = this.endMove.createDelegate(this);
30361 dd.startDrag = this.startMove.createDelegate(this);
30362 dd.onDrag = this.onDrag.createDelegate(this);
30367 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30368 this.mask.enableDisplayMode("block");
30370 this.el.addClass("x-dlg-modal");
30373 this.shadow = new Roo.Shadow({
30374 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30375 offset : this.shadowOffset
30378 this.shadowOffset = 0;
30380 if(Roo.useShims && this.shim !== false){
30381 this.shim = this.el.createShim();
30382 this.shim.hide = this.hideAction;
30390 if (this.buttons) {
30391 var bts= this.buttons;
30393 Roo.each(bts, function(b) {
30402 * Fires when a key is pressed
30403 * @param {Roo.BasicDialog} this
30404 * @param {Roo.EventObject} e
30409 * Fires when this dialog is moved by the user.
30410 * @param {Roo.BasicDialog} this
30411 * @param {Number} x The new page X
30412 * @param {Number} y The new page Y
30417 * Fires when this dialog is resized by the user.
30418 * @param {Roo.BasicDialog} this
30419 * @param {Number} width The new width
30420 * @param {Number} height The new height
30424 * @event beforehide
30425 * Fires before this dialog is hidden.
30426 * @param {Roo.BasicDialog} this
30428 "beforehide" : true,
30431 * Fires when this dialog is hidden.
30432 * @param {Roo.BasicDialog} this
30436 * @event beforeshow
30437 * Fires before this dialog is shown.
30438 * @param {Roo.BasicDialog} this
30440 "beforeshow" : true,
30443 * Fires when this dialog is shown.
30444 * @param {Roo.BasicDialog} this
30448 el.on("keydown", this.onKeyDown, this);
30449 el.on("mousedown", this.toFront, this);
30450 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30452 Roo.DialogManager.register(this);
30453 Roo.BasicDialog.superclass.constructor.call(this);
30456 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30457 shadowOffset: Roo.isIE ? 6 : 5,
30460 minButtonWidth: 75,
30461 defaultButton: null,
30462 buttonAlign: "right",
30467 * Sets the dialog title text
30468 * @param {String} text The title text to display
30469 * @return {Roo.BasicDialog} this
30471 setTitle : function(text){
30472 this.header.update(text);
30477 closeClick : function(){
30482 collapseClick : function(){
30483 this[this.collapsed ? "expand" : "collapse"]();
30487 * Collapses the dialog to its minimized state (only the title bar is visible).
30488 * Equivalent to the user clicking the collapse dialog button.
30490 collapse : function(){
30491 if(!this.collapsed){
30492 this.collapsed = true;
30493 this.el.addClass("x-dlg-collapsed");
30494 this.restoreHeight = this.el.getHeight();
30495 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30500 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30501 * clicking the expand dialog button.
30503 expand : function(){
30504 if(this.collapsed){
30505 this.collapsed = false;
30506 this.el.removeClass("x-dlg-collapsed");
30507 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30512 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30513 * @return {Roo.TabPanel} The tabs component
30515 initTabs : function(){
30516 var tabs = this.getTabs();
30517 while(tabs.getTab(0)){
30520 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30522 tabs.addTab(Roo.id(dom), dom.title);
30530 beforeResize : function(){
30531 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30535 onResize : function(){
30536 this.refreshSize();
30537 this.syncBodyHeight();
30538 this.adjustAssets();
30540 this.fireEvent("resize", this, this.size.width, this.size.height);
30544 onKeyDown : function(e){
30545 if(this.isVisible()){
30546 this.fireEvent("keydown", this, e);
30551 * Resizes the dialog.
30552 * @param {Number} width
30553 * @param {Number} height
30554 * @return {Roo.BasicDialog} this
30556 resizeTo : function(width, height){
30557 this.el.setSize(width, height);
30558 this.size = {width: width, height: height};
30559 this.syncBodyHeight();
30560 if(this.fixedcenter){
30563 if(this.isVisible()){
30564 this.constrainXY();
30565 this.adjustAssets();
30567 this.fireEvent("resize", this, width, height);
30573 * Resizes the dialog to fit the specified content size.
30574 * @param {Number} width
30575 * @param {Number} height
30576 * @return {Roo.BasicDialog} this
30578 setContentSize : function(w, h){
30579 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30580 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30581 //if(!this.el.isBorderBox()){
30582 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30583 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30586 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30587 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30589 this.resizeTo(w, h);
30594 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30595 * executed in response to a particular key being pressed while the dialog is active.
30596 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30597 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30598 * @param {Function} fn The function to call
30599 * @param {Object} scope (optional) The scope of the function
30600 * @return {Roo.BasicDialog} this
30602 addKeyListener : function(key, fn, scope){
30603 var keyCode, shift, ctrl, alt;
30604 if(typeof key == "object" && !(key instanceof Array)){
30605 keyCode = key["key"];
30606 shift = key["shift"];
30607 ctrl = key["ctrl"];
30612 var handler = function(dlg, e){
30613 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30614 var k = e.getKey();
30615 if(keyCode instanceof Array){
30616 for(var i = 0, len = keyCode.length; i < len; i++){
30617 if(keyCode[i] == k){
30618 fn.call(scope || window, dlg, k, e);
30624 fn.call(scope || window, dlg, k, e);
30629 this.on("keydown", handler);
30634 * Returns the TabPanel component (creates it if it doesn't exist).
30635 * Note: If you wish to simply check for the existence of tabs without creating them,
30636 * check for a null 'tabs' property.
30637 * @return {Roo.TabPanel} The tabs component
30639 getTabs : function(){
30641 this.el.addClass("x-dlg-auto-tabs");
30642 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30643 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30649 * Adds a button to the footer section of the dialog.
30650 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30651 * object or a valid Roo.DomHelper element config
30652 * @param {Function} handler The function called when the button is clicked
30653 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30654 * @return {Roo.Button} The new button
30656 addButton : function(config, handler, scope){
30657 var dh = Roo.DomHelper;
30659 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30661 if(!this.btnContainer){
30662 var tb = this.footer.createChild({
30664 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30665 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30667 this.btnContainer = tb.firstChild.firstChild.firstChild;
30672 minWidth: this.minButtonWidth,
30675 if(typeof config == "string"){
30676 bconfig.text = config;
30679 bconfig.dhconfig = config;
30681 Roo.apply(bconfig, config);
30685 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30686 bconfig.position = Math.max(0, bconfig.position);
30687 fc = this.btnContainer.childNodes[bconfig.position];
30690 var btn = new Roo.Button(
30692 this.btnContainer.insertBefore(document.createElement("td"),fc)
30693 : this.btnContainer.appendChild(document.createElement("td")),
30694 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30697 this.syncBodyHeight();
30700 * Array of all the buttons that have been added to this dialog via addButton
30705 this.buttons.push(btn);
30710 * Sets the default button to be focused when the dialog is displayed.
30711 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30712 * @return {Roo.BasicDialog} this
30714 setDefaultButton : function(btn){
30715 this.defaultButton = btn;
30720 getHeaderFooterHeight : function(safe){
30723 height += this.header.getHeight();
30726 var fm = this.footer.getMargins();
30727 height += (this.footer.getHeight()+fm.top+fm.bottom);
30729 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30730 height += this.centerBg.getPadding("tb");
30735 syncBodyHeight : function()
30737 var bd = this.body, // the text
30738 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30740 var height = this.size.height - this.getHeaderFooterHeight(false);
30741 bd.setHeight(height-bd.getMargins("tb"));
30742 var hh = this.header.getHeight();
30743 var h = this.size.height-hh;
30746 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30747 bw.setHeight(h-cb.getPadding("tb"));
30749 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30750 bd.setWidth(bw.getWidth(true));
30752 this.tabs.syncHeight();
30754 this.tabs.el.repaint();
30760 * Restores the previous state of the dialog if Roo.state is configured.
30761 * @return {Roo.BasicDialog} this
30763 restoreState : function(){
30764 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30765 if(box && box.width){
30766 this.xy = [box.x, box.y];
30767 this.resizeTo(box.width, box.height);
30773 beforeShow : function(){
30775 if(this.fixedcenter){
30776 this.xy = this.el.getCenterXY(true);
30779 Roo.get(document.body).addClass("x-body-masked");
30780 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30783 this.constrainXY();
30787 animShow : function(){
30788 var b = Roo.get(this.animateTarget).getBox();
30789 this.proxy.setSize(b.width, b.height);
30790 this.proxy.setLocation(b.x, b.y);
30792 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30793 true, .35, this.showEl.createDelegate(this));
30797 * Shows the dialog.
30798 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30799 * @return {Roo.BasicDialog} this
30801 show : function(animateTarget){
30802 if (this.fireEvent("beforeshow", this) === false){
30805 if(this.syncHeightBeforeShow){
30806 this.syncBodyHeight();
30807 }else if(this.firstShow){
30808 this.firstShow = false;
30809 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30811 this.animateTarget = animateTarget || this.animateTarget;
30812 if(!this.el.isVisible()){
30814 if(this.animateTarget && Roo.get(this.animateTarget)){
30824 showEl : function(){
30826 this.el.setXY(this.xy);
30828 this.adjustAssets(true);
30831 // IE peekaboo bug - fix found by Dave Fenwick
30835 this.fireEvent("show", this);
30839 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30840 * dialog itself will receive focus.
30842 focus : function(){
30843 if(this.defaultButton){
30844 this.defaultButton.focus();
30846 this.focusEl.focus();
30851 constrainXY : function(){
30852 if(this.constraintoviewport !== false){
30853 if(!this.viewSize){
30854 if(this.container){
30855 var s = this.container.getSize();
30856 this.viewSize = [s.width, s.height];
30858 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30861 var s = Roo.get(this.container||document).getScroll();
30863 var x = this.xy[0], y = this.xy[1];
30864 var w = this.size.width, h = this.size.height;
30865 var vw = this.viewSize[0], vh = this.viewSize[1];
30866 // only move it if it needs it
30868 // first validate right/bottom
30869 if(x + w > vw+s.left){
30873 if(y + h > vh+s.top){
30877 // then make sure top/left isn't negative
30889 if(this.isVisible()){
30890 this.el.setLocation(x, y);
30891 this.adjustAssets();
30898 onDrag : function(){
30899 if(!this.proxyDrag){
30900 this.xy = this.el.getXY();
30901 this.adjustAssets();
30906 adjustAssets : function(doShow){
30907 var x = this.xy[0], y = this.xy[1];
30908 var w = this.size.width, h = this.size.height;
30909 if(doShow === true){
30911 this.shadow.show(this.el);
30917 if(this.shadow && this.shadow.isVisible()){
30918 this.shadow.show(this.el);
30920 if(this.shim && this.shim.isVisible()){
30921 this.shim.setBounds(x, y, w, h);
30926 adjustViewport : function(w, h){
30928 w = Roo.lib.Dom.getViewWidth();
30929 h = Roo.lib.Dom.getViewHeight();
30932 this.viewSize = [w, h];
30933 if(this.modal && this.mask.isVisible()){
30934 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30935 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30937 if(this.isVisible()){
30938 this.constrainXY();
30943 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30944 * shadow, proxy, mask, etc.) Also removes all event listeners.
30945 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30947 destroy : function(removeEl){
30948 if(this.isVisible()){
30949 this.animateTarget = null;
30952 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30954 this.tabs.destroy(removeEl);
30967 for(var i = 0, len = this.buttons.length; i < len; i++){
30968 this.buttons[i].destroy();
30971 this.el.removeAllListeners();
30972 if(removeEl === true){
30973 this.el.update("");
30976 Roo.DialogManager.unregister(this);
30980 startMove : function(){
30981 if(this.proxyDrag){
30984 if(this.constraintoviewport !== false){
30985 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30990 endMove : function(){
30991 if(!this.proxyDrag){
30992 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30994 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30997 this.refreshSize();
30998 this.adjustAssets();
31000 this.fireEvent("move", this, this.xy[0], this.xy[1]);
31004 * Brings this dialog to the front of any other visible dialogs
31005 * @return {Roo.BasicDialog} this
31007 toFront : function(){
31008 Roo.DialogManager.bringToFront(this);
31013 * Sends this dialog to the back (under) of any other visible dialogs
31014 * @return {Roo.BasicDialog} this
31016 toBack : function(){
31017 Roo.DialogManager.sendToBack(this);
31022 * Centers this dialog in the viewport
31023 * @return {Roo.BasicDialog} this
31025 center : function(){
31026 var xy = this.el.getCenterXY(true);
31027 this.moveTo(xy[0], xy[1]);
31032 * Moves the dialog's top-left corner to the specified point
31033 * @param {Number} x
31034 * @param {Number} y
31035 * @return {Roo.BasicDialog} this
31037 moveTo : function(x, y){
31039 if(this.isVisible()){
31040 this.el.setXY(this.xy);
31041 this.adjustAssets();
31047 * Aligns the dialog to the specified element
31048 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31049 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31050 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31051 * @return {Roo.BasicDialog} this
31053 alignTo : function(element, position, offsets){
31054 this.xy = this.el.getAlignToXY(element, position, offsets);
31055 if(this.isVisible()){
31056 this.el.setXY(this.xy);
31057 this.adjustAssets();
31063 * Anchors an element to another element and realigns it when the window is resized.
31064 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31065 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31066 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31067 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31068 * is a number, it is used as the buffer delay (defaults to 50ms).
31069 * @return {Roo.BasicDialog} this
31071 anchorTo : function(el, alignment, offsets, monitorScroll){
31072 var action = function(){
31073 this.alignTo(el, alignment, offsets);
31075 Roo.EventManager.onWindowResize(action, this);
31076 var tm = typeof monitorScroll;
31077 if(tm != 'undefined'){
31078 Roo.EventManager.on(window, 'scroll', action, this,
31079 {buffer: tm == 'number' ? monitorScroll : 50});
31086 * Returns true if the dialog is visible
31087 * @return {Boolean}
31089 isVisible : function(){
31090 return this.el.isVisible();
31094 animHide : function(callback){
31095 var b = Roo.get(this.animateTarget).getBox();
31097 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31099 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31100 this.hideEl.createDelegate(this, [callback]));
31104 * Hides the dialog.
31105 * @param {Function} callback (optional) Function to call when the dialog is hidden
31106 * @return {Roo.BasicDialog} this
31108 hide : function(callback){
31109 if (this.fireEvent("beforehide", this) === false){
31113 this.shadow.hide();
31118 // sometimes animateTarget seems to get set.. causing problems...
31119 // this just double checks..
31120 if(this.animateTarget && Roo.get(this.animateTarget)) {
31121 this.animHide(callback);
31124 this.hideEl(callback);
31130 hideEl : function(callback){
31134 Roo.get(document.body).removeClass("x-body-masked");
31136 this.fireEvent("hide", this);
31137 if(typeof callback == "function"){
31143 hideAction : function(){
31144 this.setLeft("-10000px");
31145 this.setTop("-10000px");
31146 this.setStyle("visibility", "hidden");
31150 refreshSize : function(){
31151 this.size = this.el.getSize();
31152 this.xy = this.el.getXY();
31153 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31157 // z-index is managed by the DialogManager and may be overwritten at any time
31158 setZIndex : function(index){
31160 this.mask.setStyle("z-index", index);
31163 this.shim.setStyle("z-index", ++index);
31166 this.shadow.setZIndex(++index);
31168 this.el.setStyle("z-index", ++index);
31170 this.proxy.setStyle("z-index", ++index);
31173 this.resizer.proxy.setStyle("z-index", ++index);
31176 this.lastZIndex = index;
31180 * Returns the element for this dialog
31181 * @return {Roo.Element} The underlying dialog Element
31183 getEl : function(){
31189 * @class Roo.DialogManager
31190 * Provides global access to BasicDialogs that have been created and
31191 * support for z-indexing (layering) multiple open dialogs.
31193 Roo.DialogManager = function(){
31195 var accessList = [];
31199 var sortDialogs = function(d1, d2){
31200 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31204 var orderDialogs = function(){
31205 accessList.sort(sortDialogs);
31206 var seed = Roo.DialogManager.zseed;
31207 for(var i = 0, len = accessList.length; i < len; i++){
31208 var dlg = accessList[i];
31210 dlg.setZIndex(seed + (i*10));
31217 * The starting z-index for BasicDialogs (defaults to 9000)
31218 * @type Number The z-index value
31223 register : function(dlg){
31224 list[dlg.id] = dlg;
31225 accessList.push(dlg);
31229 unregister : function(dlg){
31230 delete list[dlg.id];
31233 if(!accessList.indexOf){
31234 for( i = 0, len = accessList.length; i < len; i++){
31235 if(accessList[i] == dlg){
31236 accessList.splice(i, 1);
31241 i = accessList.indexOf(dlg);
31243 accessList.splice(i, 1);
31249 * Gets a registered dialog by id
31250 * @param {String/Object} id The id of the dialog or a dialog
31251 * @return {Roo.BasicDialog} this
31253 get : function(id){
31254 return typeof id == "object" ? id : list[id];
31258 * Brings the specified dialog to the front
31259 * @param {String/Object} dlg The id of the dialog or a dialog
31260 * @return {Roo.BasicDialog} this
31262 bringToFront : function(dlg){
31263 dlg = this.get(dlg);
31266 dlg._lastAccess = new Date().getTime();
31273 * Sends the specified dialog to the back
31274 * @param {String/Object} dlg The id of the dialog or a dialog
31275 * @return {Roo.BasicDialog} this
31277 sendToBack : function(dlg){
31278 dlg = this.get(dlg);
31279 dlg._lastAccess = -(new Date().getTime());
31285 * Hides all dialogs
31287 hideAll : function(){
31288 for(var id in list){
31289 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31298 * @class Roo.LayoutDialog
31299 * @extends Roo.BasicDialog
31300 * Dialog which provides adjustments for working with a layout in a Dialog.
31301 * Add your necessary layout config options to the dialog's config.<br>
31302 * Example usage (including a nested layout):
31305 dialog = new Roo.LayoutDialog("download-dlg", {
31314 // layout config merges with the dialog config
31316 tabPosition: "top",
31317 alwaysShowTabs: true
31320 dialog.addKeyListener(27, dialog.hide, dialog);
31321 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31322 dialog.addButton("Build It!", this.getDownload, this);
31324 // we can even add nested layouts
31325 var innerLayout = new Roo.BorderLayout("dl-inner", {
31335 innerLayout.beginUpdate();
31336 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31337 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31338 innerLayout.endUpdate(true);
31340 var layout = dialog.getLayout();
31341 layout.beginUpdate();
31342 layout.add("center", new Roo.ContentPanel("standard-panel",
31343 {title: "Download the Source", fitToFrame:true}));
31344 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31345 {title: "Build your own roo.js"}));
31346 layout.getRegion("center").showPanel(sp);
31347 layout.endUpdate();
31351 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31352 * @param {Object} config configuration options
31354 Roo.LayoutDialog = function(el, cfg){
31357 if (typeof(cfg) == 'undefined') {
31358 config = Roo.apply({}, el);
31359 // not sure why we use documentElement here.. - it should always be body.
31360 // IE7 borks horribly if we use documentElement.
31361 // webkit also does not like documentElement - it creates a body element...
31362 el = Roo.get( document.body || document.documentElement ).createChild();
31363 //config.autoCreate = true;
31367 config.autoTabs = false;
31368 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31369 this.body.setStyle({overflow:"hidden", position:"relative"});
31370 this.layout = new Roo.BorderLayout(this.body.dom, config);
31371 this.layout.monitorWindowResize = false;
31372 this.el.addClass("x-dlg-auto-layout");
31373 // fix case when center region overwrites center function
31374 this.center = Roo.BasicDialog.prototype.center;
31375 this.on("show", this.layout.layout, this.layout, true);
31376 if (config.items) {
31377 var xitems = config.items;
31378 delete config.items;
31379 Roo.each(xitems, this.addxtype, this);
31384 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31386 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31389 endUpdate : function(){
31390 this.layout.endUpdate();
31394 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31397 beginUpdate : function(){
31398 this.layout.beginUpdate();
31402 * Get the BorderLayout for this dialog
31403 * @return {Roo.BorderLayout}
31405 getLayout : function(){
31406 return this.layout;
31409 showEl : function(){
31410 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31412 this.layout.layout();
31417 // Use the syncHeightBeforeShow config option to control this automatically
31418 syncBodyHeight : function(){
31419 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31420 if(this.layout){this.layout.layout();}
31424 * Add an xtype element (actually adds to the layout.)
31425 * @return {Object} xdata xtype object data.
31428 addxtype : function(c) {
31429 return this.layout.addxtype(c);
31433 * Ext JS Library 1.1.1
31434 * Copyright(c) 2006-2007, Ext JS, LLC.
31436 * Originally Released Under LGPL - original licence link has changed is not relivant.
31439 * <script type="text/javascript">
31443 * @class Roo.MessageBox
31444 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31448 Roo.Msg.alert('Status', 'Changes saved successfully.');
31450 // Prompt for user data:
31451 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31453 // process text value...
31457 // Show a dialog using config options:
31459 title:'Save Changes?',
31460 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31461 buttons: Roo.Msg.YESNOCANCEL,
31468 Roo.MessageBox = function(){
31469 var dlg, opt, mask, waitTimer;
31470 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31471 var buttons, activeTextEl, bwidth;
31474 var handleButton = function(button){
31476 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31480 var handleHide = function(){
31481 if(opt && opt.cls){
31482 dlg.el.removeClass(opt.cls);
31485 Roo.TaskMgr.stop(waitTimer);
31491 var updateButtons = function(b){
31494 buttons["ok"].hide();
31495 buttons["cancel"].hide();
31496 buttons["yes"].hide();
31497 buttons["no"].hide();
31498 dlg.footer.dom.style.display = 'none';
31501 dlg.footer.dom.style.display = '';
31502 for(var k in buttons){
31503 if(typeof buttons[k] != "function"){
31506 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31507 width += buttons[k].el.getWidth()+15;
31517 var handleEsc = function(d, k, e){
31518 if(opt && opt.closable !== false){
31528 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31529 * @return {Roo.BasicDialog} The BasicDialog element
31531 getDialog : function(){
31533 dlg = new Roo.BasicDialog("x-msg-box", {
31538 constraintoviewport:false,
31540 collapsible : false,
31543 width:400, height:100,
31544 buttonAlign:"center",
31545 closeClick : function(){
31546 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31547 handleButton("no");
31549 handleButton("cancel");
31553 dlg.on("hide", handleHide);
31555 dlg.addKeyListener(27, handleEsc);
31557 var bt = this.buttonText;
31558 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31559 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31560 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31561 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31562 bodyEl = dlg.body.createChild({
31564 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>'
31566 msgEl = bodyEl.dom.firstChild;
31567 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31568 textboxEl.enableDisplayMode();
31569 textboxEl.addKeyListener([10,13], function(){
31570 if(dlg.isVisible() && opt && opt.buttons){
31571 if(opt.buttons.ok){
31572 handleButton("ok");
31573 }else if(opt.buttons.yes){
31574 handleButton("yes");
31578 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31579 textareaEl.enableDisplayMode();
31580 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31581 progressEl.enableDisplayMode();
31582 var pf = progressEl.dom.firstChild;
31584 pp = Roo.get(pf.firstChild);
31585 pp.setHeight(pf.offsetHeight);
31593 * Updates the message box body text
31594 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31595 * the XHTML-compliant non-breaking space character '&#160;')
31596 * @return {Roo.MessageBox} This message box
31598 updateText : function(text){
31599 if(!dlg.isVisible() && !opt.width){
31600 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31602 msgEl.innerHTML = text || ' ';
31604 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31605 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31607 Math.min(opt.width || cw , this.maxWidth),
31608 Math.max(opt.minWidth || this.minWidth, bwidth)
31611 activeTextEl.setWidth(w);
31613 if(dlg.isVisible()){
31614 dlg.fixedcenter = false;
31616 // to big, make it scroll. = But as usual stupid IE does not support
31619 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31620 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31621 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31623 bodyEl.dom.style.height = '';
31624 bodyEl.dom.style.overflowY = '';
31627 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31629 bodyEl.dom.style.overflowX = '';
31632 dlg.setContentSize(w, bodyEl.getHeight());
31633 if(dlg.isVisible()){
31634 dlg.fixedcenter = true;
31640 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31641 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31642 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31643 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31644 * @return {Roo.MessageBox} This message box
31646 updateProgress : function(value, text){
31648 this.updateText(text);
31650 if (pp) { // weird bug on my firefox - for some reason this is not defined
31651 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31657 * Returns true if the message box is currently displayed
31658 * @return {Boolean} True if the message box is visible, else false
31660 isVisible : function(){
31661 return dlg && dlg.isVisible();
31665 * Hides the message box if it is displayed
31668 if(this.isVisible()){
31674 * Displays a new message box, or reinitializes an existing message box, based on the config options
31675 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31676 * The following config object properties are supported:
31678 Property Type Description
31679 ---------- --------------- ------------------------------------------------------------------------------------
31680 animEl String/Element An id or Element from which the message box should animate as it opens and
31681 closes (defaults to undefined)
31682 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31683 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31684 closable Boolean False to hide the top-right close button (defaults to true). Note that
31685 progress and wait dialogs will ignore this property and always hide the
31686 close button as they can only be closed programmatically.
31687 cls String A custom CSS class to apply to the message box element
31688 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31689 displayed (defaults to 75)
31690 fn Function A callback function to execute after closing the dialog. The arguments to the
31691 function will be btn (the name of the button that was clicked, if applicable,
31692 e.g. "ok"), and text (the value of the active text field, if applicable).
31693 Progress and wait dialogs will ignore this option since they do not respond to
31694 user actions and can only be closed programmatically, so any required function
31695 should be called by the same code after it closes the dialog.
31696 icon String A CSS class that provides a background image to be used as an icon for
31697 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31698 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31699 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31700 modal Boolean False to allow user interaction with the page while the message box is
31701 displayed (defaults to true)
31702 msg String A string that will replace the existing message box body text (defaults
31703 to the XHTML-compliant non-breaking space character ' ')
31704 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31705 progress Boolean True to display a progress bar (defaults to false)
31706 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31707 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31708 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31709 title String The title text
31710 value String The string value to set into the active textbox element if displayed
31711 wait Boolean True to display a progress bar (defaults to false)
31712 width Number The width of the dialog in pixels
31719 msg: 'Please enter your address:',
31721 buttons: Roo.MessageBox.OKCANCEL,
31724 animEl: 'addAddressBtn'
31727 * @param {Object} config Configuration options
31728 * @return {Roo.MessageBox} This message box
31730 show : function(options)
31733 // this causes nightmares if you show one dialog after another
31734 // especially on callbacks..
31736 if(this.isVisible()){
31739 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31740 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31741 Roo.log("New Dialog Message:" + options.msg )
31742 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31743 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31746 var d = this.getDialog();
31748 d.setTitle(opt.title || " ");
31749 d.close.setDisplayed(opt.closable !== false);
31750 activeTextEl = textboxEl;
31751 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31756 textareaEl.setHeight(typeof opt.multiline == "number" ?
31757 opt.multiline : this.defaultTextHeight);
31758 activeTextEl = textareaEl;
31767 progressEl.setDisplayed(opt.progress === true);
31768 this.updateProgress(0);
31769 activeTextEl.dom.value = opt.value || "";
31771 dlg.setDefaultButton(activeTextEl);
31773 var bs = opt.buttons;
31776 db = buttons["ok"];
31777 }else if(bs && bs.yes){
31778 db = buttons["yes"];
31780 dlg.setDefaultButton(db);
31782 bwidth = updateButtons(opt.buttons);
31783 this.updateText(opt.msg);
31785 d.el.addClass(opt.cls);
31787 d.proxyDrag = opt.proxyDrag === true;
31788 d.modal = opt.modal !== false;
31789 d.mask = opt.modal !== false ? mask : false;
31790 if(!d.isVisible()){
31791 // force it to the end of the z-index stack so it gets a cursor in FF
31792 document.body.appendChild(dlg.el.dom);
31793 d.animateTarget = null;
31794 d.show(options.animEl);
31800 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31801 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31802 * and closing the message box when the process is complete.
31803 * @param {String} title The title bar text
31804 * @param {String} msg The message box body text
31805 * @return {Roo.MessageBox} This message box
31807 progress : function(title, msg){
31814 minWidth: this.minProgressWidth,
31821 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31822 * If a callback function is passed it will be called after the user clicks the button, and the
31823 * id of the button that was clicked will be passed as the only parameter to the callback
31824 * (could also be the top-right close button).
31825 * @param {String} title The title bar text
31826 * @param {String} msg The message box body text
31827 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31828 * @param {Object} scope (optional) The scope of the callback function
31829 * @return {Roo.MessageBox} This message box
31831 alert : function(title, msg, fn, scope){
31844 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31845 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31846 * You are responsible for closing the message box when the process is complete.
31847 * @param {String} msg The message box body text
31848 * @param {String} title (optional) The title bar text
31849 * @return {Roo.MessageBox} This message box
31851 wait : function(msg, title){
31862 waitTimer = Roo.TaskMgr.start({
31864 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31872 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31873 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31874 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31875 * @param {String} title The title bar text
31876 * @param {String} msg The message box body text
31877 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31878 * @param {Object} scope (optional) The scope of the callback function
31879 * @return {Roo.MessageBox} This message box
31881 confirm : function(title, msg, fn, scope){
31885 buttons: this.YESNO,
31894 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31895 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31896 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31897 * (could also be the top-right close button) and the text that was entered will be passed as the two
31898 * parameters to the callback.
31899 * @param {String} title The title bar text
31900 * @param {String} msg The message box body text
31901 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31902 * @param {Object} scope (optional) The scope of the callback function
31903 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31904 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31905 * @return {Roo.MessageBox} This message box
31907 prompt : function(title, msg, fn, scope, multiline){
31911 buttons: this.OKCANCEL,
31916 multiline: multiline,
31923 * Button config that displays a single OK button
31928 * Button config that displays Yes and No buttons
31931 YESNO : {yes:true, no:true},
31933 * Button config that displays OK and Cancel buttons
31936 OKCANCEL : {ok:true, cancel:true},
31938 * Button config that displays Yes, No and Cancel buttons
31941 YESNOCANCEL : {yes:true, no:true, cancel:true},
31944 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31947 defaultTextHeight : 75,
31949 * The maximum width in pixels of the message box (defaults to 600)
31954 * The minimum width in pixels of the message box (defaults to 100)
31959 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31960 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31963 minProgressWidth : 250,
31965 * An object containing the default button text strings that can be overriden for localized language support.
31966 * Supported properties are: ok, cancel, yes and no.
31967 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31980 * Shorthand for {@link Roo.MessageBox}
31982 Roo.Msg = Roo.MessageBox;/*
31984 * Ext JS Library 1.1.1
31985 * Copyright(c) 2006-2007, Ext JS, LLC.
31987 * Originally Released Under LGPL - original licence link has changed is not relivant.
31990 * <script type="text/javascript">
31993 * @class Roo.QuickTips
31994 * Provides attractive and customizable tooltips for any element.
31997 Roo.QuickTips = function(){
31998 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31999 var ce, bd, xy, dd;
32000 var visible = false, disabled = true, inited = false;
32001 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
32003 var onOver = function(e){
32007 var t = e.getTarget();
32008 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32011 if(ce && t == ce.el){
32012 clearTimeout(hideProc);
32015 if(t && tagEls[t.id]){
32016 tagEls[t.id].el = t;
32017 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32020 var ttp, et = Roo.fly(t);
32021 var ns = cfg.namespace;
32022 if(tm.interceptTitles && t.title){
32025 t.removeAttribute("title");
32026 e.preventDefault();
32028 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32031 showProc = show.defer(tm.showDelay, tm, [{
32034 width: et.getAttributeNS(ns, cfg.width),
32035 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32036 title: et.getAttributeNS(ns, cfg.title),
32037 cls: et.getAttributeNS(ns, cfg.cls)
32042 var onOut = function(e){
32043 clearTimeout(showProc);
32044 var t = e.getTarget();
32045 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32046 hideProc = setTimeout(hide, tm.hideDelay);
32050 var onMove = function(e){
32056 if(tm.trackMouse && ce){
32061 var onDown = function(e){
32062 clearTimeout(showProc);
32063 clearTimeout(hideProc);
32065 if(tm.hideOnClick){
32068 tm.enable.defer(100, tm);
32073 var getPad = function(){
32074 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32077 var show = function(o){
32081 clearTimeout(dismissProc);
32083 if(removeCls){ // in case manually hidden
32084 el.removeClass(removeCls);
32088 el.addClass(ce.cls);
32089 removeCls = ce.cls;
32092 tipTitle.update(ce.title);
32095 tipTitle.update('');
32098 el.dom.style.width = tm.maxWidth+'px';
32099 //tipBody.dom.style.width = '';
32100 tipBodyText.update(o.text);
32101 var p = getPad(), w = ce.width;
32103 var td = tipBodyText.dom;
32104 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32105 if(aw > tm.maxWidth){
32107 }else if(aw < tm.minWidth){
32113 //tipBody.setWidth(w);
32114 el.setWidth(parseInt(w, 10) + p);
32115 if(ce.autoHide === false){
32116 close.setDisplayed(true);
32121 close.setDisplayed(false);
32127 el.avoidY = xy[1]-18;
32132 el.setStyle("visibility", "visible");
32133 el.fadeIn({callback: afterShow});
32139 var afterShow = function(){
32143 if(tm.autoDismiss && ce.autoHide !== false){
32144 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32149 var hide = function(noanim){
32150 clearTimeout(dismissProc);
32151 clearTimeout(hideProc);
32153 if(el.isVisible()){
32155 if(noanim !== true && tm.animate){
32156 el.fadeOut({callback: afterHide});
32163 var afterHide = function(){
32166 el.removeClass(removeCls);
32173 * @cfg {Number} minWidth
32174 * The minimum width of the quick tip (defaults to 40)
32178 * @cfg {Number} maxWidth
32179 * The maximum width of the quick tip (defaults to 300)
32183 * @cfg {Boolean} interceptTitles
32184 * True to automatically use the element's DOM title value if available (defaults to false)
32186 interceptTitles : false,
32188 * @cfg {Boolean} trackMouse
32189 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32191 trackMouse : false,
32193 * @cfg {Boolean} hideOnClick
32194 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32196 hideOnClick : true,
32198 * @cfg {Number} showDelay
32199 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32203 * @cfg {Number} hideDelay
32204 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32208 * @cfg {Boolean} autoHide
32209 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32210 * Used in conjunction with hideDelay.
32215 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32216 * (defaults to true). Used in conjunction with autoDismissDelay.
32218 autoDismiss : true,
32221 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32223 autoDismissDelay : 5000,
32225 * @cfg {Boolean} animate
32226 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32231 * @cfg {String} title
32232 * Title text to display (defaults to ''). This can be any valid HTML markup.
32236 * @cfg {String} text
32237 * Body text to display (defaults to ''). This can be any valid HTML markup.
32241 * @cfg {String} cls
32242 * A CSS class to apply to the base quick tip element (defaults to '').
32246 * @cfg {Number} width
32247 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32248 * minWidth or maxWidth.
32253 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32254 * or display QuickTips in a page.
32257 tm = Roo.QuickTips;
32258 cfg = tm.tagConfig;
32260 if(!Roo.isReady){ // allow calling of init() before onReady
32261 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32264 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32265 el.fxDefaults = {stopFx: true};
32266 // maximum custom styling
32267 //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>');
32268 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>');
32269 tipTitle = el.child('h3');
32270 tipTitle.enableDisplayMode("block");
32271 tipBody = el.child('div.x-tip-bd');
32272 tipBodyText = el.child('div.x-tip-bd-inner');
32273 //bdLeft = el.child('div.x-tip-bd-left');
32274 //bdRight = el.child('div.x-tip-bd-right');
32275 close = el.child('div.x-tip-close');
32276 close.enableDisplayMode("block");
32277 close.on("click", hide);
32278 var d = Roo.get(document);
32279 d.on("mousedown", onDown);
32280 d.on("mouseover", onOver);
32281 d.on("mouseout", onOut);
32282 d.on("mousemove", onMove);
32283 esc = d.addKeyListener(27, hide);
32286 dd = el.initDD("default", null, {
32287 onDrag : function(){
32291 dd.setHandleElId(tipTitle.id);
32300 * Configures a new quick tip instance and assigns it to a target element. The following config options
32303 Property Type Description
32304 ---------- --------------------- ------------------------------------------------------------------------
32305 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32307 * @param {Object} config The config object
32309 register : function(config){
32310 var cs = config instanceof Array ? config : arguments;
32311 for(var i = 0, len = cs.length; i < len; i++) {
32313 var target = c.target;
32315 if(target instanceof Array){
32316 for(var j = 0, jlen = target.length; j < jlen; j++){
32317 tagEls[target[j]] = c;
32320 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32327 * Removes this quick tip from its element and destroys it.
32328 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32330 unregister : function(el){
32331 delete tagEls[Roo.id(el)];
32335 * Enable this quick tip.
32337 enable : function(){
32338 if(inited && disabled){
32340 if(locks.length < 1){
32347 * Disable this quick tip.
32349 disable : function(){
32351 clearTimeout(showProc);
32352 clearTimeout(hideProc);
32353 clearTimeout(dismissProc);
32361 * Returns true if the quick tip is enabled, else false.
32363 isEnabled : function(){
32370 attribute : "qtip",
32380 // backwards compat
32381 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32383 * Ext JS Library 1.1.1
32384 * Copyright(c) 2006-2007, Ext JS, LLC.
32386 * Originally Released Under LGPL - original licence link has changed is not relivant.
32389 * <script type="text/javascript">
32394 * @class Roo.tree.TreePanel
32395 * @extends Roo.data.Tree
32397 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32398 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32399 * @cfg {Boolean} enableDD true to enable drag and drop
32400 * @cfg {Boolean} enableDrag true to enable just drag
32401 * @cfg {Boolean} enableDrop true to enable just drop
32402 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32403 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32404 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32405 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32406 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32407 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32408 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32409 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32410 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32411 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32412 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32413 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32414 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32415 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32416 * @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>
32417 * @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>
32420 * @param {String/HTMLElement/Element} el The container element
32421 * @param {Object} config
32423 Roo.tree.TreePanel = function(el, config){
32425 var loader = false;
32427 root = config.root;
32428 delete config.root;
32430 if (config.loader) {
32431 loader = config.loader;
32432 delete config.loader;
32435 Roo.apply(this, config);
32436 Roo.tree.TreePanel.superclass.constructor.call(this);
32437 this.el = Roo.get(el);
32438 this.el.addClass('x-tree');
32439 //console.log(root);
32441 this.setRootNode( Roo.factory(root, Roo.tree));
32444 this.loader = Roo.factory(loader, Roo.tree);
32447 * Read-only. The id of the container element becomes this TreePanel's id.
32449 this.id = this.el.id;
32452 * @event beforeload
32453 * Fires before a node is loaded, return false to cancel
32454 * @param {Node} node The node being loaded
32456 "beforeload" : true,
32459 * Fires when a node is loaded
32460 * @param {Node} node The node that was loaded
32464 * @event textchange
32465 * Fires when the text for a node is changed
32466 * @param {Node} node The node
32467 * @param {String} text The new text
32468 * @param {String} oldText The old text
32470 "textchange" : true,
32472 * @event beforeexpand
32473 * Fires before a node is expanded, return false to cancel.
32474 * @param {Node} node The node
32475 * @param {Boolean} deep
32476 * @param {Boolean} anim
32478 "beforeexpand" : true,
32480 * @event beforecollapse
32481 * Fires before a node is collapsed, return false to cancel.
32482 * @param {Node} node The node
32483 * @param {Boolean} deep
32484 * @param {Boolean} anim
32486 "beforecollapse" : true,
32489 * Fires when a node is expanded
32490 * @param {Node} node The node
32494 * @event disabledchange
32495 * Fires when the disabled status of a node changes
32496 * @param {Node} node The node
32497 * @param {Boolean} disabled
32499 "disabledchange" : true,
32502 * Fires when a node is collapsed
32503 * @param {Node} node The node
32507 * @event beforeclick
32508 * Fires before click processing on a node. Return false to cancel the default action.
32509 * @param {Node} node The node
32510 * @param {Roo.EventObject} e The event object
32512 "beforeclick":true,
32514 * @event checkchange
32515 * Fires when a node with a checkbox's checked property changes
32516 * @param {Node} this This node
32517 * @param {Boolean} checked
32519 "checkchange":true,
32522 * Fires when a node is clicked
32523 * @param {Node} node The node
32524 * @param {Roo.EventObject} e The event object
32529 * Fires when a node is double clicked
32530 * @param {Node} node The node
32531 * @param {Roo.EventObject} e The event object
32535 * @event contextmenu
32536 * Fires when a node is right clicked
32537 * @param {Node} node The node
32538 * @param {Roo.EventObject} e The event object
32540 "contextmenu":true,
32542 * @event beforechildrenrendered
32543 * Fires right before the child nodes for a node are rendered
32544 * @param {Node} node The node
32546 "beforechildrenrendered":true,
32549 * Fires when a node starts being dragged
32550 * @param {Roo.tree.TreePanel} this
32551 * @param {Roo.tree.TreeNode} node
32552 * @param {event} e The raw browser event
32554 "startdrag" : true,
32557 * Fires when a drag operation is complete
32558 * @param {Roo.tree.TreePanel} this
32559 * @param {Roo.tree.TreeNode} node
32560 * @param {event} e The raw browser event
32565 * Fires when a dragged node is dropped on a valid DD target
32566 * @param {Roo.tree.TreePanel} this
32567 * @param {Roo.tree.TreeNode} node
32568 * @param {DD} dd The dd it was dropped on
32569 * @param {event} e The raw browser event
32573 * @event beforenodedrop
32574 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32575 * passed to handlers has the following properties:<br />
32576 * <ul style="padding:5px;padding-left:16px;">
32577 * <li>tree - The TreePanel</li>
32578 * <li>target - The node being targeted for the drop</li>
32579 * <li>data - The drag data from the drag source</li>
32580 * <li>point - The point of the drop - append, above or below</li>
32581 * <li>source - The drag source</li>
32582 * <li>rawEvent - Raw mouse event</li>
32583 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32584 * to be inserted by setting them on this object.</li>
32585 * <li>cancel - Set this to true to cancel the drop.</li>
32587 * @param {Object} dropEvent
32589 "beforenodedrop" : true,
32592 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32593 * passed to handlers has the following properties:<br />
32594 * <ul style="padding:5px;padding-left:16px;">
32595 * <li>tree - The TreePanel</li>
32596 * <li>target - The node being targeted for the drop</li>
32597 * <li>data - The drag data from the drag source</li>
32598 * <li>point - The point of the drop - append, above or below</li>
32599 * <li>source - The drag source</li>
32600 * <li>rawEvent - Raw mouse event</li>
32601 * <li>dropNode - Dropped node(s).</li>
32603 * @param {Object} dropEvent
32607 * @event nodedragover
32608 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32609 * passed to handlers has the following properties:<br />
32610 * <ul style="padding:5px;padding-left:16px;">
32611 * <li>tree - The TreePanel</li>
32612 * <li>target - The node being targeted for the drop</li>
32613 * <li>data - The drag data from the drag source</li>
32614 * <li>point - The point of the drop - append, above or below</li>
32615 * <li>source - The drag source</li>
32616 * <li>rawEvent - Raw mouse event</li>
32617 * <li>dropNode - Drop node(s) provided by the source.</li>
32618 * <li>cancel - Set this to true to signal drop not allowed.</li>
32620 * @param {Object} dragOverEvent
32622 "nodedragover" : true
32625 if(this.singleExpand){
32626 this.on("beforeexpand", this.restrictExpand, this);
32629 this.editor.tree = this;
32630 this.editor = Roo.factory(this.editor, Roo.tree);
32633 if (this.selModel) {
32634 this.selModel = Roo.factory(this.selModel, Roo.tree);
32638 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32639 rootVisible : true,
32640 animate: Roo.enableFx,
32643 hlDrop : Roo.enableFx,
32647 rendererTip: false,
32649 restrictExpand : function(node){
32650 var p = node.parentNode;
32652 if(p.expandedChild && p.expandedChild.parentNode == p){
32653 p.expandedChild.collapse();
32655 p.expandedChild = node;
32659 // private override
32660 setRootNode : function(node){
32661 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32662 if(!this.rootVisible){
32663 node.ui = new Roo.tree.RootTreeNodeUI(node);
32669 * Returns the container element for this TreePanel
32671 getEl : function(){
32676 * Returns the default TreeLoader for this TreePanel
32678 getLoader : function(){
32679 return this.loader;
32685 expandAll : function(){
32686 this.root.expand(true);
32690 * Collapse all nodes
32692 collapseAll : function(){
32693 this.root.collapse(true);
32697 * Returns the selection model used by this TreePanel
32699 getSelectionModel : function(){
32700 if(!this.selModel){
32701 this.selModel = new Roo.tree.DefaultSelectionModel();
32703 return this.selModel;
32707 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32708 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32709 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32712 getChecked : function(a, startNode){
32713 startNode = startNode || this.root;
32715 var f = function(){
32716 if(this.attributes.checked){
32717 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32720 startNode.cascade(f);
32725 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32726 * @param {String} path
32727 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32728 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32729 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32731 expandPath : function(path, attr, callback){
32732 attr = attr || "id";
32733 var keys = path.split(this.pathSeparator);
32734 var curNode = this.root;
32735 if(curNode.attributes[attr] != keys[1]){ // invalid root
32737 callback(false, null);
32742 var f = function(){
32743 if(++index == keys.length){
32745 callback(true, curNode);
32749 var c = curNode.findChild(attr, keys[index]);
32752 callback(false, curNode);
32757 c.expand(false, false, f);
32759 curNode.expand(false, false, f);
32763 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32764 * @param {String} path
32765 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32766 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32767 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32769 selectPath : function(path, attr, callback){
32770 attr = attr || "id";
32771 var keys = path.split(this.pathSeparator);
32772 var v = keys.pop();
32773 if(keys.length > 0){
32774 var f = function(success, node){
32775 if(success && node){
32776 var n = node.findChild(attr, v);
32782 }else if(callback){
32783 callback(false, n);
32787 callback(false, n);
32791 this.expandPath(keys.join(this.pathSeparator), attr, f);
32793 this.root.select();
32795 callback(true, this.root);
32800 getTreeEl : function(){
32805 * Trigger rendering of this TreePanel
32807 render : function(){
32808 if (this.innerCt) {
32809 return this; // stop it rendering more than once!!
32812 this.innerCt = this.el.createChild({tag:"ul",
32813 cls:"x-tree-root-ct " +
32814 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32816 if(this.containerScroll){
32817 Roo.dd.ScrollManager.register(this.el);
32819 if((this.enableDD || this.enableDrop) && !this.dropZone){
32821 * The dropZone used by this tree if drop is enabled
32822 * @type Roo.tree.TreeDropZone
32824 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32825 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32828 if((this.enableDD || this.enableDrag) && !this.dragZone){
32830 * The dragZone used by this tree if drag is enabled
32831 * @type Roo.tree.TreeDragZone
32833 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32834 ddGroup: this.ddGroup || "TreeDD",
32835 scroll: this.ddScroll
32838 this.getSelectionModel().init(this);
32840 Roo.log("ROOT not set in tree");
32843 this.root.render();
32844 if(!this.rootVisible){
32845 this.root.renderChildren();
32851 * Ext JS Library 1.1.1
32852 * Copyright(c) 2006-2007, Ext JS, LLC.
32854 * Originally Released Under LGPL - original licence link has changed is not relivant.
32857 * <script type="text/javascript">
32862 * @class Roo.tree.DefaultSelectionModel
32863 * @extends Roo.util.Observable
32864 * The default single selection for a TreePanel.
32865 * @param {Object} cfg Configuration
32867 Roo.tree.DefaultSelectionModel = function(cfg){
32868 this.selNode = null;
32874 * @event selectionchange
32875 * Fires when the selected node changes
32876 * @param {DefaultSelectionModel} this
32877 * @param {TreeNode} node the new selection
32879 "selectionchange" : true,
32882 * @event beforeselect
32883 * Fires before the selected node changes, return false to cancel the change
32884 * @param {DefaultSelectionModel} this
32885 * @param {TreeNode} node the new selection
32886 * @param {TreeNode} node the old selection
32888 "beforeselect" : true
32891 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32894 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32895 init : function(tree){
32897 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32898 tree.on("click", this.onNodeClick, this);
32901 onNodeClick : function(node, e){
32902 if (e.ctrlKey && this.selNode == node) {
32903 this.unselect(node);
32911 * @param {TreeNode} node The node to select
32912 * @return {TreeNode} The selected node
32914 select : function(node){
32915 var last = this.selNode;
32916 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32918 last.ui.onSelectedChange(false);
32920 this.selNode = node;
32921 node.ui.onSelectedChange(true);
32922 this.fireEvent("selectionchange", this, node, last);
32929 * @param {TreeNode} node The node to unselect
32931 unselect : function(node){
32932 if(this.selNode == node){
32933 this.clearSelections();
32938 * Clear all selections
32940 clearSelections : function(){
32941 var n = this.selNode;
32943 n.ui.onSelectedChange(false);
32944 this.selNode = null;
32945 this.fireEvent("selectionchange", this, null);
32951 * Get the selected node
32952 * @return {TreeNode} The selected node
32954 getSelectedNode : function(){
32955 return this.selNode;
32959 * Returns true if the node is selected
32960 * @param {TreeNode} node The node to check
32961 * @return {Boolean}
32963 isSelected : function(node){
32964 return this.selNode == node;
32968 * Selects the node above the selected node in the tree, intelligently walking the nodes
32969 * @return TreeNode The new selection
32971 selectPrevious : function(){
32972 var s = this.selNode || this.lastSelNode;
32976 var ps = s.previousSibling;
32978 if(!ps.isExpanded() || ps.childNodes.length < 1){
32979 return this.select(ps);
32981 var lc = ps.lastChild;
32982 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32985 return this.select(lc);
32987 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32988 return this.select(s.parentNode);
32994 * Selects the node above the selected node in the tree, intelligently walking the nodes
32995 * @return TreeNode The new selection
32997 selectNext : function(){
32998 var s = this.selNode || this.lastSelNode;
33002 if(s.firstChild && s.isExpanded()){
33003 return this.select(s.firstChild);
33004 }else if(s.nextSibling){
33005 return this.select(s.nextSibling);
33006 }else if(s.parentNode){
33008 s.parentNode.bubble(function(){
33009 if(this.nextSibling){
33010 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33019 onKeyDown : function(e){
33020 var s = this.selNode || this.lastSelNode;
33021 // undesirable, but required
33026 var k = e.getKey();
33034 this.selectPrevious();
33037 e.preventDefault();
33038 if(s.hasChildNodes()){
33039 if(!s.isExpanded()){
33041 }else if(s.firstChild){
33042 this.select(s.firstChild, e);
33047 e.preventDefault();
33048 if(s.hasChildNodes() && s.isExpanded()){
33050 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33051 this.select(s.parentNode, e);
33059 * @class Roo.tree.MultiSelectionModel
33060 * @extends Roo.util.Observable
33061 * Multi selection for a TreePanel.
33062 * @param {Object} cfg Configuration
33064 Roo.tree.MultiSelectionModel = function(){
33065 this.selNodes = [];
33069 * @event selectionchange
33070 * Fires when the selected nodes change
33071 * @param {MultiSelectionModel} this
33072 * @param {Array} nodes Array of the selected nodes
33074 "selectionchange" : true
33076 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33080 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33081 init : function(tree){
33083 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33084 tree.on("click", this.onNodeClick, this);
33087 onNodeClick : function(node, e){
33088 this.select(node, e, e.ctrlKey);
33093 * @param {TreeNode} node The node to select
33094 * @param {EventObject} e (optional) An event associated with the selection
33095 * @param {Boolean} keepExisting True to retain existing selections
33096 * @return {TreeNode} The selected node
33098 select : function(node, e, keepExisting){
33099 if(keepExisting !== true){
33100 this.clearSelections(true);
33102 if(this.isSelected(node)){
33103 this.lastSelNode = node;
33106 this.selNodes.push(node);
33107 this.selMap[node.id] = node;
33108 this.lastSelNode = node;
33109 node.ui.onSelectedChange(true);
33110 this.fireEvent("selectionchange", this, this.selNodes);
33116 * @param {TreeNode} node The node to unselect
33118 unselect : function(node){
33119 if(this.selMap[node.id]){
33120 node.ui.onSelectedChange(false);
33121 var sn = this.selNodes;
33124 index = sn.indexOf(node);
33126 for(var i = 0, len = sn.length; i < len; i++){
33134 this.selNodes.splice(index, 1);
33136 delete this.selMap[node.id];
33137 this.fireEvent("selectionchange", this, this.selNodes);
33142 * Clear all selections
33144 clearSelections : function(suppressEvent){
33145 var sn = this.selNodes;
33147 for(var i = 0, len = sn.length; i < len; i++){
33148 sn[i].ui.onSelectedChange(false);
33150 this.selNodes = [];
33152 if(suppressEvent !== true){
33153 this.fireEvent("selectionchange", this, this.selNodes);
33159 * Returns true if the node is selected
33160 * @param {TreeNode} node The node to check
33161 * @return {Boolean}
33163 isSelected : function(node){
33164 return this.selMap[node.id] ? true : false;
33168 * Returns an array of the selected nodes
33171 getSelectedNodes : function(){
33172 return this.selNodes;
33175 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33177 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33179 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33182 * Ext JS Library 1.1.1
33183 * Copyright(c) 2006-2007, Ext JS, LLC.
33185 * Originally Released Under LGPL - original licence link has changed is not relivant.
33188 * <script type="text/javascript">
33192 * @class Roo.tree.TreeNode
33193 * @extends Roo.data.Node
33194 * @cfg {String} text The text for this node
33195 * @cfg {Boolean} expanded true to start the node expanded
33196 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33197 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33198 * @cfg {Boolean} disabled true to start the node disabled
33199 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33200 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33201 * @cfg {String} cls A css class to be added to the node
33202 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33203 * @cfg {String} href URL of the link used for the node (defaults to #)
33204 * @cfg {String} hrefTarget target frame for the link
33205 * @cfg {String} qtip An Ext QuickTip for the node
33206 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33207 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33208 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33209 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33210 * (defaults to undefined with no checkbox rendered)
33212 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33214 Roo.tree.TreeNode = function(attributes){
33215 attributes = attributes || {};
33216 if(typeof attributes == "string"){
33217 attributes = {text: attributes};
33219 this.childrenRendered = false;
33220 this.rendered = false;
33221 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33222 this.expanded = attributes.expanded === true;
33223 this.isTarget = attributes.isTarget !== false;
33224 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33225 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33228 * Read-only. The text for this node. To change it use setText().
33231 this.text = attributes.text;
33233 * True if this node is disabled.
33236 this.disabled = attributes.disabled === true;
33240 * @event textchange
33241 * Fires when the text for this node is changed
33242 * @param {Node} this This node
33243 * @param {String} text The new text
33244 * @param {String} oldText The old text
33246 "textchange" : true,
33248 * @event beforeexpand
33249 * Fires before this node is expanded, return false to cancel.
33250 * @param {Node} this This node
33251 * @param {Boolean} deep
33252 * @param {Boolean} anim
33254 "beforeexpand" : true,
33256 * @event beforecollapse
33257 * Fires before this node is collapsed, return false to cancel.
33258 * @param {Node} this This node
33259 * @param {Boolean} deep
33260 * @param {Boolean} anim
33262 "beforecollapse" : true,
33265 * Fires when this node is expanded
33266 * @param {Node} this This node
33270 * @event disabledchange
33271 * Fires when the disabled status of this node changes
33272 * @param {Node} this This node
33273 * @param {Boolean} disabled
33275 "disabledchange" : true,
33278 * Fires when this node is collapsed
33279 * @param {Node} this This node
33283 * @event beforeclick
33284 * Fires before click processing. Return false to cancel the default action.
33285 * @param {Node} this This node
33286 * @param {Roo.EventObject} e The event object
33288 "beforeclick":true,
33290 * @event checkchange
33291 * Fires when a node with a checkbox's checked property changes
33292 * @param {Node} this This node
33293 * @param {Boolean} checked
33295 "checkchange":true,
33298 * Fires when this node is clicked
33299 * @param {Node} this This node
33300 * @param {Roo.EventObject} e The event object
33305 * Fires when this node is double clicked
33306 * @param {Node} this This node
33307 * @param {Roo.EventObject} e The event object
33311 * @event contextmenu
33312 * Fires when this node is right clicked
33313 * @param {Node} this This node
33314 * @param {Roo.EventObject} e The event object
33316 "contextmenu":true,
33318 * @event beforechildrenrendered
33319 * Fires right before the child nodes for this node are rendered
33320 * @param {Node} this This node
33322 "beforechildrenrendered":true
33325 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33328 * Read-only. The UI for this node
33331 this.ui = new uiClass(this);
33333 // finally support items[]
33334 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33339 Roo.each(this.attributes.items, function(c) {
33340 this.appendChild(Roo.factory(c,Roo.Tree));
33342 delete this.attributes.items;
33347 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33348 preventHScroll: true,
33350 * Returns true if this node is expanded
33351 * @return {Boolean}
33353 isExpanded : function(){
33354 return this.expanded;
33358 * Returns the UI object for this node
33359 * @return {TreeNodeUI}
33361 getUI : function(){
33365 // private override
33366 setFirstChild : function(node){
33367 var of = this.firstChild;
33368 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33369 if(this.childrenRendered && of && node != of){
33370 of.renderIndent(true, true);
33373 this.renderIndent(true, true);
33377 // private override
33378 setLastChild : function(node){
33379 var ol = this.lastChild;
33380 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33381 if(this.childrenRendered && ol && node != ol){
33382 ol.renderIndent(true, true);
33385 this.renderIndent(true, true);
33389 // these methods are overridden to provide lazy rendering support
33390 // private override
33391 appendChild : function()
33393 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33394 if(node && this.childrenRendered){
33397 this.ui.updateExpandIcon();
33401 // private override
33402 removeChild : function(node){
33403 this.ownerTree.getSelectionModel().unselect(node);
33404 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33405 // if it's been rendered remove dom node
33406 if(this.childrenRendered){
33409 if(this.childNodes.length < 1){
33410 this.collapse(false, false);
33412 this.ui.updateExpandIcon();
33414 if(!this.firstChild) {
33415 this.childrenRendered = false;
33420 // private override
33421 insertBefore : function(node, refNode){
33422 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33423 if(newNode && refNode && this.childrenRendered){
33426 this.ui.updateExpandIcon();
33431 * Sets the text for this node
33432 * @param {String} text
33434 setText : function(text){
33435 var oldText = this.text;
33437 this.attributes.text = text;
33438 if(this.rendered){ // event without subscribing
33439 this.ui.onTextChange(this, text, oldText);
33441 this.fireEvent("textchange", this, text, oldText);
33445 * Triggers selection of this node
33447 select : function(){
33448 this.getOwnerTree().getSelectionModel().select(this);
33452 * Triggers deselection of this node
33454 unselect : function(){
33455 this.getOwnerTree().getSelectionModel().unselect(this);
33459 * Returns true if this node is selected
33460 * @return {Boolean}
33462 isSelected : function(){
33463 return this.getOwnerTree().getSelectionModel().isSelected(this);
33467 * Expand this node.
33468 * @param {Boolean} deep (optional) True to expand all children as well
33469 * @param {Boolean} anim (optional) false to cancel the default animation
33470 * @param {Function} callback (optional) A callback to be called when
33471 * expanding this node completes (does not wait for deep expand to complete).
33472 * Called with 1 parameter, this node.
33474 expand : function(deep, anim, callback){
33475 if(!this.expanded){
33476 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33479 if(!this.childrenRendered){
33480 this.renderChildren();
33482 this.expanded = true;
33483 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33484 this.ui.animExpand(function(){
33485 this.fireEvent("expand", this);
33486 if(typeof callback == "function"){
33490 this.expandChildNodes(true);
33492 }.createDelegate(this));
33496 this.fireEvent("expand", this);
33497 if(typeof callback == "function"){
33502 if(typeof callback == "function"){
33507 this.expandChildNodes(true);
33511 isHiddenRoot : function(){
33512 return this.isRoot && !this.getOwnerTree().rootVisible;
33516 * Collapse this node.
33517 * @param {Boolean} deep (optional) True to collapse all children as well
33518 * @param {Boolean} anim (optional) false to cancel the default animation
33520 collapse : function(deep, anim){
33521 if(this.expanded && !this.isHiddenRoot()){
33522 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33525 this.expanded = false;
33526 if((this.getOwnerTree().animate && anim !== false) || anim){
33527 this.ui.animCollapse(function(){
33528 this.fireEvent("collapse", this);
33530 this.collapseChildNodes(true);
33532 }.createDelegate(this));
33535 this.ui.collapse();
33536 this.fireEvent("collapse", this);
33540 var cs = this.childNodes;
33541 for(var i = 0, len = cs.length; i < len; i++) {
33542 cs[i].collapse(true, false);
33548 delayedExpand : function(delay){
33549 if(!this.expandProcId){
33550 this.expandProcId = this.expand.defer(delay, this);
33555 cancelExpand : function(){
33556 if(this.expandProcId){
33557 clearTimeout(this.expandProcId);
33559 this.expandProcId = false;
33563 * Toggles expanded/collapsed state of the node
33565 toggle : function(){
33574 * Ensures all parent nodes are expanded
33576 ensureVisible : function(callback){
33577 var tree = this.getOwnerTree();
33578 tree.expandPath(this.parentNode.getPath(), false, function(){
33579 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33580 Roo.callback(callback);
33581 }.createDelegate(this));
33585 * Expand all child nodes
33586 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33588 expandChildNodes : function(deep){
33589 var cs = this.childNodes;
33590 for(var i = 0, len = cs.length; i < len; i++) {
33591 cs[i].expand(deep);
33596 * Collapse all child nodes
33597 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33599 collapseChildNodes : function(deep){
33600 var cs = this.childNodes;
33601 for(var i = 0, len = cs.length; i < len; i++) {
33602 cs[i].collapse(deep);
33607 * Disables this node
33609 disable : function(){
33610 this.disabled = true;
33612 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33613 this.ui.onDisableChange(this, true);
33615 this.fireEvent("disabledchange", this, true);
33619 * Enables this node
33621 enable : function(){
33622 this.disabled = false;
33623 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33624 this.ui.onDisableChange(this, false);
33626 this.fireEvent("disabledchange", this, false);
33630 renderChildren : function(suppressEvent){
33631 if(suppressEvent !== false){
33632 this.fireEvent("beforechildrenrendered", this);
33634 var cs = this.childNodes;
33635 for(var i = 0, len = cs.length; i < len; i++){
33636 cs[i].render(true);
33638 this.childrenRendered = true;
33642 sort : function(fn, scope){
33643 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33644 if(this.childrenRendered){
33645 var cs = this.childNodes;
33646 for(var i = 0, len = cs.length; i < len; i++){
33647 cs[i].render(true);
33653 render : function(bulkRender){
33654 this.ui.render(bulkRender);
33655 if(!this.rendered){
33656 this.rendered = true;
33658 this.expanded = false;
33659 this.expand(false, false);
33665 renderIndent : function(deep, refresh){
33667 this.ui.childIndent = null;
33669 this.ui.renderIndent();
33670 if(deep === true && this.childrenRendered){
33671 var cs = this.childNodes;
33672 for(var i = 0, len = cs.length; i < len; i++){
33673 cs[i].renderIndent(true, refresh);
33679 * Ext JS Library 1.1.1
33680 * Copyright(c) 2006-2007, Ext JS, LLC.
33682 * Originally Released Under LGPL - original licence link has changed is not relivant.
33685 * <script type="text/javascript">
33689 * @class Roo.tree.AsyncTreeNode
33690 * @extends Roo.tree.TreeNode
33691 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33693 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33695 Roo.tree.AsyncTreeNode = function(config){
33696 this.loaded = false;
33697 this.loading = false;
33698 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33700 * @event beforeload
33701 * Fires before this node is loaded, return false to cancel
33702 * @param {Node} this This node
33704 this.addEvents({'beforeload':true, 'load': true});
33707 * Fires when this node is loaded
33708 * @param {Node} this This node
33711 * The loader used by this node (defaults to using the tree's defined loader)
33716 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33717 expand : function(deep, anim, callback){
33718 if(this.loading){ // if an async load is already running, waiting til it's done
33720 var f = function(){
33721 if(!this.loading){ // done loading
33722 clearInterval(timer);
33723 this.expand(deep, anim, callback);
33725 }.createDelegate(this);
33726 timer = setInterval(f, 200);
33730 if(this.fireEvent("beforeload", this) === false){
33733 this.loading = true;
33734 this.ui.beforeLoad(this);
33735 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33737 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33741 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33745 * Returns true if this node is currently loading
33746 * @return {Boolean}
33748 isLoading : function(){
33749 return this.loading;
33752 loadComplete : function(deep, anim, callback){
33753 this.loading = false;
33754 this.loaded = true;
33755 this.ui.afterLoad(this);
33756 this.fireEvent("load", this);
33757 this.expand(deep, anim, callback);
33761 * Returns true if this node has been loaded
33762 * @return {Boolean}
33764 isLoaded : function(){
33765 return this.loaded;
33768 hasChildNodes : function(){
33769 if(!this.isLeaf() && !this.loaded){
33772 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33777 * Trigger a reload for this node
33778 * @param {Function} callback
33780 reload : function(callback){
33781 this.collapse(false, false);
33782 while(this.firstChild){
33783 this.removeChild(this.firstChild);
33785 this.childrenRendered = false;
33786 this.loaded = false;
33787 if(this.isHiddenRoot()){
33788 this.expanded = false;
33790 this.expand(false, false, callback);
33794 * Ext JS Library 1.1.1
33795 * Copyright(c) 2006-2007, Ext JS, LLC.
33797 * Originally Released Under LGPL - original licence link has changed is not relivant.
33800 * <script type="text/javascript">
33804 * @class Roo.tree.TreeNodeUI
33806 * @param {Object} node The node to render
33807 * The TreeNode UI implementation is separate from the
33808 * tree implementation. Unless you are customizing the tree UI,
33809 * you should never have to use this directly.
33811 Roo.tree.TreeNodeUI = function(node){
33813 this.rendered = false;
33814 this.animating = false;
33815 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33818 Roo.tree.TreeNodeUI.prototype = {
33819 removeChild : function(node){
33821 this.ctNode.removeChild(node.ui.getEl());
33825 beforeLoad : function(){
33826 this.addClass("x-tree-node-loading");
33829 afterLoad : function(){
33830 this.removeClass("x-tree-node-loading");
33833 onTextChange : function(node, text, oldText){
33835 this.textNode.innerHTML = text;
33839 onDisableChange : function(node, state){
33840 this.disabled = state;
33842 this.addClass("x-tree-node-disabled");
33844 this.removeClass("x-tree-node-disabled");
33848 onSelectedChange : function(state){
33851 this.addClass("x-tree-selected");
33854 this.removeClass("x-tree-selected");
33858 onMove : function(tree, node, oldParent, newParent, index, refNode){
33859 this.childIndent = null;
33861 var targetNode = newParent.ui.getContainer();
33862 if(!targetNode){//target not rendered
33863 this.holder = document.createElement("div");
33864 this.holder.appendChild(this.wrap);
33867 var insertBefore = refNode ? refNode.ui.getEl() : null;
33869 targetNode.insertBefore(this.wrap, insertBefore);
33871 targetNode.appendChild(this.wrap);
33873 this.node.renderIndent(true);
33877 addClass : function(cls){
33879 Roo.fly(this.elNode).addClass(cls);
33883 removeClass : function(cls){
33885 Roo.fly(this.elNode).removeClass(cls);
33889 remove : function(){
33891 this.holder = document.createElement("div");
33892 this.holder.appendChild(this.wrap);
33896 fireEvent : function(){
33897 return this.node.fireEvent.apply(this.node, arguments);
33900 initEvents : function(){
33901 this.node.on("move", this.onMove, this);
33902 var E = Roo.EventManager;
33903 var a = this.anchor;
33905 var el = Roo.fly(a, '_treeui');
33907 if(Roo.isOpera){ // opera render bug ignores the CSS
33908 el.setStyle("text-decoration", "none");
33911 el.on("click", this.onClick, this);
33912 el.on("dblclick", this.onDblClick, this);
33915 Roo.EventManager.on(this.checkbox,
33916 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33919 el.on("contextmenu", this.onContextMenu, this);
33921 var icon = Roo.fly(this.iconNode);
33922 icon.on("click", this.onClick, this);
33923 icon.on("dblclick", this.onDblClick, this);
33924 icon.on("contextmenu", this.onContextMenu, this);
33925 E.on(this.ecNode, "click", this.ecClick, this, true);
33927 if(this.node.disabled){
33928 this.addClass("x-tree-node-disabled");
33930 if(this.node.hidden){
33931 this.addClass("x-tree-node-disabled");
33933 var ot = this.node.getOwnerTree();
33934 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33935 if(dd && (!this.node.isRoot || ot.rootVisible)){
33936 Roo.dd.Registry.register(this.elNode, {
33938 handles: this.getDDHandles(),
33944 getDDHandles : function(){
33945 return [this.iconNode, this.textNode];
33950 this.wrap.style.display = "none";
33956 this.wrap.style.display = "";
33960 onContextMenu : function(e){
33961 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33962 e.preventDefault();
33964 this.fireEvent("contextmenu", this.node, e);
33968 onClick : function(e){
33973 if(this.fireEvent("beforeclick", this.node, e) !== false){
33974 if(!this.disabled && this.node.attributes.href){
33975 this.fireEvent("click", this.node, e);
33978 e.preventDefault();
33983 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33984 this.node.toggle();
33987 this.fireEvent("click", this.node, e);
33993 onDblClick : function(e){
33994 e.preventDefault();
33999 this.toggleCheck();
34001 if(!this.animating && this.node.hasChildNodes()){
34002 this.node.toggle();
34004 this.fireEvent("dblclick", this.node, e);
34007 onCheckChange : function(){
34008 var checked = this.checkbox.checked;
34009 this.node.attributes.checked = checked;
34010 this.fireEvent('checkchange', this.node, checked);
34013 ecClick : function(e){
34014 if(!this.animating && this.node.hasChildNodes()){
34015 this.node.toggle();
34019 startDrop : function(){
34020 this.dropping = true;
34023 // delayed drop so the click event doesn't get fired on a drop
34024 endDrop : function(){
34025 setTimeout(function(){
34026 this.dropping = false;
34027 }.createDelegate(this), 50);
34030 expand : function(){
34031 this.updateExpandIcon();
34032 this.ctNode.style.display = "";
34035 focus : function(){
34036 if(!this.node.preventHScroll){
34037 try{this.anchor.focus();
34039 }else if(!Roo.isIE){
34041 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34042 var l = noscroll.scrollLeft;
34043 this.anchor.focus();
34044 noscroll.scrollLeft = l;
34049 toggleCheck : function(value){
34050 var cb = this.checkbox;
34052 cb.checked = (value === undefined ? !cb.checked : value);
34058 this.anchor.blur();
34062 animExpand : function(callback){
34063 var ct = Roo.get(this.ctNode);
34065 if(!this.node.hasChildNodes()){
34066 this.updateExpandIcon();
34067 this.ctNode.style.display = "";
34068 Roo.callback(callback);
34071 this.animating = true;
34072 this.updateExpandIcon();
34075 callback : function(){
34076 this.animating = false;
34077 Roo.callback(callback);
34080 duration: this.node.ownerTree.duration || .25
34084 highlight : function(){
34085 var tree = this.node.getOwnerTree();
34086 Roo.fly(this.wrap).highlight(
34087 tree.hlColor || "C3DAF9",
34088 {endColor: tree.hlBaseColor}
34092 collapse : function(){
34093 this.updateExpandIcon();
34094 this.ctNode.style.display = "none";
34097 animCollapse : function(callback){
34098 var ct = Roo.get(this.ctNode);
34099 ct.enableDisplayMode('block');
34102 this.animating = true;
34103 this.updateExpandIcon();
34106 callback : function(){
34107 this.animating = false;
34108 Roo.callback(callback);
34111 duration: this.node.ownerTree.duration || .25
34115 getContainer : function(){
34116 return this.ctNode;
34119 getEl : function(){
34123 appendDDGhost : function(ghostNode){
34124 ghostNode.appendChild(this.elNode.cloneNode(true));
34127 getDDRepairXY : function(){
34128 return Roo.lib.Dom.getXY(this.iconNode);
34131 onRender : function(){
34135 render : function(bulkRender){
34136 var n = this.node, a = n.attributes;
34137 var targetNode = n.parentNode ?
34138 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34140 if(!this.rendered){
34141 this.rendered = true;
34143 this.renderElements(n, a, targetNode, bulkRender);
34146 if(this.textNode.setAttributeNS){
34147 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34149 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34152 this.textNode.setAttribute("ext:qtip", a.qtip);
34154 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34157 }else if(a.qtipCfg){
34158 a.qtipCfg.target = Roo.id(this.textNode);
34159 Roo.QuickTips.register(a.qtipCfg);
34162 if(!this.node.expanded){
34163 this.updateExpandIcon();
34166 if(bulkRender === true) {
34167 targetNode.appendChild(this.wrap);
34172 renderElements : function(n, a, targetNode, bulkRender)
34174 // add some indent caching, this helps performance when rendering a large tree
34175 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34176 var t = n.getOwnerTree();
34177 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34178 if (typeof(n.attributes.html) != 'undefined') {
34179 txt = n.attributes.html;
34181 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34182 var cb = typeof a.checked == 'boolean';
34183 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34184 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34185 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34186 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34187 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34188 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34189 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34190 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34191 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34192 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34195 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34196 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34197 n.nextSibling.ui.getEl(), buf.join(""));
34199 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34202 this.elNode = this.wrap.childNodes[0];
34203 this.ctNode = this.wrap.childNodes[1];
34204 var cs = this.elNode.childNodes;
34205 this.indentNode = cs[0];
34206 this.ecNode = cs[1];
34207 this.iconNode = cs[2];
34210 this.checkbox = cs[3];
34213 this.anchor = cs[index];
34214 this.textNode = cs[index].firstChild;
34217 getAnchor : function(){
34218 return this.anchor;
34221 getTextEl : function(){
34222 return this.textNode;
34225 getIconEl : function(){
34226 return this.iconNode;
34229 isChecked : function(){
34230 return this.checkbox ? this.checkbox.checked : false;
34233 updateExpandIcon : function(){
34235 var n = this.node, c1, c2;
34236 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34237 var hasChild = n.hasChildNodes();
34241 c1 = "x-tree-node-collapsed";
34242 c2 = "x-tree-node-expanded";
34245 c1 = "x-tree-node-expanded";
34246 c2 = "x-tree-node-collapsed";
34249 this.removeClass("x-tree-node-leaf");
34250 this.wasLeaf = false;
34252 if(this.c1 != c1 || this.c2 != c2){
34253 Roo.fly(this.elNode).replaceClass(c1, c2);
34254 this.c1 = c1; this.c2 = c2;
34257 // this changes non-leafs into leafs if they have no children.
34258 // it's not very rational behaviour..
34260 if(!this.wasLeaf && this.node.leaf){
34261 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34264 this.wasLeaf = true;
34267 var ecc = "x-tree-ec-icon "+cls;
34268 if(this.ecc != ecc){
34269 this.ecNode.className = ecc;
34275 getChildIndent : function(){
34276 if(!this.childIndent){
34280 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34282 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34284 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34289 this.childIndent = buf.join("");
34291 return this.childIndent;
34294 renderIndent : function(){
34297 var p = this.node.parentNode;
34299 indent = p.ui.getChildIndent();
34301 if(this.indentMarkup != indent){ // don't rerender if not required
34302 this.indentNode.innerHTML = indent;
34303 this.indentMarkup = indent;
34305 this.updateExpandIcon();
34310 Roo.tree.RootTreeNodeUI = function(){
34311 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34313 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34314 render : function(){
34315 if(!this.rendered){
34316 var targetNode = this.node.ownerTree.innerCt.dom;
34317 this.node.expanded = true;
34318 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34319 this.wrap = this.ctNode = targetNode.firstChild;
34322 collapse : function(){
34324 expand : function(){
34328 * Ext JS Library 1.1.1
34329 * Copyright(c) 2006-2007, Ext JS, LLC.
34331 * Originally Released Under LGPL - original licence link has changed is not relivant.
34334 * <script type="text/javascript">
34337 * @class Roo.tree.TreeLoader
34338 * @extends Roo.util.Observable
34339 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34340 * nodes from a specified URL. The response must be a javascript Array definition
34341 * who's elements are node definition objects. eg:
34346 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34347 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34354 * The old style respose with just an array is still supported, but not recommended.
34357 * A server request is sent, and child nodes are loaded only when a node is expanded.
34358 * The loading node's id is passed to the server under the parameter name "node" to
34359 * enable the server to produce the correct child nodes.
34361 * To pass extra parameters, an event handler may be attached to the "beforeload"
34362 * event, and the parameters specified in the TreeLoader's baseParams property:
34364 myTreeLoader.on("beforeload", function(treeLoader, node) {
34365 this.baseParams.category = node.attributes.category;
34368 * This would pass an HTTP parameter called "category" to the server containing
34369 * the value of the Node's "category" attribute.
34371 * Creates a new Treeloader.
34372 * @param {Object} config A config object containing config properties.
34374 Roo.tree.TreeLoader = function(config){
34375 this.baseParams = {};
34376 this.requestMethod = "POST";
34377 Roo.apply(this, config);
34382 * @event beforeload
34383 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34384 * @param {Object} This TreeLoader object.
34385 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34386 * @param {Object} callback The callback function specified in the {@link #load} call.
34391 * Fires when the node has been successfuly loaded.
34392 * @param {Object} This TreeLoader object.
34393 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34394 * @param {Object} response The response object containing the data from the server.
34398 * @event loadexception
34399 * Fires if the network request failed.
34400 * @param {Object} This TreeLoader object.
34401 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34402 * @param {Object} response The response object containing the data from the server.
34404 loadexception : true,
34407 * Fires before a node is created, enabling you to return custom Node types
34408 * @param {Object} This TreeLoader object.
34409 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34414 Roo.tree.TreeLoader.superclass.constructor.call(this);
34417 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34419 * @cfg {String} dataUrl The URL from which to request a Json string which
34420 * specifies an array of node definition object representing the child nodes
34424 * @cfg {String} requestMethod either GET or POST
34425 * defaults to POST (due to BC)
34429 * @cfg {Object} baseParams (optional) An object containing properties which
34430 * specify HTTP parameters to be passed to each request for child nodes.
34433 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34434 * created by this loader. If the attributes sent by the server have an attribute in this object,
34435 * they take priority.
34438 * @cfg {Object} uiProviders (optional) An object containing properties which
34440 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34441 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34442 * <i>uiProvider</i> attribute of a returned child node is a string rather
34443 * than a reference to a TreeNodeUI implementation, this that string value
34444 * is used as a property name in the uiProviders object. You can define the provider named
34445 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34450 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34451 * child nodes before loading.
34453 clearOnLoad : true,
34456 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34457 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34458 * Grid query { data : [ .....] }
34463 * @cfg {String} queryParam (optional)
34464 * Name of the query as it will be passed on the querystring (defaults to 'node')
34465 * eg. the request will be ?node=[id]
34472 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34473 * This is called automatically when a node is expanded, but may be used to reload
34474 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34475 * @param {Roo.tree.TreeNode} node
34476 * @param {Function} callback
34478 load : function(node, callback){
34479 if(this.clearOnLoad){
34480 while(node.firstChild){
34481 node.removeChild(node.firstChild);
34484 if(node.attributes.children){ // preloaded json children
34485 var cs = node.attributes.children;
34486 for(var i = 0, len = cs.length; i < len; i++){
34487 node.appendChild(this.createNode(cs[i]));
34489 if(typeof callback == "function"){
34492 }else if(this.dataUrl){
34493 this.requestData(node, callback);
34497 getParams: function(node){
34498 var buf = [], bp = this.baseParams;
34499 for(var key in bp){
34500 if(typeof bp[key] != "function"){
34501 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34504 var n = this.queryParam === false ? 'node' : this.queryParam;
34505 buf.push(n + "=", encodeURIComponent(node.id));
34506 return buf.join("");
34509 requestData : function(node, callback){
34510 if(this.fireEvent("beforeload", this, node, callback) !== false){
34511 this.transId = Roo.Ajax.request({
34512 method:this.requestMethod,
34513 url: this.dataUrl||this.url,
34514 success: this.handleResponse,
34515 failure: this.handleFailure,
34517 argument: {callback: callback, node: node},
34518 params: this.getParams(node)
34521 // if the load is cancelled, make sure we notify
34522 // the node that we are done
34523 if(typeof callback == "function"){
34529 isLoading : function(){
34530 return this.transId ? true : false;
34533 abort : function(){
34534 if(this.isLoading()){
34535 Roo.Ajax.abort(this.transId);
34540 createNode : function(attr)
34542 // apply baseAttrs, nice idea Corey!
34543 if(this.baseAttrs){
34544 Roo.applyIf(attr, this.baseAttrs);
34546 if(this.applyLoader !== false){
34547 attr.loader = this;
34549 // uiProvider = depreciated..
34551 if(typeof(attr.uiProvider) == 'string'){
34552 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34553 /** eval:var:attr */ eval(attr.uiProvider);
34555 if(typeof(this.uiProviders['default']) != 'undefined') {
34556 attr.uiProvider = this.uiProviders['default'];
34559 this.fireEvent('create', this, attr);
34561 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34563 new Roo.tree.TreeNode(attr) :
34564 new Roo.tree.AsyncTreeNode(attr));
34567 processResponse : function(response, node, callback)
34569 var json = response.responseText;
34572 var o = Roo.decode(json);
34574 if (this.root === false && typeof(o.success) != undefined) {
34575 this.root = 'data'; // the default behaviour for list like data..
34578 if (this.root !== false && !o.success) {
34579 // it's a failure condition.
34580 var a = response.argument;
34581 this.fireEvent("loadexception", this, a.node, response);
34582 Roo.log("Load failed - should have a handler really");
34588 if (this.root !== false) {
34592 for(var i = 0, len = o.length; i < len; i++){
34593 var n = this.createNode(o[i]);
34595 node.appendChild(n);
34598 if(typeof callback == "function"){
34599 callback(this, node);
34602 this.handleFailure(response);
34606 handleResponse : function(response){
34607 this.transId = false;
34608 var a = response.argument;
34609 this.processResponse(response, a.node, a.callback);
34610 this.fireEvent("load", this, a.node, response);
34613 handleFailure : function(response)
34615 // should handle failure better..
34616 this.transId = false;
34617 var a = response.argument;
34618 this.fireEvent("loadexception", this, a.node, response);
34619 if(typeof a.callback == "function"){
34620 a.callback(this, a.node);
34625 * Ext JS Library 1.1.1
34626 * Copyright(c) 2006-2007, Ext JS, LLC.
34628 * Originally Released Under LGPL - original licence link has changed is not relivant.
34631 * <script type="text/javascript">
34635 * @class Roo.tree.TreeFilter
34636 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34637 * @param {TreePanel} tree
34638 * @param {Object} config (optional)
34640 Roo.tree.TreeFilter = function(tree, config){
34642 this.filtered = {};
34643 Roo.apply(this, config);
34646 Roo.tree.TreeFilter.prototype = {
34653 * Filter the data by a specific attribute.
34654 * @param {String/RegExp} value Either string that the attribute value
34655 * should start with or a RegExp to test against the attribute
34656 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34657 * @param {TreeNode} startNode (optional) The node to start the filter at.
34659 filter : function(value, attr, startNode){
34660 attr = attr || "text";
34662 if(typeof value == "string"){
34663 var vlen = value.length;
34664 // auto clear empty filter
34665 if(vlen == 0 && this.clearBlank){
34669 value = value.toLowerCase();
34671 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34673 }else if(value.exec){ // regex?
34675 return value.test(n.attributes[attr]);
34678 throw 'Illegal filter type, must be string or regex';
34680 this.filterBy(f, null, startNode);
34684 * Filter by a function. The passed function will be called with each
34685 * node in the tree (or from the startNode). If the function returns true, the node is kept
34686 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34687 * @param {Function} fn The filter function
34688 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34690 filterBy : function(fn, scope, startNode){
34691 startNode = startNode || this.tree.root;
34692 if(this.autoClear){
34695 var af = this.filtered, rv = this.reverse;
34696 var f = function(n){
34697 if(n == startNode){
34703 var m = fn.call(scope || n, n);
34711 startNode.cascade(f);
34714 if(typeof id != "function"){
34716 if(n && n.parentNode){
34717 n.parentNode.removeChild(n);
34725 * Clears the current filter. Note: with the "remove" option
34726 * set a filter cannot be cleared.
34728 clear : function(){
34730 var af = this.filtered;
34732 if(typeof id != "function"){
34739 this.filtered = {};
34744 * Ext JS Library 1.1.1
34745 * Copyright(c) 2006-2007, Ext JS, LLC.
34747 * Originally Released Under LGPL - original licence link has changed is not relivant.
34750 * <script type="text/javascript">
34755 * @class Roo.tree.TreeSorter
34756 * Provides sorting of nodes in a TreePanel
34758 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34759 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34760 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34761 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34762 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34763 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34765 * @param {TreePanel} tree
34766 * @param {Object} config
34768 Roo.tree.TreeSorter = function(tree, config){
34769 Roo.apply(this, config);
34770 tree.on("beforechildrenrendered", this.doSort, this);
34771 tree.on("append", this.updateSort, this);
34772 tree.on("insert", this.updateSort, this);
34774 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34775 var p = this.property || "text";
34776 var sortType = this.sortType;
34777 var fs = this.folderSort;
34778 var cs = this.caseSensitive === true;
34779 var leafAttr = this.leafAttr || 'leaf';
34781 this.sortFn = function(n1, n2){
34783 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34786 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34790 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34791 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34793 return dsc ? +1 : -1;
34795 return dsc ? -1 : +1;
34802 Roo.tree.TreeSorter.prototype = {
34803 doSort : function(node){
34804 node.sort(this.sortFn);
34807 compareNodes : function(n1, n2){
34808 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34811 updateSort : function(tree, node){
34812 if(node.childrenRendered){
34813 this.doSort.defer(1, this, [node]);
34818 * Ext JS Library 1.1.1
34819 * Copyright(c) 2006-2007, Ext JS, LLC.
34821 * Originally Released Under LGPL - original licence link has changed is not relivant.
34824 * <script type="text/javascript">
34827 if(Roo.dd.DropZone){
34829 Roo.tree.TreeDropZone = function(tree, config){
34830 this.allowParentInsert = false;
34831 this.allowContainerDrop = false;
34832 this.appendOnly = false;
34833 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34835 this.lastInsertClass = "x-tree-no-status";
34836 this.dragOverData = {};
34839 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34840 ddGroup : "TreeDD",
34843 expandDelay : 1000,
34845 expandNode : function(node){
34846 if(node.hasChildNodes() && !node.isExpanded()){
34847 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34851 queueExpand : function(node){
34852 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34855 cancelExpand : function(){
34856 if(this.expandProcId){
34857 clearTimeout(this.expandProcId);
34858 this.expandProcId = false;
34862 isValidDropPoint : function(n, pt, dd, e, data){
34863 if(!n || !data){ return false; }
34864 var targetNode = n.node;
34865 var dropNode = data.node;
34866 // default drop rules
34867 if(!(targetNode && targetNode.isTarget && pt)){
34870 if(pt == "append" && targetNode.allowChildren === false){
34873 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34876 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34879 // reuse the object
34880 var overEvent = this.dragOverData;
34881 overEvent.tree = this.tree;
34882 overEvent.target = targetNode;
34883 overEvent.data = data;
34884 overEvent.point = pt;
34885 overEvent.source = dd;
34886 overEvent.rawEvent = e;
34887 overEvent.dropNode = dropNode;
34888 overEvent.cancel = false;
34889 var result = this.tree.fireEvent("nodedragover", overEvent);
34890 return overEvent.cancel === false && result !== false;
34893 getDropPoint : function(e, n, dd)
34897 return tn.allowChildren !== false ? "append" : false; // always append for root
34899 var dragEl = n.ddel;
34900 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34901 var y = Roo.lib.Event.getPageY(e);
34902 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34904 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34905 var noAppend = tn.allowChildren === false;
34906 if(this.appendOnly || tn.parentNode.allowChildren === false){
34907 return noAppend ? false : "append";
34909 var noBelow = false;
34910 if(!this.allowParentInsert){
34911 noBelow = tn.hasChildNodes() && tn.isExpanded();
34913 var q = (b - t) / (noAppend ? 2 : 3);
34914 if(y >= t && y < (t + q)){
34916 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34923 onNodeEnter : function(n, dd, e, data)
34925 this.cancelExpand();
34928 onNodeOver : function(n, dd, e, data)
34931 var pt = this.getDropPoint(e, n, dd);
34934 // auto node expand check
34935 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34936 this.queueExpand(node);
34937 }else if(pt != "append"){
34938 this.cancelExpand();
34941 // set the insert point style on the target node
34942 var returnCls = this.dropNotAllowed;
34943 if(this.isValidDropPoint(n, pt, dd, e, data)){
34948 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34949 cls = "x-tree-drag-insert-above";
34950 }else if(pt == "below"){
34951 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34952 cls = "x-tree-drag-insert-below";
34954 returnCls = "x-tree-drop-ok-append";
34955 cls = "x-tree-drag-append";
34957 if(this.lastInsertClass != cls){
34958 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34959 this.lastInsertClass = cls;
34966 onNodeOut : function(n, dd, e, data){
34968 this.cancelExpand();
34969 this.removeDropIndicators(n);
34972 onNodeDrop : function(n, dd, e, data){
34973 var point = this.getDropPoint(e, n, dd);
34974 var targetNode = n.node;
34975 targetNode.ui.startDrop();
34976 if(!this.isValidDropPoint(n, point, dd, e, data)){
34977 targetNode.ui.endDrop();
34980 // first try to find the drop node
34981 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34984 target: targetNode,
34989 dropNode: dropNode,
34992 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34993 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34994 targetNode.ui.endDrop();
34997 // allow target changing
34998 targetNode = dropEvent.target;
34999 if(point == "append" && !targetNode.isExpanded()){
35000 targetNode.expand(false, null, function(){
35001 this.completeDrop(dropEvent);
35002 }.createDelegate(this));
35004 this.completeDrop(dropEvent);
35009 completeDrop : function(de){
35010 var ns = de.dropNode, p = de.point, t = de.target;
35011 if(!(ns instanceof Array)){
35015 for(var i = 0, len = ns.length; i < len; i++){
35018 t.parentNode.insertBefore(n, t);
35019 }else if(p == "below"){
35020 t.parentNode.insertBefore(n, t.nextSibling);
35026 if(this.tree.hlDrop){
35030 this.tree.fireEvent("nodedrop", de);
35033 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35034 if(this.tree.hlDrop){
35035 dropNode.ui.focus();
35036 dropNode.ui.highlight();
35038 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35041 getTree : function(){
35045 removeDropIndicators : function(n){
35048 Roo.fly(el).removeClass([
35049 "x-tree-drag-insert-above",
35050 "x-tree-drag-insert-below",
35051 "x-tree-drag-append"]);
35052 this.lastInsertClass = "_noclass";
35056 beforeDragDrop : function(target, e, id){
35057 this.cancelExpand();
35061 afterRepair : function(data){
35062 if(data && Roo.enableFx){
35063 data.node.ui.highlight();
35073 * Ext JS Library 1.1.1
35074 * Copyright(c) 2006-2007, Ext JS, LLC.
35076 * Originally Released Under LGPL - original licence link has changed is not relivant.
35079 * <script type="text/javascript">
35083 if(Roo.dd.DragZone){
35084 Roo.tree.TreeDragZone = function(tree, config){
35085 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35089 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35090 ddGroup : "TreeDD",
35092 onBeforeDrag : function(data, e){
35094 return n && n.draggable && !n.disabled;
35098 onInitDrag : function(e){
35099 var data = this.dragData;
35100 this.tree.getSelectionModel().select(data.node);
35101 this.proxy.update("");
35102 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35103 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35106 getRepairXY : function(e, data){
35107 return data.node.ui.getDDRepairXY();
35110 onEndDrag : function(data, e){
35111 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35116 onValidDrop : function(dd, e, id){
35117 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35121 beforeInvalidDrop : function(e, id){
35122 // this scrolls the original position back into view
35123 var sm = this.tree.getSelectionModel();
35124 sm.clearSelections();
35125 sm.select(this.dragData.node);
35130 * Ext JS Library 1.1.1
35131 * Copyright(c) 2006-2007, Ext JS, LLC.
35133 * Originally Released Under LGPL - original licence link has changed is not relivant.
35136 * <script type="text/javascript">
35139 * @class Roo.tree.TreeEditor
35140 * @extends Roo.Editor
35141 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35142 * as the editor field.
35144 * @param {Object} config (used to be the tree panel.)
35145 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35147 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35148 * @cfg {Roo.form.TextField|Object} field The field configuration
35152 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35155 if (oldconfig) { // old style..
35156 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35159 tree = config.tree;
35160 config.field = config.field || {};
35161 config.field.xtype = 'TextField';
35162 field = Roo.factory(config.field, Roo.form);
35164 config = config || {};
35169 * @event beforenodeedit
35170 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35171 * false from the handler of this event.
35172 * @param {Editor} this
35173 * @param {Roo.tree.Node} node
35175 "beforenodeedit" : true
35179 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35183 tree.on('beforeclick', this.beforeNodeClick, this);
35184 tree.getTreeEl().on('mousedown', this.hide, this);
35185 this.on('complete', this.updateNode, this);
35186 this.on('beforestartedit', this.fitToTree, this);
35187 this.on('startedit', this.bindScroll, this, {delay:10});
35188 this.on('specialkey', this.onSpecialKey, this);
35191 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35193 * @cfg {String} alignment
35194 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35200 * @cfg {Boolean} hideEl
35201 * True to hide the bound element while the editor is displayed (defaults to false)
35205 * @cfg {String} cls
35206 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35208 cls: "x-small-editor x-tree-editor",
35210 * @cfg {Boolean} shim
35211 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35217 * @cfg {Number} maxWidth
35218 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35219 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35220 * scroll and client offsets into account prior to each edit.
35227 fitToTree : function(ed, el){
35228 var td = this.tree.getTreeEl().dom, nd = el.dom;
35229 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35230 td.scrollLeft = nd.offsetLeft;
35234 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35235 this.setSize(w, '');
35237 return this.fireEvent('beforenodeedit', this, this.editNode);
35242 triggerEdit : function(node){
35243 this.completeEdit();
35244 this.editNode = node;
35245 this.startEdit(node.ui.textNode, node.text);
35249 bindScroll : function(){
35250 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35254 beforeNodeClick : function(node, e){
35255 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35256 this.lastClick = new Date();
35257 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35259 this.triggerEdit(node);
35266 updateNode : function(ed, value){
35267 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35268 this.editNode.setText(value);
35272 onHide : function(){
35273 Roo.tree.TreeEditor.superclass.onHide.call(this);
35275 this.editNode.ui.focus();
35280 onSpecialKey : function(field, e){
35281 var k = e.getKey();
35285 }else if(k == e.ENTER && !e.hasModifier()){
35287 this.completeEdit();
35290 });//<Script type="text/javascript">
35293 * Ext JS Library 1.1.1
35294 * Copyright(c) 2006-2007, Ext JS, LLC.
35296 * Originally Released Under LGPL - original licence link has changed is not relivant.
35299 * <script type="text/javascript">
35303 * Not documented??? - probably should be...
35306 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35307 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35309 renderElements : function(n, a, targetNode, bulkRender){
35310 //consel.log("renderElements?");
35311 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35313 var t = n.getOwnerTree();
35314 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35316 var cols = t.columns;
35317 var bw = t.borderWidth;
35319 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35320 var cb = typeof a.checked == "boolean";
35321 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35322 var colcls = 'x-t-' + tid + '-c0';
35324 '<li class="x-tree-node">',
35327 '<div class="x-tree-node-el ', a.cls,'">',
35329 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35332 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35333 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35334 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35335 (a.icon ? ' x-tree-node-inline-icon' : ''),
35336 (a.iconCls ? ' '+a.iconCls : ''),
35337 '" unselectable="on" />',
35338 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35339 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35341 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35342 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35343 '<span unselectable="on" qtip="' + tx + '">',
35347 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35348 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35350 for(var i = 1, len = cols.length; i < len; i++){
35352 colcls = 'x-t-' + tid + '-c' +i;
35353 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35354 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35355 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35361 '<div class="x-clear"></div></div>',
35362 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35365 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35366 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35367 n.nextSibling.ui.getEl(), buf.join(""));
35369 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35371 var el = this.wrap.firstChild;
35373 this.elNode = el.firstChild;
35374 this.ranchor = el.childNodes[1];
35375 this.ctNode = this.wrap.childNodes[1];
35376 var cs = el.firstChild.childNodes;
35377 this.indentNode = cs[0];
35378 this.ecNode = cs[1];
35379 this.iconNode = cs[2];
35382 this.checkbox = cs[3];
35385 this.anchor = cs[index];
35387 this.textNode = cs[index].firstChild;
35389 //el.on("click", this.onClick, this);
35390 //el.on("dblclick", this.onDblClick, this);
35393 // console.log(this);
35395 initEvents : function(){
35396 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35399 var a = this.ranchor;
35401 var el = Roo.get(a);
35403 if(Roo.isOpera){ // opera render bug ignores the CSS
35404 el.setStyle("text-decoration", "none");
35407 el.on("click", this.onClick, this);
35408 el.on("dblclick", this.onDblClick, this);
35409 el.on("contextmenu", this.onContextMenu, this);
35413 /*onSelectedChange : function(state){
35416 this.addClass("x-tree-selected");
35419 this.removeClass("x-tree-selected");
35422 addClass : function(cls){
35424 Roo.fly(this.elRow).addClass(cls);
35430 removeClass : function(cls){
35432 Roo.fly(this.elRow).removeClass(cls);
35438 });//<Script type="text/javascript">
35442 * Ext JS Library 1.1.1
35443 * Copyright(c) 2006-2007, Ext JS, LLC.
35445 * Originally Released Under LGPL - original licence link has changed is not relivant.
35448 * <script type="text/javascript">
35453 * @class Roo.tree.ColumnTree
35454 * @extends Roo.data.TreePanel
35455 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35456 * @cfg {int} borderWidth compined right/left border allowance
35458 * @param {String/HTMLElement/Element} el The container element
35459 * @param {Object} config
35461 Roo.tree.ColumnTree = function(el, config)
35463 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35467 * Fire this event on a container when it resizes
35468 * @param {int} w Width
35469 * @param {int} h Height
35473 this.on('resize', this.onResize, this);
35476 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35480 borderWidth: Roo.isBorderBox ? 0 : 2,
35483 render : function(){
35484 // add the header.....
35486 Roo.tree.ColumnTree.superclass.render.apply(this);
35488 this.el.addClass('x-column-tree');
35490 this.headers = this.el.createChild(
35491 {cls:'x-tree-headers'},this.innerCt.dom);
35493 var cols = this.columns, c;
35494 var totalWidth = 0;
35496 var len = cols.length;
35497 for(var i = 0; i < len; i++){
35499 totalWidth += c.width;
35500 this.headEls.push(this.headers.createChild({
35501 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35503 cls:'x-tree-hd-text',
35506 style:'width:'+(c.width-this.borderWidth)+'px;'
35509 this.headers.createChild({cls:'x-clear'});
35510 // prevent floats from wrapping when clipped
35511 this.headers.setWidth(totalWidth);
35512 //this.innerCt.setWidth(totalWidth);
35513 this.innerCt.setStyle({ overflow: 'auto' });
35514 this.onResize(this.width, this.height);
35518 onResize : function(w,h)
35523 this.innerCt.setWidth(this.width);
35524 this.innerCt.setHeight(this.height-20);
35527 var cols = this.columns, c;
35528 var totalWidth = 0;
35530 var len = cols.length;
35531 for(var i = 0; i < len; i++){
35533 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35534 // it's the expander..
35535 expEl = this.headEls[i];
35538 totalWidth += c.width;
35542 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35544 this.headers.setWidth(w-20);
35553 * Ext JS Library 1.1.1
35554 * Copyright(c) 2006-2007, Ext JS, LLC.
35556 * Originally Released Under LGPL - original licence link has changed is not relivant.
35559 * <script type="text/javascript">
35563 * @class Roo.menu.Menu
35564 * @extends Roo.util.Observable
35565 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35566 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35568 * Creates a new Menu
35569 * @param {Object} config Configuration options
35571 Roo.menu.Menu = function(config){
35572 Roo.apply(this, config);
35573 this.id = this.id || Roo.id();
35576 * @event beforeshow
35577 * Fires before this menu is displayed
35578 * @param {Roo.menu.Menu} this
35582 * @event beforehide
35583 * Fires before this menu is hidden
35584 * @param {Roo.menu.Menu} this
35589 * Fires after this menu is displayed
35590 * @param {Roo.menu.Menu} this
35595 * Fires after this menu is hidden
35596 * @param {Roo.menu.Menu} this
35601 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35602 * @param {Roo.menu.Menu} this
35603 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35604 * @param {Roo.EventObject} e
35609 * Fires when the mouse is hovering over this menu
35610 * @param {Roo.menu.Menu} this
35611 * @param {Roo.EventObject} e
35612 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35617 * Fires when the mouse exits this menu
35618 * @param {Roo.menu.Menu} this
35619 * @param {Roo.EventObject} e
35620 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35625 * Fires when a menu item contained in this menu is clicked
35626 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35627 * @param {Roo.EventObject} e
35631 if (this.registerMenu) {
35632 Roo.menu.MenuMgr.register(this);
35635 var mis = this.items;
35636 this.items = new Roo.util.MixedCollection();
35638 this.add.apply(this, mis);
35642 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35644 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35648 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35649 * for bottom-right shadow (defaults to "sides")
35653 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35654 * this menu (defaults to "tl-tr?")
35656 subMenuAlign : "tl-tr?",
35658 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35659 * relative to its element of origin (defaults to "tl-bl?")
35661 defaultAlign : "tl-bl?",
35663 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35665 allowOtherMenus : false,
35667 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35669 registerMenu : true,
35674 render : function(){
35678 var el = this.el = new Roo.Layer({
35680 shadow:this.shadow,
35682 parentEl: this.parentEl || document.body,
35686 this.keyNav = new Roo.menu.MenuNav(this);
35689 el.addClass("x-menu-plain");
35692 el.addClass(this.cls);
35694 // generic focus element
35695 this.focusEl = el.createChild({
35696 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35698 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35699 //disabling touch- as it's causing issues ..
35700 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35702 ul.on("mouseover", this.onMouseOver, this);
35703 ul.on("mouseout", this.onMouseOut, this);
35704 this.items.each(function(item){
35709 var li = document.createElement("li");
35710 li.className = "x-menu-list-item";
35711 ul.dom.appendChild(li);
35712 item.render(li, this);
35719 autoWidth : function(){
35720 var el = this.el, ul = this.ul;
35724 var w = this.width;
35727 }else if(Roo.isIE){
35728 el.setWidth(this.minWidth);
35729 var t = el.dom.offsetWidth; // force recalc
35730 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35735 delayAutoWidth : function(){
35738 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35740 this.awTask.delay(20);
35745 findTargetItem : function(e){
35746 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35747 if(t && t.menuItemId){
35748 return this.items.get(t.menuItemId);
35753 onClick : function(e){
35754 Roo.log("menu.onClick");
35755 var t = this.findTargetItem(e);
35760 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35761 if(t == this.activeItem && t.shouldDeactivate(e)){
35762 this.activeItem.deactivate();
35763 delete this.activeItem;
35767 this.setActiveItem(t, true);
35775 this.fireEvent("click", this, t, e);
35779 setActiveItem : function(item, autoExpand){
35780 if(item != this.activeItem){
35781 if(this.activeItem){
35782 this.activeItem.deactivate();
35784 this.activeItem = item;
35785 item.activate(autoExpand);
35786 }else if(autoExpand){
35792 tryActivate : function(start, step){
35793 var items = this.items;
35794 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35795 var item = items.get(i);
35796 if(!item.disabled && item.canActivate){
35797 this.setActiveItem(item, false);
35805 onMouseOver : function(e){
35807 if(t = this.findTargetItem(e)){
35808 if(t.canActivate && !t.disabled){
35809 this.setActiveItem(t, true);
35812 this.fireEvent("mouseover", this, e, t);
35816 onMouseOut : function(e){
35818 if(t = this.findTargetItem(e)){
35819 if(t == this.activeItem && t.shouldDeactivate(e)){
35820 this.activeItem.deactivate();
35821 delete this.activeItem;
35824 this.fireEvent("mouseout", this, e, t);
35828 * Read-only. Returns true if the menu is currently displayed, else false.
35831 isVisible : function(){
35832 return this.el && !this.hidden;
35836 * Displays this menu relative to another element
35837 * @param {String/HTMLElement/Roo.Element} element The element to align to
35838 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35839 * the element (defaults to this.defaultAlign)
35840 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35842 show : function(el, pos, parentMenu){
35843 this.parentMenu = parentMenu;
35847 this.fireEvent("beforeshow", this);
35848 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35852 * Displays this menu at a specific xy position
35853 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35854 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35856 showAt : function(xy, parentMenu, /* private: */_e){
35857 this.parentMenu = parentMenu;
35862 this.fireEvent("beforeshow", this);
35863 xy = this.el.adjustForConstraints(xy);
35867 this.hidden = false;
35869 this.fireEvent("show", this);
35872 focus : function(){
35874 this.doFocus.defer(50, this);
35878 doFocus : function(){
35880 this.focusEl.focus();
35885 * Hides this menu and optionally all parent menus
35886 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35888 hide : function(deep){
35889 if(this.el && this.isVisible()){
35890 this.fireEvent("beforehide", this);
35891 if(this.activeItem){
35892 this.activeItem.deactivate();
35893 this.activeItem = null;
35896 this.hidden = true;
35897 this.fireEvent("hide", this);
35899 if(deep === true && this.parentMenu){
35900 this.parentMenu.hide(true);
35905 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35906 * Any of the following are valid:
35908 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35909 * <li>An HTMLElement object which will be converted to a menu item</li>
35910 * <li>A menu item config object that will be created as a new menu item</li>
35911 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35912 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35917 var menu = new Roo.menu.Menu();
35919 // Create a menu item to add by reference
35920 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35922 // Add a bunch of items at once using different methods.
35923 // Only the last item added will be returned.
35924 var item = menu.add(
35925 menuItem, // add existing item by ref
35926 'Dynamic Item', // new TextItem
35927 '-', // new separator
35928 { text: 'Config Item' } // new item by config
35931 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35932 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35935 var a = arguments, l = a.length, item;
35936 for(var i = 0; i < l; i++){
35938 if ((typeof(el) == "object") && el.xtype && el.xns) {
35939 el = Roo.factory(el, Roo.menu);
35942 if(el.render){ // some kind of Item
35943 item = this.addItem(el);
35944 }else if(typeof el == "string"){ // string
35945 if(el == "separator" || el == "-"){
35946 item = this.addSeparator();
35948 item = this.addText(el);
35950 }else if(el.tagName || el.el){ // element
35951 item = this.addElement(el);
35952 }else if(typeof el == "object"){ // must be menu item config?
35953 item = this.addMenuItem(el);
35960 * Returns this menu's underlying {@link Roo.Element} object
35961 * @return {Roo.Element} The element
35963 getEl : function(){
35971 * Adds a separator bar to the menu
35972 * @return {Roo.menu.Item} The menu item that was added
35974 addSeparator : function(){
35975 return this.addItem(new Roo.menu.Separator());
35979 * Adds an {@link Roo.Element} object to the menu
35980 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35981 * @return {Roo.menu.Item} The menu item that was added
35983 addElement : function(el){
35984 return this.addItem(new Roo.menu.BaseItem(el));
35988 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35989 * @param {Roo.menu.Item} item The menu item to add
35990 * @return {Roo.menu.Item} The menu item that was added
35992 addItem : function(item){
35993 this.items.add(item);
35995 var li = document.createElement("li");
35996 li.className = "x-menu-list-item";
35997 this.ul.dom.appendChild(li);
35998 item.render(li, this);
35999 this.delayAutoWidth();
36005 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36006 * @param {Object} config A MenuItem config object
36007 * @return {Roo.menu.Item} The menu item that was added
36009 addMenuItem : function(config){
36010 if(!(config instanceof Roo.menu.Item)){
36011 if(typeof config.checked == "boolean"){ // must be check menu item config?
36012 config = new Roo.menu.CheckItem(config);
36014 config = new Roo.menu.Item(config);
36017 return this.addItem(config);
36021 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36022 * @param {String} text The text to display in the menu item
36023 * @return {Roo.menu.Item} The menu item that was added
36025 addText : function(text){
36026 return this.addItem(new Roo.menu.TextItem({ text : text }));
36030 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36031 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36032 * @param {Roo.menu.Item} item The menu item to add
36033 * @return {Roo.menu.Item} The menu item that was added
36035 insert : function(index, item){
36036 this.items.insert(index, item);
36038 var li = document.createElement("li");
36039 li.className = "x-menu-list-item";
36040 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36041 item.render(li, this);
36042 this.delayAutoWidth();
36048 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36049 * @param {Roo.menu.Item} item The menu item to remove
36051 remove : function(item){
36052 this.items.removeKey(item.id);
36057 * Removes and destroys all items in the menu
36059 removeAll : function(){
36061 while(f = this.items.first()){
36067 // MenuNav is a private utility class used internally by the Menu
36068 Roo.menu.MenuNav = function(menu){
36069 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36070 this.scope = this.menu = menu;
36073 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36074 doRelay : function(e, h){
36075 var k = e.getKey();
36076 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36077 this.menu.tryActivate(0, 1);
36080 return h.call(this.scope || this, e, this.menu);
36083 up : function(e, m){
36084 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36085 m.tryActivate(m.items.length-1, -1);
36089 down : function(e, m){
36090 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36091 m.tryActivate(0, 1);
36095 right : function(e, m){
36097 m.activeItem.expandMenu(true);
36101 left : function(e, m){
36103 if(m.parentMenu && m.parentMenu.activeItem){
36104 m.parentMenu.activeItem.activate();
36108 enter : function(e, m){
36110 e.stopPropagation();
36111 m.activeItem.onClick(e);
36112 m.fireEvent("click", this, m.activeItem);
36118 * Ext JS Library 1.1.1
36119 * Copyright(c) 2006-2007, Ext JS, LLC.
36121 * Originally Released Under LGPL - original licence link has changed is not relivant.
36124 * <script type="text/javascript">
36128 * @class Roo.menu.MenuMgr
36129 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36132 Roo.menu.MenuMgr = function(){
36133 var menus, active, groups = {}, attached = false, lastShow = new Date();
36135 // private - called when first menu is created
36138 active = new Roo.util.MixedCollection();
36139 Roo.get(document).addKeyListener(27, function(){
36140 if(active.length > 0){
36147 function hideAll(){
36148 if(active && active.length > 0){
36149 var c = active.clone();
36150 c.each(function(m){
36157 function onHide(m){
36159 if(active.length < 1){
36160 Roo.get(document).un("mousedown", onMouseDown);
36166 function onShow(m){
36167 var last = active.last();
36168 lastShow = new Date();
36171 Roo.get(document).on("mousedown", onMouseDown);
36175 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36176 m.parentMenu.activeChild = m;
36177 }else if(last && last.isVisible()){
36178 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36183 function onBeforeHide(m){
36185 m.activeChild.hide();
36187 if(m.autoHideTimer){
36188 clearTimeout(m.autoHideTimer);
36189 delete m.autoHideTimer;
36194 function onBeforeShow(m){
36195 var pm = m.parentMenu;
36196 if(!pm && !m.allowOtherMenus){
36198 }else if(pm && pm.activeChild && active != m){
36199 pm.activeChild.hide();
36204 function onMouseDown(e){
36205 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36211 function onBeforeCheck(mi, state){
36213 var g = groups[mi.group];
36214 for(var i = 0, l = g.length; i < l; i++){
36216 g[i].setChecked(false);
36225 * Hides all menus that are currently visible
36227 hideAll : function(){
36232 register : function(menu){
36236 menus[menu.id] = menu;
36237 menu.on("beforehide", onBeforeHide);
36238 menu.on("hide", onHide);
36239 menu.on("beforeshow", onBeforeShow);
36240 menu.on("show", onShow);
36241 var g = menu.group;
36242 if(g && menu.events["checkchange"]){
36246 groups[g].push(menu);
36247 menu.on("checkchange", onCheck);
36252 * Returns a {@link Roo.menu.Menu} object
36253 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36254 * be used to generate and return a new Menu instance.
36256 get : function(menu){
36257 if(typeof menu == "string"){ // menu id
36258 return menus[menu];
36259 }else if(menu.events){ // menu instance
36261 }else if(typeof menu.length == 'number'){ // array of menu items?
36262 return new Roo.menu.Menu({items:menu});
36263 }else{ // otherwise, must be a config
36264 return new Roo.menu.Menu(menu);
36269 unregister : function(menu){
36270 delete menus[menu.id];
36271 menu.un("beforehide", onBeforeHide);
36272 menu.un("hide", onHide);
36273 menu.un("beforeshow", onBeforeShow);
36274 menu.un("show", onShow);
36275 var g = menu.group;
36276 if(g && menu.events["checkchange"]){
36277 groups[g].remove(menu);
36278 menu.un("checkchange", onCheck);
36283 registerCheckable : function(menuItem){
36284 var g = menuItem.group;
36289 groups[g].push(menuItem);
36290 menuItem.on("beforecheckchange", onBeforeCheck);
36295 unregisterCheckable : function(menuItem){
36296 var g = menuItem.group;
36298 groups[g].remove(menuItem);
36299 menuItem.un("beforecheckchange", onBeforeCheck);
36305 * Ext JS Library 1.1.1
36306 * Copyright(c) 2006-2007, Ext JS, LLC.
36308 * Originally Released Under LGPL - original licence link has changed is not relivant.
36311 * <script type="text/javascript">
36316 * @class Roo.menu.BaseItem
36317 * @extends Roo.Component
36318 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36319 * management and base configuration options shared by all menu components.
36321 * Creates a new BaseItem
36322 * @param {Object} config Configuration options
36324 Roo.menu.BaseItem = function(config){
36325 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36330 * Fires when this item is clicked
36331 * @param {Roo.menu.BaseItem} this
36332 * @param {Roo.EventObject} e
36337 * Fires when this item is activated
36338 * @param {Roo.menu.BaseItem} this
36342 * @event deactivate
36343 * Fires when this item is deactivated
36344 * @param {Roo.menu.BaseItem} this
36350 this.on("click", this.handler, this.scope, true);
36354 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36356 * @cfg {Function} handler
36357 * A function that will handle the click event of this menu item (defaults to undefined)
36360 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36362 canActivate : false,
36365 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36370 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36372 activeClass : "x-menu-item-active",
36374 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36376 hideOnClick : true,
36378 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36383 ctype: "Roo.menu.BaseItem",
36386 actionMode : "container",
36389 render : function(container, parentMenu){
36390 this.parentMenu = parentMenu;
36391 Roo.menu.BaseItem.superclass.render.call(this, container);
36392 this.container.menuItemId = this.id;
36396 onRender : function(container, position){
36397 this.el = Roo.get(this.el);
36398 container.dom.appendChild(this.el.dom);
36402 onClick : function(e){
36403 if(!this.disabled && this.fireEvent("click", this, e) !== false
36404 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36405 this.handleClick(e);
36412 activate : function(){
36416 var li = this.container;
36417 li.addClass(this.activeClass);
36418 this.region = li.getRegion().adjust(2, 2, -2, -2);
36419 this.fireEvent("activate", this);
36424 deactivate : function(){
36425 this.container.removeClass(this.activeClass);
36426 this.fireEvent("deactivate", this);
36430 shouldDeactivate : function(e){
36431 return !this.region || !this.region.contains(e.getPoint());
36435 handleClick : function(e){
36436 if(this.hideOnClick){
36437 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36442 expandMenu : function(autoActivate){
36447 hideMenu : function(){
36452 * Ext JS Library 1.1.1
36453 * Copyright(c) 2006-2007, Ext JS, LLC.
36455 * Originally Released Under LGPL - original licence link has changed is not relivant.
36458 * <script type="text/javascript">
36462 * @class Roo.menu.Adapter
36463 * @extends Roo.menu.BaseItem
36464 * 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.
36465 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36467 * Creates a new Adapter
36468 * @param {Object} config Configuration options
36470 Roo.menu.Adapter = function(component, config){
36471 Roo.menu.Adapter.superclass.constructor.call(this, config);
36472 this.component = component;
36474 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36476 canActivate : true,
36479 onRender : function(container, position){
36480 this.component.render(container);
36481 this.el = this.component.getEl();
36485 activate : function(){
36489 this.component.focus();
36490 this.fireEvent("activate", this);
36495 deactivate : function(){
36496 this.fireEvent("deactivate", this);
36500 disable : function(){
36501 this.component.disable();
36502 Roo.menu.Adapter.superclass.disable.call(this);
36506 enable : function(){
36507 this.component.enable();
36508 Roo.menu.Adapter.superclass.enable.call(this);
36512 * Ext JS Library 1.1.1
36513 * Copyright(c) 2006-2007, Ext JS, LLC.
36515 * Originally Released Under LGPL - original licence link has changed is not relivant.
36518 * <script type="text/javascript">
36522 * @class Roo.menu.TextItem
36523 * @extends Roo.menu.BaseItem
36524 * Adds a static text string to a menu, usually used as either a heading or group separator.
36525 * Note: old style constructor with text is still supported.
36528 * Creates a new TextItem
36529 * @param {Object} cfg Configuration
36531 Roo.menu.TextItem = function(cfg){
36532 if (typeof(cfg) == 'string') {
36535 Roo.apply(this,cfg);
36538 Roo.menu.TextItem.superclass.constructor.call(this);
36541 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36543 * @cfg {Boolean} text Text to show on item.
36548 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36550 hideOnClick : false,
36552 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36554 itemCls : "x-menu-text",
36557 onRender : function(){
36558 var s = document.createElement("span");
36559 s.className = this.itemCls;
36560 s.innerHTML = this.text;
36562 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36566 * Ext JS Library 1.1.1
36567 * Copyright(c) 2006-2007, Ext JS, LLC.
36569 * Originally Released Under LGPL - original licence link has changed is not relivant.
36572 * <script type="text/javascript">
36576 * @class Roo.menu.Separator
36577 * @extends Roo.menu.BaseItem
36578 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36579 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36581 * @param {Object} config Configuration options
36583 Roo.menu.Separator = function(config){
36584 Roo.menu.Separator.superclass.constructor.call(this, config);
36587 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36589 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36591 itemCls : "x-menu-sep",
36593 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36595 hideOnClick : false,
36598 onRender : function(li){
36599 var s = document.createElement("span");
36600 s.className = this.itemCls;
36601 s.innerHTML = " ";
36603 li.addClass("x-menu-sep-li");
36604 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36608 * Ext JS Library 1.1.1
36609 * Copyright(c) 2006-2007, Ext JS, LLC.
36611 * Originally Released Under LGPL - original licence link has changed is not relivant.
36614 * <script type="text/javascript">
36617 * @class Roo.menu.Item
36618 * @extends Roo.menu.BaseItem
36619 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36620 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36621 * activation and click handling.
36623 * Creates a new Item
36624 * @param {Object} config Configuration options
36626 Roo.menu.Item = function(config){
36627 Roo.menu.Item.superclass.constructor.call(this, config);
36629 this.menu = Roo.menu.MenuMgr.get(this.menu);
36632 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36635 * @cfg {String} text
36636 * The text to show on the menu item.
36640 * @cfg {String} HTML to render in menu
36641 * The text to show on the menu item (HTML version).
36645 * @cfg {String} icon
36646 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36650 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36652 itemCls : "x-menu-item",
36654 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36656 canActivate : true,
36658 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36661 // doc'd in BaseItem
36665 ctype: "Roo.menu.Item",
36668 onRender : function(container, position){
36669 var el = document.createElement("a");
36670 el.hideFocus = true;
36671 el.unselectable = "on";
36672 el.href = this.href || "#";
36673 if(this.hrefTarget){
36674 el.target = this.hrefTarget;
36676 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36678 var html = this.html.length ? this.html : String.format('{0}',this.text);
36680 el.innerHTML = String.format(
36681 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36682 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36684 Roo.menu.Item.superclass.onRender.call(this, container, position);
36688 * Sets the text to display in this menu item
36689 * @param {String} text The text to display
36690 * @param {Boolean} isHTML true to indicate text is pure html.
36692 setText : function(text, isHTML){
36700 var html = this.html.length ? this.html : String.format('{0}',this.text);
36702 this.el.update(String.format(
36703 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36704 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36705 this.parentMenu.autoWidth();
36710 handleClick : function(e){
36711 if(!this.href){ // if no link defined, stop the event automatically
36714 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36718 activate : function(autoExpand){
36719 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36729 shouldDeactivate : function(e){
36730 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36731 if(this.menu && this.menu.isVisible()){
36732 return !this.menu.getEl().getRegion().contains(e.getPoint());
36740 deactivate : function(){
36741 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36746 expandMenu : function(autoActivate){
36747 if(!this.disabled && this.menu){
36748 clearTimeout(this.hideTimer);
36749 delete this.hideTimer;
36750 if(!this.menu.isVisible() && !this.showTimer){
36751 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36752 }else if (this.menu.isVisible() && autoActivate){
36753 this.menu.tryActivate(0, 1);
36759 deferExpand : function(autoActivate){
36760 delete this.showTimer;
36761 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36763 this.menu.tryActivate(0, 1);
36768 hideMenu : function(){
36769 clearTimeout(this.showTimer);
36770 delete this.showTimer;
36771 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36772 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36777 deferHide : function(){
36778 delete this.hideTimer;
36783 * Ext JS Library 1.1.1
36784 * Copyright(c) 2006-2007, Ext JS, LLC.
36786 * Originally Released Under LGPL - original licence link has changed is not relivant.
36789 * <script type="text/javascript">
36793 * @class Roo.menu.CheckItem
36794 * @extends Roo.menu.Item
36795 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36797 * Creates a new CheckItem
36798 * @param {Object} config Configuration options
36800 Roo.menu.CheckItem = function(config){
36801 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36804 * @event beforecheckchange
36805 * Fires before the checked value is set, providing an opportunity to cancel if needed
36806 * @param {Roo.menu.CheckItem} this
36807 * @param {Boolean} checked The new checked value that will be set
36809 "beforecheckchange" : true,
36811 * @event checkchange
36812 * Fires after the checked value has been set
36813 * @param {Roo.menu.CheckItem} this
36814 * @param {Boolean} checked The checked value that was set
36816 "checkchange" : true
36818 if(this.checkHandler){
36819 this.on('checkchange', this.checkHandler, this.scope);
36822 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36824 * @cfg {String} group
36825 * All check items with the same group name will automatically be grouped into a single-select
36826 * radio button group (defaults to '')
36829 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36831 itemCls : "x-menu-item x-menu-check-item",
36833 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36835 groupClass : "x-menu-group-item",
36838 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36839 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36840 * initialized with checked = true will be rendered as checked.
36845 ctype: "Roo.menu.CheckItem",
36848 onRender : function(c){
36849 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36851 this.el.addClass(this.groupClass);
36853 Roo.menu.MenuMgr.registerCheckable(this);
36855 this.checked = false;
36856 this.setChecked(true, true);
36861 destroy : function(){
36863 Roo.menu.MenuMgr.unregisterCheckable(this);
36865 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36869 * Set the checked state of this item
36870 * @param {Boolean} checked The new checked value
36871 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36873 setChecked : function(state, suppressEvent){
36874 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36875 if(this.container){
36876 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36878 this.checked = state;
36879 if(suppressEvent !== true){
36880 this.fireEvent("checkchange", this, state);
36886 handleClick : function(e){
36887 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36888 this.setChecked(!this.checked);
36890 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36894 * Ext JS Library 1.1.1
36895 * Copyright(c) 2006-2007, Ext JS, LLC.
36897 * Originally Released Under LGPL - original licence link has changed is not relivant.
36900 * <script type="text/javascript">
36904 * @class Roo.menu.DateItem
36905 * @extends Roo.menu.Adapter
36906 * A menu item that wraps the {@link Roo.DatPicker} component.
36908 * Creates a new DateItem
36909 * @param {Object} config Configuration options
36911 Roo.menu.DateItem = function(config){
36912 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36913 /** The Roo.DatePicker object @type Roo.DatePicker */
36914 this.picker = this.component;
36915 this.addEvents({select: true});
36917 this.picker.on("render", function(picker){
36918 picker.getEl().swallowEvent("click");
36919 picker.container.addClass("x-menu-date-item");
36922 this.picker.on("select", this.onSelect, this);
36925 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36927 onSelect : function(picker, date){
36928 this.fireEvent("select", this, date, picker);
36929 Roo.menu.DateItem.superclass.handleClick.call(this);
36933 * Ext JS Library 1.1.1
36934 * Copyright(c) 2006-2007, Ext JS, LLC.
36936 * Originally Released Under LGPL - original licence link has changed is not relivant.
36939 * <script type="text/javascript">
36943 * @class Roo.menu.ColorItem
36944 * @extends Roo.menu.Adapter
36945 * A menu item that wraps the {@link Roo.ColorPalette} component.
36947 * Creates a new ColorItem
36948 * @param {Object} config Configuration options
36950 Roo.menu.ColorItem = function(config){
36951 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36952 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36953 this.palette = this.component;
36954 this.relayEvents(this.palette, ["select"]);
36955 if(this.selectHandler){
36956 this.on('select', this.selectHandler, this.scope);
36959 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36961 * Ext JS Library 1.1.1
36962 * Copyright(c) 2006-2007, Ext JS, LLC.
36964 * Originally Released Under LGPL - original licence link has changed is not relivant.
36967 * <script type="text/javascript">
36972 * @class Roo.menu.DateMenu
36973 * @extends Roo.menu.Menu
36974 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36976 * Creates a new DateMenu
36977 * @param {Object} config Configuration options
36979 Roo.menu.DateMenu = function(config){
36980 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36982 var di = new Roo.menu.DateItem(config);
36985 * The {@link Roo.DatePicker} instance for this DateMenu
36988 this.picker = di.picker;
36991 * @param {DatePicker} picker
36992 * @param {Date} date
36994 this.relayEvents(di, ["select"]);
36995 this.on('beforeshow', function(){
36997 this.picker.hideMonthPicker(false);
37001 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37005 * Ext JS Library 1.1.1
37006 * Copyright(c) 2006-2007, Ext JS, LLC.
37008 * Originally Released Under LGPL - original licence link has changed is not relivant.
37011 * <script type="text/javascript">
37016 * @class Roo.menu.ColorMenu
37017 * @extends Roo.menu.Menu
37018 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37020 * Creates a new ColorMenu
37021 * @param {Object} config Configuration options
37023 Roo.menu.ColorMenu = function(config){
37024 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37026 var ci = new Roo.menu.ColorItem(config);
37029 * The {@link Roo.ColorPalette} instance for this ColorMenu
37030 * @type ColorPalette
37032 this.palette = ci.palette;
37035 * @param {ColorPalette} palette
37036 * @param {String} color
37038 this.relayEvents(ci, ["select"]);
37040 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37042 * Ext JS Library 1.1.1
37043 * Copyright(c) 2006-2007, Ext JS, LLC.
37045 * Originally Released Under LGPL - original licence link has changed is not relivant.
37048 * <script type="text/javascript">
37052 * @class Roo.form.Field
37053 * @extends Roo.BoxComponent
37054 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37056 * Creates a new Field
37057 * @param {Object} config Configuration options
37059 Roo.form.Field = function(config){
37060 Roo.form.Field.superclass.constructor.call(this, config);
37063 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37065 * @cfg {String} fieldLabel Label to use when rendering a form.
37068 * @cfg {String} qtip Mouse over tip
37072 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37074 invalidClass : "x-form-invalid",
37076 * @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")
37078 invalidText : "The value in this field is invalid",
37080 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37082 focusClass : "x-form-focus",
37084 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37085 automatic validation (defaults to "keyup").
37087 validationEvent : "keyup",
37089 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37091 validateOnBlur : true,
37093 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37095 validationDelay : 250,
37097 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37098 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37100 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37102 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37104 fieldClass : "x-form-field",
37106 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37109 ----------- ----------------------------------------------------------------------
37110 qtip Display a quick tip when the user hovers over the field
37111 title Display a default browser title attribute popup
37112 under Add a block div beneath the field containing the error text
37113 side Add an error icon to the right of the field with a popup on hover
37114 [element id] Add the error text directly to the innerHTML of the specified element
37117 msgTarget : 'qtip',
37119 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37124 * @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.
37129 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37134 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37136 inputType : undefined,
37139 * @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).
37141 tabIndex : undefined,
37144 isFormField : true,
37149 * @property {Roo.Element} fieldEl
37150 * Element Containing the rendered Field (with label etc.)
37153 * @cfg {Mixed} value A value to initialize this field with.
37158 * @cfg {String} name The field's HTML name attribute.
37161 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37165 initComponent : function(){
37166 Roo.form.Field.superclass.initComponent.call(this);
37170 * Fires when this field receives input focus.
37171 * @param {Roo.form.Field} this
37176 * Fires when this field loses input focus.
37177 * @param {Roo.form.Field} this
37181 * @event specialkey
37182 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37183 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37184 * @param {Roo.form.Field} this
37185 * @param {Roo.EventObject} e The event object
37190 * Fires just before the field blurs if the field value has changed.
37191 * @param {Roo.form.Field} this
37192 * @param {Mixed} newValue The new value
37193 * @param {Mixed} oldValue The original value
37198 * Fires after the field has been marked as invalid.
37199 * @param {Roo.form.Field} this
37200 * @param {String} msg The validation message
37205 * Fires after the field has been validated with no errors.
37206 * @param {Roo.form.Field} this
37211 * Fires after the key up
37212 * @param {Roo.form.Field} this
37213 * @param {Roo.EventObject} e The event Object
37220 * Returns the name attribute of the field if available
37221 * @return {String} name The field name
37223 getName: function(){
37224 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37228 onRender : function(ct, position){
37229 Roo.form.Field.superclass.onRender.call(this, ct, position);
37231 var cfg = this.getAutoCreate();
37233 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37235 if (!cfg.name.length) {
37238 if(this.inputType){
37239 cfg.type = this.inputType;
37241 this.el = ct.createChild(cfg, position);
37243 var type = this.el.dom.type;
37245 if(type == 'password'){
37248 this.el.addClass('x-form-'+type);
37251 this.el.dom.readOnly = true;
37253 if(this.tabIndex !== undefined){
37254 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37257 this.el.addClass([this.fieldClass, this.cls]);
37262 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37263 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37264 * @return {Roo.form.Field} this
37266 applyTo : function(target){
37267 this.allowDomMove = false;
37268 this.el = Roo.get(target);
37269 this.render(this.el.dom.parentNode);
37274 initValue : function(){
37275 if(this.value !== undefined){
37276 this.setValue(this.value);
37277 }else if(this.el.dom.value.length > 0){
37278 this.setValue(this.el.dom.value);
37283 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37285 isDirty : function() {
37286 if(this.disabled) {
37289 return String(this.getValue()) !== String(this.originalValue);
37293 afterRender : function(){
37294 Roo.form.Field.superclass.afterRender.call(this);
37299 fireKey : function(e){
37300 //Roo.log('field ' + e.getKey());
37301 if(e.isNavKeyPress()){
37302 this.fireEvent("specialkey", this, e);
37307 * Resets the current field value to the originally loaded value and clears any validation messages
37309 reset : function(){
37310 this.setValue(this.resetValue);
37311 this.clearInvalid();
37315 initEvents : function(){
37316 // safari killled keypress - so keydown is now used..
37317 this.el.on("keydown" , this.fireKey, this);
37318 this.el.on("focus", this.onFocus, this);
37319 this.el.on("blur", this.onBlur, this);
37320 this.el.relayEvent('keyup', this);
37322 // reference to original value for reset
37323 this.originalValue = this.getValue();
37324 this.resetValue = this.getValue();
37328 onFocus : function(){
37329 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37330 this.el.addClass(this.focusClass);
37332 if(!this.hasFocus){
37333 this.hasFocus = true;
37334 this.startValue = this.getValue();
37335 this.fireEvent("focus", this);
37339 beforeBlur : Roo.emptyFn,
37342 onBlur : function(){
37344 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37345 this.el.removeClass(this.focusClass);
37347 this.hasFocus = false;
37348 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37351 var v = this.getValue();
37352 if(String(v) !== String(this.startValue)){
37353 this.fireEvent('change', this, v, this.startValue);
37355 this.fireEvent("blur", this);
37359 * Returns whether or not the field value is currently valid
37360 * @param {Boolean} preventMark True to disable marking the field invalid
37361 * @return {Boolean} True if the value is valid, else false
37363 isValid : function(preventMark){
37367 var restore = this.preventMark;
37368 this.preventMark = preventMark === true;
37369 var v = this.validateValue(this.processValue(this.getRawValue()));
37370 this.preventMark = restore;
37375 * Validates the field value
37376 * @return {Boolean} True if the value is valid, else false
37378 validate : function(){
37379 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37380 this.clearInvalid();
37386 processValue : function(value){
37391 // Subclasses should provide the validation implementation by overriding this
37392 validateValue : function(value){
37397 * Mark this field as invalid
37398 * @param {String} msg The validation message
37400 markInvalid : function(msg){
37401 if(!this.rendered || this.preventMark){ // not rendered
37405 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37407 obj.el.addClass(this.invalidClass);
37408 msg = msg || this.invalidText;
37409 switch(this.msgTarget){
37411 obj.el.dom.qtip = msg;
37412 obj.el.dom.qclass = 'x-form-invalid-tip';
37413 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37414 Roo.QuickTips.enable();
37418 this.el.dom.title = msg;
37422 var elp = this.el.findParent('.x-form-element', 5, true);
37423 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37424 this.errorEl.setWidth(elp.getWidth(true)-20);
37426 this.errorEl.update(msg);
37427 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37430 if(!this.errorIcon){
37431 var elp = this.el.findParent('.x-form-element', 5, true);
37432 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37434 this.alignErrorIcon();
37435 this.errorIcon.dom.qtip = msg;
37436 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37437 this.errorIcon.show();
37438 this.on('resize', this.alignErrorIcon, this);
37441 var t = Roo.getDom(this.msgTarget);
37443 t.style.display = this.msgDisplay;
37446 this.fireEvent('invalid', this, msg);
37450 alignErrorIcon : function(){
37451 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37455 * Clear any invalid styles/messages for this field
37457 clearInvalid : function(){
37458 if(!this.rendered || this.preventMark){ // not rendered
37461 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37463 obj.el.removeClass(this.invalidClass);
37464 switch(this.msgTarget){
37466 obj.el.dom.qtip = '';
37469 this.el.dom.title = '';
37473 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37477 if(this.errorIcon){
37478 this.errorIcon.dom.qtip = '';
37479 this.errorIcon.hide();
37480 this.un('resize', this.alignErrorIcon, this);
37484 var t = Roo.getDom(this.msgTarget);
37486 t.style.display = 'none';
37489 this.fireEvent('valid', this);
37493 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37494 * @return {Mixed} value The field value
37496 getRawValue : function(){
37497 var v = this.el.getValue();
37503 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37504 * @return {Mixed} value The field value
37506 getValue : function(){
37507 var v = this.el.getValue();
37513 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37514 * @param {Mixed} value The value to set
37516 setRawValue : function(v){
37517 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37521 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37522 * @param {Mixed} value The value to set
37524 setValue : function(v){
37527 this.el.dom.value = (v === null || v === undefined ? '' : v);
37532 adjustSize : function(w, h){
37533 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37534 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37538 adjustWidth : function(tag, w){
37539 tag = tag.toLowerCase();
37540 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37541 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37542 if(tag == 'input'){
37545 if(tag == 'textarea'){
37548 }else if(Roo.isOpera){
37549 if(tag == 'input'){
37552 if(tag == 'textarea'){
37562 // anything other than normal should be considered experimental
37563 Roo.form.Field.msgFx = {
37565 show: function(msgEl, f){
37566 msgEl.setDisplayed('block');
37569 hide : function(msgEl, f){
37570 msgEl.setDisplayed(false).update('');
37575 show: function(msgEl, f){
37576 msgEl.slideIn('t', {stopFx:true});
37579 hide : function(msgEl, f){
37580 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37585 show: function(msgEl, f){
37586 msgEl.fixDisplay();
37587 msgEl.alignTo(f.el, 'tl-tr');
37588 msgEl.slideIn('l', {stopFx:true});
37591 hide : function(msgEl, f){
37592 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37597 * Ext JS Library 1.1.1
37598 * Copyright(c) 2006-2007, Ext JS, LLC.
37600 * Originally Released Under LGPL - original licence link has changed is not relivant.
37603 * <script type="text/javascript">
37608 * @class Roo.form.TextField
37609 * @extends Roo.form.Field
37610 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37611 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37613 * Creates a new TextField
37614 * @param {Object} config Configuration options
37616 Roo.form.TextField = function(config){
37617 Roo.form.TextField.superclass.constructor.call(this, config);
37621 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37622 * according to the default logic, but this event provides a hook for the developer to apply additional
37623 * logic at runtime to resize the field if needed.
37624 * @param {Roo.form.Field} this This text field
37625 * @param {Number} width The new field width
37631 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37633 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37637 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37641 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37645 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37649 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37653 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37655 disableKeyFilter : false,
37657 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37661 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37665 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37667 maxLength : Number.MAX_VALUE,
37669 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37671 minLengthText : "The minimum length for this field is {0}",
37673 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37675 maxLengthText : "The maximum length for this field is {0}",
37677 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37679 selectOnFocus : false,
37681 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37683 blankText : "This field is required",
37685 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37686 * If available, this function will be called only after the basic validators all return true, and will be passed the
37687 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37691 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37692 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37693 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37697 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37701 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37707 initEvents : function()
37709 if (this.emptyText) {
37710 this.el.attr('placeholder', this.emptyText);
37713 Roo.form.TextField.superclass.initEvents.call(this);
37714 if(this.validationEvent == 'keyup'){
37715 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37716 this.el.on('keyup', this.filterValidation, this);
37718 else if(this.validationEvent !== false){
37719 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37722 if(this.selectOnFocus){
37723 this.on("focus", this.preFocus, this);
37726 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37727 this.el.on("keypress", this.filterKeys, this);
37730 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37731 this.el.on("click", this.autoSize, this);
37733 if(this.el.is('input[type=password]') && Roo.isSafari){
37734 this.el.on('keydown', this.SafariOnKeyDown, this);
37738 processValue : function(value){
37739 if(this.stripCharsRe){
37740 var newValue = value.replace(this.stripCharsRe, '');
37741 if(newValue !== value){
37742 this.setRawValue(newValue);
37749 filterValidation : function(e){
37750 if(!e.isNavKeyPress()){
37751 this.validationTask.delay(this.validationDelay);
37756 onKeyUp : function(e){
37757 if(!e.isNavKeyPress()){
37763 * Resets the current field value to the originally-loaded value and clears any validation messages.
37766 reset : function(){
37767 Roo.form.TextField.superclass.reset.call(this);
37773 preFocus : function(){
37775 if(this.selectOnFocus){
37776 this.el.dom.select();
37782 filterKeys : function(e){
37783 var k = e.getKey();
37784 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37787 var c = e.getCharCode(), cc = String.fromCharCode(c);
37788 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37791 if(!this.maskRe.test(cc)){
37796 setValue : function(v){
37798 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37804 * Validates a value according to the field's validation rules and marks the field as invalid
37805 * if the validation fails
37806 * @param {Mixed} value The value to validate
37807 * @return {Boolean} True if the value is valid, else false
37809 validateValue : function(value){
37810 if(value.length < 1) { // if it's blank
37811 if(this.allowBlank){
37812 this.clearInvalid();
37815 this.markInvalid(this.blankText);
37819 if(value.length < this.minLength){
37820 this.markInvalid(String.format(this.minLengthText, this.minLength));
37823 if(value.length > this.maxLength){
37824 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37828 var vt = Roo.form.VTypes;
37829 if(!vt[this.vtype](value, this)){
37830 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37834 if(typeof this.validator == "function"){
37835 var msg = this.validator(value);
37837 this.markInvalid(msg);
37841 if(this.regex && !this.regex.test(value)){
37842 this.markInvalid(this.regexText);
37849 * Selects text in this field
37850 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37851 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37853 selectText : function(start, end){
37854 var v = this.getRawValue();
37856 start = start === undefined ? 0 : start;
37857 end = end === undefined ? v.length : end;
37858 var d = this.el.dom;
37859 if(d.setSelectionRange){
37860 d.setSelectionRange(start, end);
37861 }else if(d.createTextRange){
37862 var range = d.createTextRange();
37863 range.moveStart("character", start);
37864 range.moveEnd("character", v.length-end);
37871 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37872 * This only takes effect if grow = true, and fires the autosize event.
37874 autoSize : function(){
37875 if(!this.grow || !this.rendered){
37879 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37882 var v = el.dom.value;
37883 var d = document.createElement('div');
37884 d.appendChild(document.createTextNode(v));
37888 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37889 this.el.setWidth(w);
37890 this.fireEvent("autosize", this, w);
37894 SafariOnKeyDown : function(event)
37896 // this is a workaround for a password hang bug on chrome/ webkit.
37898 var isSelectAll = false;
37900 if(this.el.dom.selectionEnd > 0){
37901 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37903 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37904 event.preventDefault();
37909 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37911 event.preventDefault();
37912 // this is very hacky as keydown always get's upper case.
37914 var cc = String.fromCharCode(event.getCharCode());
37917 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37925 * Ext JS Library 1.1.1
37926 * Copyright(c) 2006-2007, Ext JS, LLC.
37928 * Originally Released Under LGPL - original licence link has changed is not relivant.
37931 * <script type="text/javascript">
37935 * @class Roo.form.Hidden
37936 * @extends Roo.form.TextField
37937 * Simple Hidden element used on forms
37939 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37942 * Creates a new Hidden form element.
37943 * @param {Object} config Configuration options
37948 // easy hidden field...
37949 Roo.form.Hidden = function(config){
37950 Roo.form.Hidden.superclass.constructor.call(this, config);
37953 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37955 inputType: 'hidden',
37958 labelSeparator: '',
37960 itemCls : 'x-form-item-display-none'
37968 * Ext JS Library 1.1.1
37969 * Copyright(c) 2006-2007, Ext JS, LLC.
37971 * Originally Released Under LGPL - original licence link has changed is not relivant.
37974 * <script type="text/javascript">
37978 * @class Roo.form.TriggerField
37979 * @extends Roo.form.TextField
37980 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37981 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37982 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37983 * for which you can provide a custom implementation. For example:
37985 var trigger = new Roo.form.TriggerField();
37986 trigger.onTriggerClick = myTriggerFn;
37987 trigger.applyTo('my-field');
37990 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37991 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37992 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37993 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37995 * Create a new TriggerField.
37996 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37997 * to the base TextField)
37999 Roo.form.TriggerField = function(config){
38000 this.mimicing = false;
38001 Roo.form.TriggerField.superclass.constructor.call(this, config);
38004 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38006 * @cfg {String} triggerClass A CSS class to apply to the trigger
38009 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38010 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38012 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38014 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38018 /** @cfg {Boolean} grow @hide */
38019 /** @cfg {Number} growMin @hide */
38020 /** @cfg {Number} growMax @hide */
38026 autoSize: Roo.emptyFn,
38030 deferHeight : true,
38033 actionMode : 'wrap',
38035 onResize : function(w, h){
38036 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38037 if(typeof w == 'number'){
38038 var x = w - this.trigger.getWidth();
38039 this.el.setWidth(this.adjustWidth('input', x));
38040 this.trigger.setStyle('left', x+'px');
38045 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38048 getResizeEl : function(){
38053 getPositionEl : function(){
38058 alignErrorIcon : function(){
38059 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38063 onRender : function(ct, position){
38064 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38065 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38066 this.trigger = this.wrap.createChild(this.triggerConfig ||
38067 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38068 if(this.hideTrigger){
38069 this.trigger.setDisplayed(false);
38071 this.initTrigger();
38073 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38078 initTrigger : function(){
38079 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38080 this.trigger.addClassOnOver('x-form-trigger-over');
38081 this.trigger.addClassOnClick('x-form-trigger-click');
38085 onDestroy : function(){
38087 this.trigger.removeAllListeners();
38088 this.trigger.remove();
38091 this.wrap.remove();
38093 Roo.form.TriggerField.superclass.onDestroy.call(this);
38097 onFocus : function(){
38098 Roo.form.TriggerField.superclass.onFocus.call(this);
38099 if(!this.mimicing){
38100 this.wrap.addClass('x-trigger-wrap-focus');
38101 this.mimicing = true;
38102 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38103 if(this.monitorTab){
38104 this.el.on("keydown", this.checkTab, this);
38110 checkTab : function(e){
38111 if(e.getKey() == e.TAB){
38112 this.triggerBlur();
38117 onBlur : function(){
38122 mimicBlur : function(e, t){
38123 if(!this.wrap.contains(t) && this.validateBlur()){
38124 this.triggerBlur();
38129 triggerBlur : function(){
38130 this.mimicing = false;
38131 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38132 if(this.monitorTab){
38133 this.el.un("keydown", this.checkTab, this);
38135 this.wrap.removeClass('x-trigger-wrap-focus');
38136 Roo.form.TriggerField.superclass.onBlur.call(this);
38140 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38141 validateBlur : function(e, t){
38146 onDisable : function(){
38147 Roo.form.TriggerField.superclass.onDisable.call(this);
38149 this.wrap.addClass('x-item-disabled');
38154 onEnable : function(){
38155 Roo.form.TriggerField.superclass.onEnable.call(this);
38157 this.wrap.removeClass('x-item-disabled');
38162 onShow : function(){
38163 var ae = this.getActionEl();
38166 ae.dom.style.display = '';
38167 ae.dom.style.visibility = 'visible';
38173 onHide : function(){
38174 var ae = this.getActionEl();
38175 ae.dom.style.display = 'none';
38179 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38180 * by an implementing function.
38182 * @param {EventObject} e
38184 onTriggerClick : Roo.emptyFn
38187 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38188 // to be extended by an implementing class. For an example of implementing this class, see the custom
38189 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38190 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38191 initComponent : function(){
38192 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38194 this.triggerConfig = {
38195 tag:'span', cls:'x-form-twin-triggers', cn:[
38196 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38197 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38201 getTrigger : function(index){
38202 return this.triggers[index];
38205 initTrigger : function(){
38206 var ts = this.trigger.select('.x-form-trigger', true);
38207 this.wrap.setStyle('overflow', 'hidden');
38208 var triggerField = this;
38209 ts.each(function(t, all, index){
38210 t.hide = function(){
38211 var w = triggerField.wrap.getWidth();
38212 this.dom.style.display = 'none';
38213 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38215 t.show = function(){
38216 var w = triggerField.wrap.getWidth();
38217 this.dom.style.display = '';
38218 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38220 var triggerIndex = 'Trigger'+(index+1);
38222 if(this['hide'+triggerIndex]){
38223 t.dom.style.display = 'none';
38225 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38226 t.addClassOnOver('x-form-trigger-over');
38227 t.addClassOnClick('x-form-trigger-click');
38229 this.triggers = ts.elements;
38232 onTrigger1Click : Roo.emptyFn,
38233 onTrigger2Click : Roo.emptyFn
38236 * Ext JS Library 1.1.1
38237 * Copyright(c) 2006-2007, Ext JS, LLC.
38239 * Originally Released Under LGPL - original licence link has changed is not relivant.
38242 * <script type="text/javascript">
38246 * @class Roo.form.TextArea
38247 * @extends Roo.form.TextField
38248 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38249 * support for auto-sizing.
38251 * Creates a new TextArea
38252 * @param {Object} config Configuration options
38254 Roo.form.TextArea = function(config){
38255 Roo.form.TextArea.superclass.constructor.call(this, config);
38256 // these are provided exchanges for backwards compat
38257 // minHeight/maxHeight were replaced by growMin/growMax to be
38258 // compatible with TextField growing config values
38259 if(this.minHeight !== undefined){
38260 this.growMin = this.minHeight;
38262 if(this.maxHeight !== undefined){
38263 this.growMax = this.maxHeight;
38267 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38269 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38273 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38277 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38278 * in the field (equivalent to setting overflow: hidden, defaults to false)
38280 preventScrollbars: false,
38282 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38283 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38287 onRender : function(ct, position){
38289 this.defaultAutoCreate = {
38291 style:"width:300px;height:60px;",
38292 autocomplete: "new-password"
38295 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38297 this.textSizeEl = Roo.DomHelper.append(document.body, {
38298 tag: "pre", cls: "x-form-grow-sizer"
38300 if(this.preventScrollbars){
38301 this.el.setStyle("overflow", "hidden");
38303 this.el.setHeight(this.growMin);
38307 onDestroy : function(){
38308 if(this.textSizeEl){
38309 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38311 Roo.form.TextArea.superclass.onDestroy.call(this);
38315 onKeyUp : function(e){
38316 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38322 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38323 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38325 autoSize : function(){
38326 if(!this.grow || !this.textSizeEl){
38330 var v = el.dom.value;
38331 var ts = this.textSizeEl;
38334 ts.appendChild(document.createTextNode(v));
38337 Roo.fly(ts).setWidth(this.el.getWidth());
38339 v = "  ";
38342 v = v.replace(/\n/g, '<p> </p>');
38344 v += " \n ";
38347 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38348 if(h != this.lastHeight){
38349 this.lastHeight = h;
38350 this.el.setHeight(h);
38351 this.fireEvent("autosize", this, h);
38356 * Ext JS Library 1.1.1
38357 * Copyright(c) 2006-2007, Ext JS, LLC.
38359 * Originally Released Under LGPL - original licence link has changed is not relivant.
38362 * <script type="text/javascript">
38367 * @class Roo.form.NumberField
38368 * @extends Roo.form.TextField
38369 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38371 * Creates a new NumberField
38372 * @param {Object} config Configuration options
38374 Roo.form.NumberField = function(config){
38375 Roo.form.NumberField.superclass.constructor.call(this, config);
38378 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38380 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38382 fieldClass: "x-form-field x-form-num-field",
38384 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38386 allowDecimals : true,
38388 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38390 decimalSeparator : ".",
38392 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38394 decimalPrecision : 2,
38396 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38398 allowNegative : true,
38400 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38402 minValue : Number.NEGATIVE_INFINITY,
38404 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38406 maxValue : Number.MAX_VALUE,
38408 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38410 minText : "The minimum value for this field is {0}",
38412 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38414 maxText : "The maximum value for this field is {0}",
38416 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38417 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38419 nanText : "{0} is not a valid number",
38422 initEvents : function(){
38423 Roo.form.NumberField.superclass.initEvents.call(this);
38424 var allowed = "0123456789";
38425 if(this.allowDecimals){
38426 allowed += this.decimalSeparator;
38428 if(this.allowNegative){
38431 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38432 var keyPress = function(e){
38433 var k = e.getKey();
38434 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38437 var c = e.getCharCode();
38438 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38442 this.el.on("keypress", keyPress, this);
38446 validateValue : function(value){
38447 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38450 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38453 var num = this.parseValue(value);
38455 this.markInvalid(String.format(this.nanText, value));
38458 if(num < this.minValue){
38459 this.markInvalid(String.format(this.minText, this.minValue));
38462 if(num > this.maxValue){
38463 this.markInvalid(String.format(this.maxText, this.maxValue));
38469 getValue : function(){
38470 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38474 parseValue : function(value){
38475 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38476 return isNaN(value) ? '' : value;
38480 fixPrecision : function(value){
38481 var nan = isNaN(value);
38482 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38483 return nan ? '' : value;
38485 return parseFloat(value).toFixed(this.decimalPrecision);
38488 setValue : function(v){
38489 v = this.fixPrecision(v);
38490 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38494 decimalPrecisionFcn : function(v){
38495 return Math.floor(v);
38498 beforeBlur : function(){
38499 var v = this.parseValue(this.getRawValue());
38506 * Ext JS Library 1.1.1
38507 * Copyright(c) 2006-2007, Ext JS, LLC.
38509 * Originally Released Under LGPL - original licence link has changed is not relivant.
38512 * <script type="text/javascript">
38516 * @class Roo.form.DateField
38517 * @extends Roo.form.TriggerField
38518 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38520 * Create a new DateField
38521 * @param {Object} config
38523 Roo.form.DateField = function(config){
38524 Roo.form.DateField.superclass.constructor.call(this, config);
38530 * Fires when a date is selected
38531 * @param {Roo.form.DateField} combo This combo box
38532 * @param {Date} date The date selected
38539 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38540 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38541 this.ddMatch = null;
38542 if(this.disabledDates){
38543 var dd = this.disabledDates;
38545 for(var i = 0; i < dd.length; i++){
38547 if(i != dd.length-1) re += "|";
38549 this.ddMatch = new RegExp(re + ")");
38553 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38555 * @cfg {String} format
38556 * The default date format string which can be overriden for localization support. The format must be
38557 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38561 * @cfg {String} altFormats
38562 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38563 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38565 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38567 * @cfg {Array} disabledDays
38568 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38570 disabledDays : null,
38572 * @cfg {String} disabledDaysText
38573 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38575 disabledDaysText : "Disabled",
38577 * @cfg {Array} disabledDates
38578 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38579 * expression so they are very powerful. Some examples:
38581 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38582 * <li>["03/08", "09/16"] would disable those days for every year</li>
38583 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38584 * <li>["03/../2006"] would disable every day in March 2006</li>
38585 * <li>["^03"] would disable every day in every March</li>
38587 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38588 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38590 disabledDates : null,
38592 * @cfg {String} disabledDatesText
38593 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38595 disabledDatesText : "Disabled",
38597 * @cfg {Date/String} minValue
38598 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38599 * valid format (defaults to null).
38603 * @cfg {Date/String} maxValue
38604 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38605 * valid format (defaults to null).
38609 * @cfg {String} minText
38610 * The error text to display when the date in the cell is before minValue (defaults to
38611 * 'The date in this field must be after {minValue}').
38613 minText : "The date in this field must be equal to or after {0}",
38615 * @cfg {String} maxText
38616 * The error text to display when the date in the cell is after maxValue (defaults to
38617 * 'The date in this field must be before {maxValue}').
38619 maxText : "The date in this field must be equal to or before {0}",
38621 * @cfg {String} invalidText
38622 * The error text to display when the date in the field is invalid (defaults to
38623 * '{value} is not a valid date - it must be in the format {format}').
38625 invalidText : "{0} is not a valid date - it must be in the format {1}",
38627 * @cfg {String} triggerClass
38628 * An additional CSS class used to style the trigger button. The trigger will always get the
38629 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38630 * which displays a calendar icon).
38632 triggerClass : 'x-form-date-trigger',
38636 * @cfg {Boolean} useIso
38637 * if enabled, then the date field will use a hidden field to store the
38638 * real value as iso formated date. default (false)
38642 * @cfg {String/Object} autoCreate
38643 * A DomHelper element spec, or true for a default element spec (defaults to
38644 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38647 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38650 hiddenField: false,
38652 onRender : function(ct, position)
38654 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38656 //this.el.dom.removeAttribute('name');
38657 Roo.log("Changing name?");
38658 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38659 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38661 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38662 // prevent input submission
38663 this.hiddenName = this.name;
38670 validateValue : function(value)
38672 value = this.formatDate(value);
38673 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38674 Roo.log('super failed');
38677 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38680 var svalue = value;
38681 value = this.parseDate(value);
38683 Roo.log('parse date failed' + svalue);
38684 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38687 var time = value.getTime();
38688 if(this.minValue && time < this.minValue.getTime()){
38689 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38692 if(this.maxValue && time > this.maxValue.getTime()){
38693 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38696 if(this.disabledDays){
38697 var day = value.getDay();
38698 for(var i = 0; i < this.disabledDays.length; i++) {
38699 if(day === this.disabledDays[i]){
38700 this.markInvalid(this.disabledDaysText);
38705 var fvalue = this.formatDate(value);
38706 if(this.ddMatch && this.ddMatch.test(fvalue)){
38707 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38714 // Provides logic to override the default TriggerField.validateBlur which just returns true
38715 validateBlur : function(){
38716 return !this.menu || !this.menu.isVisible();
38719 getName: function()
38721 // returns hidden if it's set..
38722 if (!this.rendered) {return ''};
38723 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38728 * Returns the current date value of the date field.
38729 * @return {Date} The date value
38731 getValue : function(){
38733 return this.hiddenField ?
38734 this.hiddenField.value :
38735 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38739 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38740 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38741 * (the default format used is "m/d/y").
38744 //All of these calls set the same date value (May 4, 2006)
38746 //Pass a date object:
38747 var dt = new Date('5/4/06');
38748 dateField.setValue(dt);
38750 //Pass a date string (default format):
38751 dateField.setValue('5/4/06');
38753 //Pass a date string (custom format):
38754 dateField.format = 'Y-m-d';
38755 dateField.setValue('2006-5-4');
38757 * @param {String/Date} date The date or valid date string
38759 setValue : function(date){
38760 if (this.hiddenField) {
38761 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38763 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38764 // make sure the value field is always stored as a date..
38765 this.value = this.parseDate(date);
38771 parseDate : function(value){
38772 if(!value || value instanceof Date){
38775 var v = Date.parseDate(value, this.format);
38776 if (!v && this.useIso) {
38777 v = Date.parseDate(value, 'Y-m-d');
38779 if(!v && this.altFormats){
38780 if(!this.altFormatsArray){
38781 this.altFormatsArray = this.altFormats.split("|");
38783 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38784 v = Date.parseDate(value, this.altFormatsArray[i]);
38791 formatDate : function(date, fmt){
38792 return (!date || !(date instanceof Date)) ?
38793 date : date.dateFormat(fmt || this.format);
38798 select: function(m, d){
38801 this.fireEvent('select', this, d);
38803 show : function(){ // retain focus styling
38807 this.focus.defer(10, this);
38808 var ml = this.menuListeners;
38809 this.menu.un("select", ml.select, this);
38810 this.menu.un("show", ml.show, this);
38811 this.menu.un("hide", ml.hide, this);
38816 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38817 onTriggerClick : function(){
38821 if(this.menu == null){
38822 this.menu = new Roo.menu.DateMenu();
38824 Roo.apply(this.menu.picker, {
38825 showClear: this.allowBlank,
38826 minDate : this.minValue,
38827 maxDate : this.maxValue,
38828 disabledDatesRE : this.ddMatch,
38829 disabledDatesText : this.disabledDatesText,
38830 disabledDays : this.disabledDays,
38831 disabledDaysText : this.disabledDaysText,
38832 format : this.useIso ? 'Y-m-d' : this.format,
38833 minText : String.format(this.minText, this.formatDate(this.minValue)),
38834 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38836 this.menu.on(Roo.apply({}, this.menuListeners, {
38839 this.menu.picker.setValue(this.getValue() || new Date());
38840 this.menu.show(this.el, "tl-bl?");
38843 beforeBlur : function(){
38844 var v = this.parseDate(this.getRawValue());
38854 isDirty : function() {
38855 if(this.disabled) {
38859 if(typeof(this.startValue) === 'undefined'){
38863 return String(this.getValue()) !== String(this.startValue);
38868 * Ext JS Library 1.1.1
38869 * Copyright(c) 2006-2007, Ext JS, LLC.
38871 * Originally Released Under LGPL - original licence link has changed is not relivant.
38874 * <script type="text/javascript">
38878 * @class Roo.form.MonthField
38879 * @extends Roo.form.TriggerField
38880 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38882 * Create a new MonthField
38883 * @param {Object} config
38885 Roo.form.MonthField = function(config){
38887 Roo.form.MonthField.superclass.constructor.call(this, config);
38893 * Fires when a date is selected
38894 * @param {Roo.form.MonthFieeld} combo This combo box
38895 * @param {Date} date The date selected
38902 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38903 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38904 this.ddMatch = null;
38905 if(this.disabledDates){
38906 var dd = this.disabledDates;
38908 for(var i = 0; i < dd.length; i++){
38910 if(i != dd.length-1) re += "|";
38912 this.ddMatch = new RegExp(re + ")");
38916 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38918 * @cfg {String} format
38919 * The default date format string which can be overriden for localization support. The format must be
38920 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38924 * @cfg {String} altFormats
38925 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38926 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38928 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38930 * @cfg {Array} disabledDays
38931 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38933 disabledDays : [0,1,2,3,4,5,6],
38935 * @cfg {String} disabledDaysText
38936 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38938 disabledDaysText : "Disabled",
38940 * @cfg {Array} disabledDates
38941 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38942 * expression so they are very powerful. Some examples:
38944 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38945 * <li>["03/08", "09/16"] would disable those days for every year</li>
38946 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38947 * <li>["03/../2006"] would disable every day in March 2006</li>
38948 * <li>["^03"] would disable every day in every March</li>
38950 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38951 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38953 disabledDates : null,
38955 * @cfg {String} disabledDatesText
38956 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38958 disabledDatesText : "Disabled",
38960 * @cfg {Date/String} minValue
38961 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38962 * valid format (defaults to null).
38966 * @cfg {Date/String} maxValue
38967 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38968 * valid format (defaults to null).
38972 * @cfg {String} minText
38973 * The error text to display when the date in the cell is before minValue (defaults to
38974 * 'The date in this field must be after {minValue}').
38976 minText : "The date in this field must be equal to or after {0}",
38978 * @cfg {String} maxTextf
38979 * The error text to display when the date in the cell is after maxValue (defaults to
38980 * 'The date in this field must be before {maxValue}').
38982 maxText : "The date in this field must be equal to or before {0}",
38984 * @cfg {String} invalidText
38985 * The error text to display when the date in the field is invalid (defaults to
38986 * '{value} is not a valid date - it must be in the format {format}').
38988 invalidText : "{0} is not a valid date - it must be in the format {1}",
38990 * @cfg {String} triggerClass
38991 * An additional CSS class used to style the trigger button. The trigger will always get the
38992 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38993 * which displays a calendar icon).
38995 triggerClass : 'x-form-date-trigger',
38999 * @cfg {Boolean} useIso
39000 * if enabled, then the date field will use a hidden field to store the
39001 * real value as iso formated date. default (true)
39005 * @cfg {String/Object} autoCreate
39006 * A DomHelper element spec, or true for a default element spec (defaults to
39007 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39010 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39013 hiddenField: false,
39015 hideMonthPicker : false,
39017 onRender : function(ct, position)
39019 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39021 this.el.dom.removeAttribute('name');
39022 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39024 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39025 // prevent input submission
39026 this.hiddenName = this.name;
39033 validateValue : function(value)
39035 value = this.formatDate(value);
39036 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39039 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39042 var svalue = value;
39043 value = this.parseDate(value);
39045 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39048 var time = value.getTime();
39049 if(this.minValue && time < this.minValue.getTime()){
39050 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39053 if(this.maxValue && time > this.maxValue.getTime()){
39054 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39057 /*if(this.disabledDays){
39058 var day = value.getDay();
39059 for(var i = 0; i < this.disabledDays.length; i++) {
39060 if(day === this.disabledDays[i]){
39061 this.markInvalid(this.disabledDaysText);
39067 var fvalue = this.formatDate(value);
39068 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39069 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39077 // Provides logic to override the default TriggerField.validateBlur which just returns true
39078 validateBlur : function(){
39079 return !this.menu || !this.menu.isVisible();
39083 * Returns the current date value of the date field.
39084 * @return {Date} The date value
39086 getValue : function(){
39090 return this.hiddenField ?
39091 this.hiddenField.value :
39092 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39096 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39097 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39098 * (the default format used is "m/d/y").
39101 //All of these calls set the same date value (May 4, 2006)
39103 //Pass a date object:
39104 var dt = new Date('5/4/06');
39105 monthField.setValue(dt);
39107 //Pass a date string (default format):
39108 monthField.setValue('5/4/06');
39110 //Pass a date string (custom format):
39111 monthField.format = 'Y-m-d';
39112 monthField.setValue('2006-5-4');
39114 * @param {String/Date} date The date or valid date string
39116 setValue : function(date){
39117 Roo.log('month setValue' + date);
39118 // can only be first of month..
39120 var val = this.parseDate(date);
39122 if (this.hiddenField) {
39123 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39125 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39126 this.value = this.parseDate(date);
39130 parseDate : function(value){
39131 if(!value || value instanceof Date){
39132 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39135 var v = Date.parseDate(value, this.format);
39136 if (!v && this.useIso) {
39137 v = Date.parseDate(value, 'Y-m-d');
39141 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39145 if(!v && this.altFormats){
39146 if(!this.altFormatsArray){
39147 this.altFormatsArray = this.altFormats.split("|");
39149 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39150 v = Date.parseDate(value, this.altFormatsArray[i]);
39157 formatDate : function(date, fmt){
39158 return (!date || !(date instanceof Date)) ?
39159 date : date.dateFormat(fmt || this.format);
39164 select: function(m, d){
39166 this.fireEvent('select', this, d);
39168 show : function(){ // retain focus styling
39172 this.focus.defer(10, this);
39173 var ml = this.menuListeners;
39174 this.menu.un("select", ml.select, this);
39175 this.menu.un("show", ml.show, this);
39176 this.menu.un("hide", ml.hide, this);
39180 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39181 onTriggerClick : function(){
39185 if(this.menu == null){
39186 this.menu = new Roo.menu.DateMenu();
39190 Roo.apply(this.menu.picker, {
39192 showClear: this.allowBlank,
39193 minDate : this.minValue,
39194 maxDate : this.maxValue,
39195 disabledDatesRE : this.ddMatch,
39196 disabledDatesText : this.disabledDatesText,
39198 format : this.useIso ? 'Y-m-d' : this.format,
39199 minText : String.format(this.minText, this.formatDate(this.minValue)),
39200 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39203 this.menu.on(Roo.apply({}, this.menuListeners, {
39211 // hide month picker get's called when we called by 'before hide';
39213 var ignorehide = true;
39214 p.hideMonthPicker = function(disableAnim){
39218 if(this.monthPicker){
39219 Roo.log("hideMonthPicker called");
39220 if(disableAnim === true){
39221 this.monthPicker.hide();
39223 this.monthPicker.slideOut('t', {duration:.2});
39224 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39225 p.fireEvent("select", this, this.value);
39231 Roo.log('picker set value');
39232 Roo.log(this.getValue());
39233 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39234 m.show(this.el, 'tl-bl?');
39235 ignorehide = false;
39236 // this will trigger hideMonthPicker..
39239 // hidden the day picker
39240 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39246 p.showMonthPicker.defer(100, p);
39252 beforeBlur : function(){
39253 var v = this.parseDate(this.getRawValue());
39259 /** @cfg {Boolean} grow @hide */
39260 /** @cfg {Number} growMin @hide */
39261 /** @cfg {Number} growMax @hide */
39268 * Ext JS Library 1.1.1
39269 * Copyright(c) 2006-2007, Ext JS, LLC.
39271 * Originally Released Under LGPL - original licence link has changed is not relivant.
39274 * <script type="text/javascript">
39279 * @class Roo.form.ComboBox
39280 * @extends Roo.form.TriggerField
39281 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39283 * Create a new ComboBox.
39284 * @param {Object} config Configuration options
39286 Roo.form.ComboBox = function(config){
39287 Roo.form.ComboBox.superclass.constructor.call(this, config);
39291 * Fires when the dropdown list is expanded
39292 * @param {Roo.form.ComboBox} combo This combo box
39297 * Fires when the dropdown list is collapsed
39298 * @param {Roo.form.ComboBox} combo This combo box
39302 * @event beforeselect
39303 * Fires before a list item is selected. Return false to cancel the selection.
39304 * @param {Roo.form.ComboBox} combo This combo box
39305 * @param {Roo.data.Record} record The data record returned from the underlying store
39306 * @param {Number} index The index of the selected item in the dropdown list
39308 'beforeselect' : true,
39311 * Fires when a list item is selected
39312 * @param {Roo.form.ComboBox} combo This combo box
39313 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39314 * @param {Number} index The index of the selected item in the dropdown list
39318 * @event beforequery
39319 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39320 * The event object passed has these properties:
39321 * @param {Roo.form.ComboBox} combo This combo box
39322 * @param {String} query The query
39323 * @param {Boolean} forceAll true to force "all" query
39324 * @param {Boolean} cancel true to cancel the query
39325 * @param {Object} e The query event object
39327 'beforequery': true,
39330 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39331 * @param {Roo.form.ComboBox} combo This combo box
39336 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39337 * @param {Roo.form.ComboBox} combo This combo box
39338 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39344 if(this.transform){
39345 this.allowDomMove = false;
39346 var s = Roo.getDom(this.transform);
39347 if(!this.hiddenName){
39348 this.hiddenName = s.name;
39351 this.mode = 'local';
39352 var d = [], opts = s.options;
39353 for(var i = 0, len = opts.length;i < len; i++){
39355 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39357 this.value = value;
39359 d.push([value, o.text]);
39361 this.store = new Roo.data.SimpleStore({
39363 fields: ['value', 'text'],
39366 this.valueField = 'value';
39367 this.displayField = 'text';
39369 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39370 if(!this.lazyRender){
39371 this.target = true;
39372 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39373 s.parentNode.removeChild(s); // remove it
39374 this.render(this.el.parentNode);
39376 s.parentNode.removeChild(s); // remove it
39381 this.store = Roo.factory(this.store, Roo.data);
39384 this.selectedIndex = -1;
39385 if(this.mode == 'local'){
39386 if(config.queryDelay === undefined){
39387 this.queryDelay = 10;
39389 if(config.minChars === undefined){
39395 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39397 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39400 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39401 * rendering into an Roo.Editor, defaults to false)
39404 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39405 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39408 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39411 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39412 * the dropdown list (defaults to undefined, with no header element)
39416 * @cfg {String/Roo.Template} tpl The template to use to render the output
39420 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39422 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39424 listWidth: undefined,
39426 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39427 * mode = 'remote' or 'text' if mode = 'local')
39429 displayField: undefined,
39431 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39432 * mode = 'remote' or 'value' if mode = 'local').
39433 * Note: use of a valueField requires the user make a selection
39434 * in order for a value to be mapped.
39436 valueField: undefined,
39440 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39441 * field's data value (defaults to the underlying DOM element's name)
39443 hiddenName: undefined,
39445 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39449 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39451 selectedClass: 'x-combo-selected',
39453 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39454 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39455 * which displays a downward arrow icon).
39457 triggerClass : 'x-form-arrow-trigger',
39459 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39463 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39464 * anchor positions (defaults to 'tl-bl')
39466 listAlign: 'tl-bl?',
39468 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39472 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39473 * query specified by the allQuery config option (defaults to 'query')
39475 triggerAction: 'query',
39477 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39478 * (defaults to 4, does not apply if editable = false)
39482 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39483 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39487 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39488 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39492 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39493 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39497 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39498 * when editable = true (defaults to false)
39500 selectOnFocus:false,
39502 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39504 queryParam: 'query',
39506 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39507 * when mode = 'remote' (defaults to 'Loading...')
39509 loadingText: 'Loading...',
39511 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39515 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39519 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39520 * traditional select (defaults to true)
39524 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39528 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39532 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39533 * listWidth has a higher value)
39537 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39538 * allow the user to set arbitrary text into the field (defaults to false)
39540 forceSelection:false,
39542 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39543 * if typeAhead = true (defaults to 250)
39545 typeAheadDelay : 250,
39547 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39548 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39550 valueNotFoundText : undefined,
39552 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39554 blockFocus : false,
39557 * @cfg {Boolean} disableClear Disable showing of clear button.
39559 disableClear : false,
39561 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39563 alwaysQuery : false,
39569 // element that contains real text value.. (when hidden is used..)
39572 onRender : function(ct, position){
39573 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39574 if(this.hiddenName){
39575 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39577 this.hiddenField.value =
39578 this.hiddenValue !== undefined ? this.hiddenValue :
39579 this.value !== undefined ? this.value : '';
39581 // prevent input submission
39582 this.el.dom.removeAttribute('name');
39587 this.el.dom.setAttribute('autocomplete', 'off');
39590 var cls = 'x-combo-list';
39592 this.list = new Roo.Layer({
39593 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39596 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39597 this.list.setWidth(lw);
39598 this.list.swallowEvent('mousewheel');
39599 this.assetHeight = 0;
39602 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39603 this.assetHeight += this.header.getHeight();
39606 this.innerList = this.list.createChild({cls:cls+'-inner'});
39607 this.innerList.on('mouseover', this.onViewOver, this);
39608 this.innerList.on('mousemove', this.onViewMove, this);
39609 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39611 if(this.allowBlank && !this.pageSize && !this.disableClear){
39612 this.footer = this.list.createChild({cls:cls+'-ft'});
39613 this.pageTb = new Roo.Toolbar(this.footer);
39617 this.footer = this.list.createChild({cls:cls+'-ft'});
39618 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39619 {pageSize: this.pageSize});
39623 if (this.pageTb && this.allowBlank && !this.disableClear) {
39625 this.pageTb.add(new Roo.Toolbar.Fill(), {
39626 cls: 'x-btn-icon x-btn-clear',
39628 handler: function()
39631 _this.clearValue();
39632 _this.onSelect(false, -1);
39637 this.assetHeight += this.footer.getHeight();
39642 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39645 this.view = new Roo.View(this.innerList, this.tpl, {
39646 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39649 this.view.on('click', this.onViewClick, this);
39651 this.store.on('beforeload', this.onBeforeLoad, this);
39652 this.store.on('load', this.onLoad, this);
39653 this.store.on('loadexception', this.onLoadException, this);
39655 if(this.resizable){
39656 this.resizer = new Roo.Resizable(this.list, {
39657 pinned:true, handles:'se'
39659 this.resizer.on('resize', function(r, w, h){
39660 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39661 this.listWidth = w;
39662 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39663 this.restrictHeight();
39665 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39667 if(!this.editable){
39668 this.editable = true;
39669 this.setEditable(false);
39673 if (typeof(this.events.add.listeners) != 'undefined') {
39675 this.addicon = this.wrap.createChild(
39676 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39678 this.addicon.on('click', function(e) {
39679 this.fireEvent('add', this);
39682 if (typeof(this.events.edit.listeners) != 'undefined') {
39684 this.editicon = this.wrap.createChild(
39685 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39686 if (this.addicon) {
39687 this.editicon.setStyle('margin-left', '40px');
39689 this.editicon.on('click', function(e) {
39691 // we fire even if inothing is selected..
39692 this.fireEvent('edit', this, this.lastData );
39702 initEvents : function(){
39703 Roo.form.ComboBox.superclass.initEvents.call(this);
39705 this.keyNav = new Roo.KeyNav(this.el, {
39706 "up" : function(e){
39707 this.inKeyMode = true;
39711 "down" : function(e){
39712 if(!this.isExpanded()){
39713 this.onTriggerClick();
39715 this.inKeyMode = true;
39720 "enter" : function(e){
39721 this.onViewClick();
39725 "esc" : function(e){
39729 "tab" : function(e){
39730 this.onViewClick(false);
39731 this.fireEvent("specialkey", this, e);
39737 doRelay : function(foo, bar, hname){
39738 if(hname == 'down' || this.scope.isExpanded()){
39739 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39746 this.queryDelay = Math.max(this.queryDelay || 10,
39747 this.mode == 'local' ? 10 : 250);
39748 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39749 if(this.typeAhead){
39750 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39752 if(this.editable !== false){
39753 this.el.on("keyup", this.onKeyUp, this);
39755 if(this.forceSelection){
39756 this.on('blur', this.doForce, this);
39760 onDestroy : function(){
39762 this.view.setStore(null);
39763 this.view.el.removeAllListeners();
39764 this.view.el.remove();
39765 this.view.purgeListeners();
39768 this.list.destroy();
39771 this.store.un('beforeload', this.onBeforeLoad, this);
39772 this.store.un('load', this.onLoad, this);
39773 this.store.un('loadexception', this.onLoadException, this);
39775 Roo.form.ComboBox.superclass.onDestroy.call(this);
39779 fireKey : function(e){
39780 if(e.isNavKeyPress() && !this.list.isVisible()){
39781 this.fireEvent("specialkey", this, e);
39786 onResize: function(w, h){
39787 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39789 if(typeof w != 'number'){
39790 // we do not handle it!?!?
39793 var tw = this.trigger.getWidth();
39794 tw += this.addicon ? this.addicon.getWidth() : 0;
39795 tw += this.editicon ? this.editicon.getWidth() : 0;
39797 this.el.setWidth( this.adjustWidth('input', x));
39799 this.trigger.setStyle('left', x+'px');
39801 if(this.list && this.listWidth === undefined){
39802 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39803 this.list.setWidth(lw);
39804 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39812 * Allow or prevent the user from directly editing the field text. If false is passed,
39813 * the user will only be able to select from the items defined in the dropdown list. This method
39814 * is the runtime equivalent of setting the 'editable' config option at config time.
39815 * @param {Boolean} value True to allow the user to directly edit the field text
39817 setEditable : function(value){
39818 if(value == this.editable){
39821 this.editable = value;
39823 this.el.dom.setAttribute('readOnly', true);
39824 this.el.on('mousedown', this.onTriggerClick, this);
39825 this.el.addClass('x-combo-noedit');
39827 this.el.dom.setAttribute('readOnly', false);
39828 this.el.un('mousedown', this.onTriggerClick, this);
39829 this.el.removeClass('x-combo-noedit');
39834 onBeforeLoad : function(){
39835 if(!this.hasFocus){
39838 this.innerList.update(this.loadingText ?
39839 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39840 this.restrictHeight();
39841 this.selectedIndex = -1;
39845 onLoad : function(){
39846 if(!this.hasFocus){
39849 if(this.store.getCount() > 0){
39851 this.restrictHeight();
39852 if(this.lastQuery == this.allQuery){
39854 this.el.dom.select();
39856 if(!this.selectByValue(this.value, true)){
39857 this.select(0, true);
39861 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39862 this.taTask.delay(this.typeAheadDelay);
39866 this.onEmptyResults();
39871 onLoadException : function()
39874 Roo.log(this.store.reader.jsonData);
39875 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39876 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39882 onTypeAhead : function(){
39883 if(this.store.getCount() > 0){
39884 var r = this.store.getAt(0);
39885 var newValue = r.data[this.displayField];
39886 var len = newValue.length;
39887 var selStart = this.getRawValue().length;
39888 if(selStart != len){
39889 this.setRawValue(newValue);
39890 this.selectText(selStart, newValue.length);
39896 onSelect : function(record, index){
39897 if(this.fireEvent('beforeselect', this, record, index) !== false){
39898 this.setFromData(index > -1 ? record.data : false);
39900 this.fireEvent('select', this, record, index);
39905 * Returns the currently selected field value or empty string if no value is set.
39906 * @return {String} value The selected value
39908 getValue : function(){
39909 if(this.valueField){
39910 return typeof this.value != 'undefined' ? this.value : '';
39912 return Roo.form.ComboBox.superclass.getValue.call(this);
39916 * Clears any text/value currently set in the field
39918 clearValue : function(){
39919 if(this.hiddenField){
39920 this.hiddenField.value = '';
39923 this.setRawValue('');
39924 this.lastSelectionText = '';
39929 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39930 * will be displayed in the field. If the value does not match the data value of an existing item,
39931 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39932 * Otherwise the field will be blank (although the value will still be set).
39933 * @param {String} value The value to match
39935 setValue : function(v){
39937 if(this.valueField){
39938 var r = this.findRecord(this.valueField, v);
39940 text = r.data[this.displayField];
39941 }else if(this.valueNotFoundText !== undefined){
39942 text = this.valueNotFoundText;
39945 this.lastSelectionText = text;
39946 if(this.hiddenField){
39947 this.hiddenField.value = v;
39949 Roo.form.ComboBox.superclass.setValue.call(this, text);
39953 * @property {Object} the last set data for the element
39958 * Sets the value of the field based on a object which is related to the record format for the store.
39959 * @param {Object} value the value to set as. or false on reset?
39961 setFromData : function(o){
39962 var dv = ''; // display value
39963 var vv = ''; // value value..
39965 if (this.displayField) {
39966 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39968 // this is an error condition!!!
39969 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39972 if(this.valueField){
39973 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39975 if(this.hiddenField){
39976 this.hiddenField.value = vv;
39978 this.lastSelectionText = dv;
39979 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39983 // no hidden field.. - we store the value in 'value', but still display
39984 // display field!!!!
39985 this.lastSelectionText = dv;
39986 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39992 reset : function(){
39993 // overridden so that last data is reset..
39994 this.setValue(this.resetValue);
39995 this.clearInvalid();
39996 this.lastData = false;
39998 this.view.clearSelections();
40002 findRecord : function(prop, value){
40004 if(this.store.getCount() > 0){
40005 this.store.each(function(r){
40006 if(r.data[prop] == value){
40016 getName: function()
40018 // returns hidden if it's set..
40019 if (!this.rendered) {return ''};
40020 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40024 onViewMove : function(e, t){
40025 this.inKeyMode = false;
40029 onViewOver : function(e, t){
40030 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40033 var item = this.view.findItemFromChild(t);
40035 var index = this.view.indexOf(item);
40036 this.select(index, false);
40041 onViewClick : function(doFocus)
40043 var index = this.view.getSelectedIndexes()[0];
40044 var r = this.store.getAt(index);
40046 this.onSelect(r, index);
40048 if(doFocus !== false && !this.blockFocus){
40054 restrictHeight : function(){
40055 this.innerList.dom.style.height = '';
40056 var inner = this.innerList.dom;
40057 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40058 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40059 this.list.beginUpdate();
40060 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40061 this.list.alignTo(this.el, this.listAlign);
40062 this.list.endUpdate();
40066 onEmptyResults : function(){
40071 * Returns true if the dropdown list is expanded, else false.
40073 isExpanded : function(){
40074 return this.list.isVisible();
40078 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40079 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40080 * @param {String} value The data value of the item to select
40081 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40082 * selected item if it is not currently in view (defaults to true)
40083 * @return {Boolean} True if the value matched an item in the list, else false
40085 selectByValue : function(v, scrollIntoView){
40086 if(v !== undefined && v !== null){
40087 var r = this.findRecord(this.valueField || this.displayField, v);
40089 this.select(this.store.indexOf(r), scrollIntoView);
40097 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40098 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40099 * @param {Number} index The zero-based index of the list item to select
40100 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40101 * selected item if it is not currently in view (defaults to true)
40103 select : function(index, scrollIntoView){
40104 this.selectedIndex = index;
40105 this.view.select(index);
40106 if(scrollIntoView !== false){
40107 var el = this.view.getNode(index);
40109 this.innerList.scrollChildIntoView(el, false);
40115 selectNext : function(){
40116 var ct = this.store.getCount();
40118 if(this.selectedIndex == -1){
40120 }else if(this.selectedIndex < ct-1){
40121 this.select(this.selectedIndex+1);
40127 selectPrev : function(){
40128 var ct = this.store.getCount();
40130 if(this.selectedIndex == -1){
40132 }else if(this.selectedIndex != 0){
40133 this.select(this.selectedIndex-1);
40139 onKeyUp : function(e){
40140 if(this.editable !== false && !e.isSpecialKey()){
40141 this.lastKey = e.getKey();
40142 this.dqTask.delay(this.queryDelay);
40147 validateBlur : function(){
40148 return !this.list || !this.list.isVisible();
40152 initQuery : function(){
40153 this.doQuery(this.getRawValue());
40157 doForce : function(){
40158 if(this.el.dom.value.length > 0){
40159 this.el.dom.value =
40160 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40166 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40167 * query allowing the query action to be canceled if needed.
40168 * @param {String} query The SQL query to execute
40169 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40170 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40171 * saved in the current store (defaults to false)
40173 doQuery : function(q, forceAll){
40174 if(q === undefined || q === null){
40179 forceAll: forceAll,
40183 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40187 forceAll = qe.forceAll;
40188 if(forceAll === true || (q.length >= this.minChars)){
40189 if(this.lastQuery != q || this.alwaysQuery){
40190 this.lastQuery = q;
40191 if(this.mode == 'local'){
40192 this.selectedIndex = -1;
40194 this.store.clearFilter();
40196 this.store.filter(this.displayField, q);
40200 this.store.baseParams[this.queryParam] = q;
40202 params: this.getParams(q)
40207 this.selectedIndex = -1;
40214 getParams : function(q){
40216 //p[this.queryParam] = q;
40219 p.limit = this.pageSize;
40225 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40227 collapse : function(){
40228 if(!this.isExpanded()){
40232 Roo.get(document).un('mousedown', this.collapseIf, this);
40233 Roo.get(document).un('mousewheel', this.collapseIf, this);
40234 if (!this.editable) {
40235 Roo.get(document).un('keydown', this.listKeyPress, this);
40237 this.fireEvent('collapse', this);
40241 collapseIf : function(e){
40242 if(!e.within(this.wrap) && !e.within(this.list)){
40248 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40250 expand : function(){
40251 if(this.isExpanded() || !this.hasFocus){
40254 this.list.alignTo(this.el, this.listAlign);
40256 Roo.get(document).on('mousedown', this.collapseIf, this);
40257 Roo.get(document).on('mousewheel', this.collapseIf, this);
40258 if (!this.editable) {
40259 Roo.get(document).on('keydown', this.listKeyPress, this);
40262 this.fireEvent('expand', this);
40266 // Implements the default empty TriggerField.onTriggerClick function
40267 onTriggerClick : function(){
40271 if(this.isExpanded()){
40273 if (!this.blockFocus) {
40278 this.hasFocus = true;
40279 if(this.triggerAction == 'all') {
40280 this.doQuery(this.allQuery, true);
40282 this.doQuery(this.getRawValue());
40284 if (!this.blockFocus) {
40289 listKeyPress : function(e)
40291 //Roo.log('listkeypress');
40292 // scroll to first matching element based on key pres..
40293 if (e.isSpecialKey()) {
40296 var k = String.fromCharCode(e.getKey()).toUpperCase();
40299 var csel = this.view.getSelectedNodes();
40300 var cselitem = false;
40302 var ix = this.view.indexOf(csel[0]);
40303 cselitem = this.store.getAt(ix);
40304 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40310 this.store.each(function(v) {
40312 // start at existing selection.
40313 if (cselitem.id == v.id) {
40319 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40320 match = this.store.indexOf(v);
40325 if (match === false) {
40326 return true; // no more action?
40329 this.view.select(match);
40330 var sn = Roo.get(this.view.getSelectedNodes()[0])
40331 sn.scrollIntoView(sn.dom.parentNode, false);
40335 * @cfg {Boolean} grow
40339 * @cfg {Number} growMin
40343 * @cfg {Number} growMax
40351 * Copyright(c) 2010-2012, Roo J Solutions Limited
40358 * @class Roo.form.ComboBoxArray
40359 * @extends Roo.form.TextField
40360 * A facebook style adder... for lists of email / people / countries etc...
40361 * pick multiple items from a combo box, and shows each one.
40363 * Fred [x] Brian [x] [Pick another |v]
40366 * For this to work: it needs various extra information
40367 * - normal combo problay has
40369 * + displayField, valueField
40371 * For our purpose...
40374 * If we change from 'extends' to wrapping...
40381 * Create a new ComboBoxArray.
40382 * @param {Object} config Configuration options
40386 Roo.form.ComboBoxArray = function(config)
40390 * @event beforeremove
40391 * Fires before remove the value from the list
40392 * @param {Roo.form.ComboBoxArray} _self This combo box array
40393 * @param {Roo.form.ComboBoxArray.Item} item removed item
40395 'beforeremove' : true,
40398 * Fires when remove the value from the list
40399 * @param {Roo.form.ComboBoxArray} _self This combo box array
40400 * @param {Roo.form.ComboBoxArray.Item} item removed item
40407 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40409 this.items = new Roo.util.MixedCollection(false);
40411 // construct the child combo...
40421 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40424 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40429 // behavies liek a hiddne field
40430 inputType: 'hidden',
40432 * @cfg {Number} width The width of the box that displays the selected element
40439 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40443 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40445 hiddenName : false,
40448 // private the array of items that are displayed..
40450 // private - the hidden field el.
40452 // private - the filed el..
40455 //validateValue : function() { return true; }, // all values are ok!
40456 //onAddClick: function() { },
40458 onRender : function(ct, position)
40461 // create the standard hidden element
40462 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40465 // give fake names to child combo;
40466 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40467 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40469 this.combo = Roo.factory(this.combo, Roo.form);
40470 this.combo.onRender(ct, position);
40471 if (typeof(this.combo.width) != 'undefined') {
40472 this.combo.onResize(this.combo.width,0);
40475 this.combo.initEvents();
40477 // assigned so form know we need to do this..
40478 this.store = this.combo.store;
40479 this.valueField = this.combo.valueField;
40480 this.displayField = this.combo.displayField ;
40483 this.combo.wrap.addClass('x-cbarray-grp');
40485 var cbwrap = this.combo.wrap.createChild(
40486 {tag: 'div', cls: 'x-cbarray-cb'},
40491 this.hiddenEl = this.combo.wrap.createChild({
40492 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40494 this.el = this.combo.wrap.createChild({
40495 tag: 'input', type:'hidden' , name: this.name, value : ''
40497 // this.el.dom.removeAttribute("name");
40500 this.outerWrap = this.combo.wrap;
40501 this.wrap = cbwrap;
40503 this.outerWrap.setWidth(this.width);
40504 this.outerWrap.dom.removeChild(this.el.dom);
40506 this.wrap.dom.appendChild(this.el.dom);
40507 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40508 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40510 this.combo.trigger.setStyle('position','relative');
40511 this.combo.trigger.setStyle('left', '0px');
40512 this.combo.trigger.setStyle('top', '2px');
40514 this.combo.el.setStyle('vertical-align', 'text-bottom');
40516 //this.trigger.setStyle('vertical-align', 'top');
40518 // this should use the code from combo really... on('add' ....)
40522 this.adder = this.outerWrap.createChild(
40523 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40525 this.adder.on('click', function(e) {
40526 _t.fireEvent('adderclick', this, e);
40530 //this.adder.on('click', this.onAddClick, _t);
40533 this.combo.on('select', function(cb, rec, ix) {
40534 this.addItem(rec.data);
40537 cb.el.dom.value = '';
40538 //cb.lastData = rec.data;
40547 getName: function()
40549 // returns hidden if it's set..
40550 if (!this.rendered) {return ''};
40551 return this.hiddenName ? this.hiddenName : this.name;
40556 onResize: function(w, h){
40559 // not sure if this is needed..
40560 //this.combo.onResize(w,h);
40562 if(typeof w != 'number'){
40563 // we do not handle it!?!?
40566 var tw = this.combo.trigger.getWidth();
40567 tw += this.addicon ? this.addicon.getWidth() : 0;
40568 tw += this.editicon ? this.editicon.getWidth() : 0;
40570 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40572 this.combo.trigger.setStyle('left', '0px');
40574 if(this.list && this.listWidth === undefined){
40575 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40576 this.list.setWidth(lw);
40577 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40584 addItem: function(rec)
40586 var valueField = this.combo.valueField;
40587 var displayField = this.combo.displayField;
40588 if (this.items.indexOfKey(rec[valueField]) > -1) {
40589 //console.log("GOT " + rec.data.id);
40593 var x = new Roo.form.ComboBoxArray.Item({
40594 //id : rec[this.idField],
40596 displayField : displayField ,
40597 tipField : displayField ,
40601 this.items.add(rec[valueField],x);
40602 // add it before the element..
40603 this.updateHiddenEl();
40604 x.render(this.outerWrap, this.wrap.dom);
40605 // add the image handler..
40608 updateHiddenEl : function()
40611 if (!this.hiddenEl) {
40615 var idField = this.combo.valueField;
40617 this.items.each(function(f) {
40618 ar.push(f.data[idField]);
40621 this.hiddenEl.dom.value = ar.join(',');
40627 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40628 this.items.each(function(f) {
40631 this.el.dom.value = '';
40632 if (this.hiddenEl) {
40633 this.hiddenEl.dom.value = '';
40637 getValue: function()
40639 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40641 setValue: function(v) // not a valid action - must use addItems..
40648 if (this.store.isLocal && (typeof(v) == 'string')) {
40649 // then we can use the store to find the values..
40650 // comma seperated at present.. this needs to allow JSON based encoding..
40651 this.hiddenEl.value = v;
40653 Roo.each(v.split(','), function(k) {
40654 Roo.log("CHECK " + this.valueField + ',' + k);
40655 var li = this.store.query(this.valueField, k);
40660 add[this.valueField] = k;
40661 add[this.displayField] = li.item(0).data[this.displayField];
40667 if (typeof(v) == 'object' ) {
40668 // then let's assume it's an array of objects..
40669 Roo.each(v, function(l) {
40677 setFromData: function(v)
40679 // this recieves an object, if setValues is called.
40681 this.el.dom.value = v[this.displayField];
40682 this.hiddenEl.dom.value = v[this.valueField];
40683 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40686 var kv = v[this.valueField];
40687 var dv = v[this.displayField];
40688 kv = typeof(kv) != 'string' ? '' : kv;
40689 dv = typeof(dv) != 'string' ? '' : dv;
40692 var keys = kv.split(',');
40693 var display = dv.split(',');
40694 for (var i = 0 ; i < keys.length; i++) {
40697 add[this.valueField] = keys[i];
40698 add[this.displayField] = display[i];
40706 * Validates the combox array value
40707 * @return {Boolean} True if the value is valid, else false
40709 validate : function(){
40710 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40711 this.clearInvalid();
40717 validateValue : function(value){
40718 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40726 isDirty : function() {
40727 if(this.disabled) {
40732 var d = Roo.decode(String(this.originalValue));
40734 return String(this.getValue()) !== String(this.originalValue);
40737 var originalValue = [];
40739 for (var i = 0; i < d.length; i++){
40740 originalValue.push(d[i][this.valueField]);
40743 return String(this.getValue()) !== String(originalValue.join(','));
40752 * @class Roo.form.ComboBoxArray.Item
40753 * @extends Roo.BoxComponent
40754 * A selected item in the list
40755 * Fred [x] Brian [x] [Pick another |v]
40758 * Create a new item.
40759 * @param {Object} config Configuration options
40762 Roo.form.ComboBoxArray.Item = function(config) {
40763 config.id = Roo.id();
40764 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40767 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40770 displayField : false,
40774 defaultAutoCreate : {
40776 cls: 'x-cbarray-item',
40783 src : Roo.BLANK_IMAGE_URL ,
40791 onRender : function(ct, position)
40793 Roo.form.Field.superclass.onRender.call(this, ct, position);
40796 var cfg = this.getAutoCreate();
40797 this.el = ct.createChild(cfg, position);
40800 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40802 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40803 this.cb.renderer(this.data) :
40804 String.format('{0}',this.data[this.displayField]);
40807 this.el.child('div').dom.setAttribute('qtip',
40808 String.format('{0}',this.data[this.tipField])
40811 this.el.child('img').on('click', this.remove, this);
40815 remove : function()
40817 if(this.cb.disabled){
40821 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40822 this.cb.items.remove(this);
40823 this.el.child('img').un('click', this.remove, this);
40825 this.cb.updateHiddenEl();
40827 this.cb.fireEvent('remove', this.cb, this);
40833 * Ext JS Library 1.1.1
40834 * Copyright(c) 2006-2007, Ext JS, LLC.
40836 * Originally Released Under LGPL - original licence link has changed is not relivant.
40839 * <script type="text/javascript">
40842 * @class Roo.form.Checkbox
40843 * @extends Roo.form.Field
40844 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40846 * Creates a new Checkbox
40847 * @param {Object} config Configuration options
40849 Roo.form.Checkbox = function(config){
40850 Roo.form.Checkbox.superclass.constructor.call(this, config);
40854 * Fires when the checkbox is checked or unchecked.
40855 * @param {Roo.form.Checkbox} this This checkbox
40856 * @param {Boolean} checked The new checked value
40862 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40864 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40866 focusClass : undefined,
40868 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40870 fieldClass: "x-form-field",
40872 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40876 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40877 * {tag: "input", type: "checkbox", autocomplete: "off"})
40879 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40881 * @cfg {String} boxLabel The text that appears beside the checkbox
40885 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40889 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40891 valueOff: '0', // value when not checked..
40893 actionMode : 'viewEl',
40896 itemCls : 'x-menu-check-item x-form-item',
40897 groupClass : 'x-menu-group-item',
40898 inputType : 'hidden',
40901 inSetChecked: false, // check that we are not calling self...
40903 inputElement: false, // real input element?
40904 basedOn: false, // ????
40906 isFormField: true, // not sure where this is needed!!!!
40908 onResize : function(){
40909 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40910 if(!this.boxLabel){
40911 this.el.alignTo(this.wrap, 'c-c');
40915 initEvents : function(){
40916 Roo.form.Checkbox.superclass.initEvents.call(this);
40917 this.el.on("click", this.onClick, this);
40918 this.el.on("change", this.onClick, this);
40922 getResizeEl : function(){
40926 getPositionEl : function(){
40931 onRender : function(ct, position){
40932 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40934 if(this.inputValue !== undefined){
40935 this.el.dom.value = this.inputValue;
40938 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40939 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40940 var viewEl = this.wrap.createChild({
40941 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40942 this.viewEl = viewEl;
40943 this.wrap.on('click', this.onClick, this);
40945 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40946 this.el.on('propertychange', this.setFromHidden, this); //ie
40951 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40952 // viewEl.on('click', this.onClick, this);
40954 //if(this.checked){
40955 this.setChecked(this.checked);
40957 //this.checked = this.el.dom;
40963 initValue : Roo.emptyFn,
40966 * Returns the checked state of the checkbox.
40967 * @return {Boolean} True if checked, else false
40969 getValue : function(){
40971 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40973 return this.valueOff;
40978 onClick : function(){
40979 if (this.disabled) {
40982 this.setChecked(!this.checked);
40984 //if(this.el.dom.checked != this.checked){
40985 // this.setValue(this.el.dom.checked);
40990 * Sets the checked state of the checkbox.
40991 * On is always based on a string comparison between inputValue and the param.
40992 * @param {Boolean/String} value - the value to set
40993 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40995 setValue : function(v,suppressEvent){
40998 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40999 //if(this.el && this.el.dom){
41000 // this.el.dom.checked = this.checked;
41001 // this.el.dom.defaultChecked = this.checked;
41003 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
41004 //this.fireEvent("check", this, this.checked);
41007 setChecked : function(state,suppressEvent)
41009 if (this.inSetChecked) {
41010 this.checked = state;
41016 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41018 this.checked = state;
41019 if(suppressEvent !== true){
41020 this.fireEvent('check', this, state);
41022 this.inSetChecked = true;
41023 this.el.dom.value = state ? this.inputValue : this.valueOff;
41024 this.inSetChecked = false;
41027 // handle setting of hidden value by some other method!!?!?
41028 setFromHidden: function()
41033 //console.log("SET FROM HIDDEN");
41034 //alert('setFrom hidden');
41035 this.setValue(this.el.dom.value);
41038 onDestroy : function()
41041 Roo.get(this.viewEl).remove();
41044 Roo.form.Checkbox.superclass.onDestroy.call(this);
41049 * Ext JS Library 1.1.1
41050 * Copyright(c) 2006-2007, Ext JS, LLC.
41052 * Originally Released Under LGPL - original licence link has changed is not relivant.
41055 * <script type="text/javascript">
41059 * @class Roo.form.Radio
41060 * @extends Roo.form.Checkbox
41061 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41062 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41064 * Creates a new Radio
41065 * @param {Object} config Configuration options
41067 Roo.form.Radio = function(){
41068 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41070 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41071 inputType: 'radio',
41074 * If this radio is part of a group, it will return the selected value
41077 getGroupValue : function(){
41078 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41082 onRender : function(ct, position){
41083 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41085 if(this.inputValue !== undefined){
41086 this.el.dom.value = this.inputValue;
41089 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41090 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41091 //var viewEl = this.wrap.createChild({
41092 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41093 //this.viewEl = viewEl;
41094 //this.wrap.on('click', this.onClick, this);
41096 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41097 //this.el.on('propertychange', this.setFromHidden, this); //ie
41102 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41103 // viewEl.on('click', this.onClick, this);
41106 this.el.dom.checked = 'checked' ;
41112 });//<script type="text/javascript">
41115 * Based Ext JS Library 1.1.1
41116 * Copyright(c) 2006-2007, Ext JS, LLC.
41122 * @class Roo.HtmlEditorCore
41123 * @extends Roo.Component
41124 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41126 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41129 Roo.HtmlEditorCore = function(config){
41132 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41137 * @event initialize
41138 * Fires when the editor is fully initialized (including the iframe)
41139 * @param {Roo.HtmlEditorCore} this
41144 * Fires when the editor is first receives the focus. Any insertion must wait
41145 * until after this event.
41146 * @param {Roo.HtmlEditorCore} this
41150 * @event beforesync
41151 * Fires before the textarea is updated with content from the editor iframe. Return false
41152 * to cancel the sync.
41153 * @param {Roo.HtmlEditorCore} this
41154 * @param {String} html
41158 * @event beforepush
41159 * Fires before the iframe editor is updated with content from the textarea. Return false
41160 * to cancel the push.
41161 * @param {Roo.HtmlEditorCore} this
41162 * @param {String} html
41167 * Fires when the textarea is updated with content from the editor iframe.
41168 * @param {Roo.HtmlEditorCore} this
41169 * @param {String} html
41174 * Fires when the iframe editor is updated with content from the textarea.
41175 * @param {Roo.HtmlEditorCore} this
41176 * @param {String} html
41181 * @event editorevent
41182 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41183 * @param {Roo.HtmlEditorCore} this
41189 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41191 // defaults : white / black...
41192 this.applyBlacklists();
41199 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41203 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41209 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41214 * @cfg {Number} height (in pixels)
41218 * @cfg {Number} width (in pixels)
41223 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41226 stylesheets: false,
41231 // private properties
41232 validationEvent : false,
41234 initialized : false,
41236 sourceEditMode : false,
41237 onFocus : Roo.emptyFn,
41239 hideMode:'offsets',
41243 // blacklist + whitelisted elements..
41250 * Protected method that will not generally be called directly. It
41251 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41252 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41254 getDocMarkup : function(){
41258 // inherit styels from page...??
41259 if (this.stylesheets === false) {
41261 Roo.get(document.head).select('style').each(function(node) {
41262 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41265 Roo.get(document.head).select('link').each(function(node) {
41266 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41269 } else if (!this.stylesheets.length) {
41271 st = '<style type="text/css">' +
41272 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41278 st += '<style type="text/css">' +
41279 'IMG { cursor: pointer } ' +
41283 return '<html><head>' + st +
41284 //<style type="text/css">' +
41285 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41287 ' </head><body class="roo-htmleditor-body"></body></html>';
41291 onRender : function(ct, position)
41294 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41295 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41298 this.el.dom.style.border = '0 none';
41299 this.el.dom.setAttribute('tabIndex', -1);
41300 this.el.addClass('x-hidden hide');
41304 if(Roo.isIE){ // fix IE 1px bogus margin
41305 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41309 this.frameId = Roo.id();
41313 var iframe = this.owner.wrap.createChild({
41315 cls: 'form-control', // bootstrap..
41317 name: this.frameId,
41318 frameBorder : 'no',
41319 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41324 this.iframe = iframe.dom;
41326 this.assignDocWin();
41328 this.doc.designMode = 'on';
41331 this.doc.write(this.getDocMarkup());
41335 var task = { // must defer to wait for browser to be ready
41337 //console.log("run task?" + this.doc.readyState);
41338 this.assignDocWin();
41339 if(this.doc.body || this.doc.readyState == 'complete'){
41341 this.doc.designMode="on";
41345 Roo.TaskMgr.stop(task);
41346 this.initEditor.defer(10, this);
41353 Roo.TaskMgr.start(task);
41358 onResize : function(w, h)
41360 Roo.log('resize: ' +w + ',' + h );
41361 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41365 if(typeof w == 'number'){
41367 this.iframe.style.width = w + 'px';
41369 if(typeof h == 'number'){
41371 this.iframe.style.height = h + 'px';
41373 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41380 * Toggles the editor between standard and source edit mode.
41381 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41383 toggleSourceEdit : function(sourceEditMode){
41385 this.sourceEditMode = sourceEditMode === true;
41387 if(this.sourceEditMode){
41389 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41392 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41393 //this.iframe.className = '';
41396 //this.setSize(this.owner.wrap.getSize());
41397 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41404 * Protected method that will not generally be called directly. If you need/want
41405 * custom HTML cleanup, this is the method you should override.
41406 * @param {String} html The HTML to be cleaned
41407 * return {String} The cleaned HTML
41409 cleanHtml : function(html){
41410 html = String(html);
41411 if(html.length > 5){
41412 if(Roo.isSafari){ // strip safari nonsense
41413 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41416 if(html == ' '){
41423 * HTML Editor -> Textarea
41424 * Protected method that will not generally be called directly. Syncs the contents
41425 * of the editor iframe with the textarea.
41427 syncValue : function(){
41428 if(this.initialized){
41429 var bd = (this.doc.body || this.doc.documentElement);
41430 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41431 var html = bd.innerHTML;
41433 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41434 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41436 html = '<div style="'+m[0]+'">' + html + '</div>';
41439 html = this.cleanHtml(html);
41440 // fix up the special chars.. normaly like back quotes in word...
41441 // however we do not want to do this with chinese..
41442 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41443 var cc = b.charCodeAt();
41445 (cc >= 0x4E00 && cc < 0xA000 ) ||
41446 (cc >= 0x3400 && cc < 0x4E00 ) ||
41447 (cc >= 0xf900 && cc < 0xfb00 )
41453 if(this.owner.fireEvent('beforesync', this, html) !== false){
41454 this.el.dom.value = html;
41455 this.owner.fireEvent('sync', this, html);
41461 * Protected method that will not generally be called directly. Pushes the value of the textarea
41462 * into the iframe editor.
41464 pushValue : function(){
41465 if(this.initialized){
41466 var v = this.el.dom.value.trim();
41468 // if(v.length < 1){
41472 if(this.owner.fireEvent('beforepush', this, v) !== false){
41473 var d = (this.doc.body || this.doc.documentElement);
41475 this.cleanUpPaste();
41476 this.el.dom.value = d.innerHTML;
41477 this.owner.fireEvent('push', this, v);
41483 deferFocus : function(){
41484 this.focus.defer(10, this);
41488 focus : function(){
41489 if(this.win && !this.sourceEditMode){
41496 assignDocWin: function()
41498 var iframe = this.iframe;
41501 this.doc = iframe.contentWindow.document;
41502 this.win = iframe.contentWindow;
41504 // if (!Roo.get(this.frameId)) {
41507 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41508 // this.win = Roo.get(this.frameId).dom.contentWindow;
41510 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41514 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41515 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41520 initEditor : function(){
41521 //console.log("INIT EDITOR");
41522 this.assignDocWin();
41526 this.doc.designMode="on";
41528 this.doc.write(this.getDocMarkup());
41531 var dbody = (this.doc.body || this.doc.documentElement);
41532 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41533 // this copies styles from the containing element into thsi one..
41534 // not sure why we need all of this..
41535 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41537 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41538 //ss['background-attachment'] = 'fixed'; // w3c
41539 dbody.bgProperties = 'fixed'; // ie
41540 //Roo.DomHelper.applyStyles(dbody, ss);
41541 Roo.EventManager.on(this.doc, {
41542 //'mousedown': this.onEditorEvent,
41543 'mouseup': this.onEditorEvent,
41544 'dblclick': this.onEditorEvent,
41545 'click': this.onEditorEvent,
41546 'keyup': this.onEditorEvent,
41551 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41553 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41554 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41556 this.initialized = true;
41558 this.owner.fireEvent('initialize', this);
41563 onDestroy : function(){
41569 //for (var i =0; i < this.toolbars.length;i++) {
41570 // // fixme - ask toolbars for heights?
41571 // this.toolbars[i].onDestroy();
41574 //this.wrap.dom.innerHTML = '';
41575 //this.wrap.remove();
41580 onFirstFocus : function(){
41582 this.assignDocWin();
41585 this.activated = true;
41588 if(Roo.isGecko){ // prevent silly gecko errors
41590 var s = this.win.getSelection();
41591 if(!s.focusNode || s.focusNode.nodeType != 3){
41592 var r = s.getRangeAt(0);
41593 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41598 this.execCmd('useCSS', true);
41599 this.execCmd('styleWithCSS', false);
41602 this.owner.fireEvent('activate', this);
41606 adjustFont: function(btn){
41607 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41608 //if(Roo.isSafari){ // safari
41611 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41612 if(Roo.isSafari){ // safari
41613 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41614 v = (v < 10) ? 10 : v;
41615 v = (v > 48) ? 48 : v;
41616 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41621 v = Math.max(1, v+adjust);
41623 this.execCmd('FontSize', v );
41626 onEditorEvent : function(e)
41628 this.owner.fireEvent('editorevent', this, e);
41629 // this.updateToolbar();
41630 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41633 insertTag : function(tg)
41635 // could be a bit smarter... -> wrap the current selected tRoo..
41636 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41638 range = this.createRange(this.getSelection());
41639 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41640 wrappingNode.appendChild(range.extractContents());
41641 range.insertNode(wrappingNode);
41648 this.execCmd("formatblock", tg);
41652 insertText : function(txt)
41656 var range = this.createRange();
41657 range.deleteContents();
41658 //alert(Sender.getAttribute('label'));
41660 range.insertNode(this.doc.createTextNode(txt));
41666 * Executes a Midas editor command on the editor document and performs necessary focus and
41667 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41668 * @param {String} cmd The Midas command
41669 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41671 relayCmd : function(cmd, value){
41673 this.execCmd(cmd, value);
41674 this.owner.fireEvent('editorevent', this);
41675 //this.updateToolbar();
41676 this.owner.deferFocus();
41680 * Executes a Midas editor command directly on the editor document.
41681 * For visual commands, you should use {@link #relayCmd} instead.
41682 * <b>This should only be called after the editor is initialized.</b>
41683 * @param {String} cmd The Midas command
41684 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41686 execCmd : function(cmd, value){
41687 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41694 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41696 * @param {String} text | dom node..
41698 insertAtCursor : function(text)
41703 if(!this.activated){
41709 var r = this.doc.selection.createRange();
41720 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41724 // from jquery ui (MIT licenced)
41726 var win = this.win;
41728 if (win.getSelection && win.getSelection().getRangeAt) {
41729 range = win.getSelection().getRangeAt(0);
41730 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41731 range.insertNode(node);
41732 } else if (win.document.selection && win.document.selection.createRange) {
41733 // no firefox support
41734 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41735 win.document.selection.createRange().pasteHTML(txt);
41737 // no firefox support
41738 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41739 this.execCmd('InsertHTML', txt);
41748 mozKeyPress : function(e){
41750 var c = e.getCharCode(), cmd;
41753 c = String.fromCharCode(c).toLowerCase();
41767 this.cleanUpPaste.defer(100, this);
41775 e.preventDefault();
41783 fixKeys : function(){ // load time branching for fastest keydown performance
41785 return function(e){
41786 var k = e.getKey(), r;
41789 r = this.doc.selection.createRange();
41792 r.pasteHTML('    ');
41799 r = this.doc.selection.createRange();
41801 var target = r.parentElement();
41802 if(!target || target.tagName.toLowerCase() != 'li'){
41804 r.pasteHTML('<br />');
41810 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41811 this.cleanUpPaste.defer(100, this);
41817 }else if(Roo.isOpera){
41818 return function(e){
41819 var k = e.getKey();
41823 this.execCmd('InsertHTML','    ');
41826 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41827 this.cleanUpPaste.defer(100, this);
41832 }else if(Roo.isSafari){
41833 return function(e){
41834 var k = e.getKey();
41838 this.execCmd('InsertText','\t');
41842 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41843 this.cleanUpPaste.defer(100, this);
41851 getAllAncestors: function()
41853 var p = this.getSelectedNode();
41856 a.push(p); // push blank onto stack..
41857 p = this.getParentElement();
41861 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41865 a.push(this.doc.body);
41869 lastSelNode : false,
41872 getSelection : function()
41874 this.assignDocWin();
41875 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41878 getSelectedNode: function()
41880 // this may only work on Gecko!!!
41882 // should we cache this!!!!
41887 var range = this.createRange(this.getSelection()).cloneRange();
41890 var parent = range.parentElement();
41892 var testRange = range.duplicate();
41893 testRange.moveToElementText(parent);
41894 if (testRange.inRange(range)) {
41897 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41900 parent = parent.parentElement;
41905 // is ancestor a text element.
41906 var ac = range.commonAncestorContainer;
41907 if (ac.nodeType == 3) {
41908 ac = ac.parentNode;
41911 var ar = ac.childNodes;
41914 var other_nodes = [];
41915 var has_other_nodes = false;
41916 for (var i=0;i<ar.length;i++) {
41917 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41920 // fullly contained node.
41922 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41927 // probably selected..
41928 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41929 other_nodes.push(ar[i]);
41933 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41938 has_other_nodes = true;
41940 if (!nodes.length && other_nodes.length) {
41941 nodes= other_nodes;
41943 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41949 createRange: function(sel)
41951 // this has strange effects when using with
41952 // top toolbar - not sure if it's a great idea.
41953 //this.editor.contentWindow.focus();
41954 if (typeof sel != "undefined") {
41956 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41958 return this.doc.createRange();
41961 return this.doc.createRange();
41964 getParentElement: function()
41967 this.assignDocWin();
41968 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41970 var range = this.createRange(sel);
41973 var p = range.commonAncestorContainer;
41974 while (p.nodeType == 3) { // text node
41985 * Range intersection.. the hard stuff...
41989 * [ -- selected range --- ]
41993 * if end is before start or hits it. fail.
41994 * if start is after end or hits it fail.
41996 * if either hits (but other is outside. - then it's not
42002 // @see http://www.thismuchiknow.co.uk/?p=64.
42003 rangeIntersectsNode : function(range, node)
42005 var nodeRange = node.ownerDocument.createRange();
42007 nodeRange.selectNode(node);
42009 nodeRange.selectNodeContents(node);
42012 var rangeStartRange = range.cloneRange();
42013 rangeStartRange.collapse(true);
42015 var rangeEndRange = range.cloneRange();
42016 rangeEndRange.collapse(false);
42018 var nodeStartRange = nodeRange.cloneRange();
42019 nodeStartRange.collapse(true);
42021 var nodeEndRange = nodeRange.cloneRange();
42022 nodeEndRange.collapse(false);
42024 return rangeStartRange.compareBoundaryPoints(
42025 Range.START_TO_START, nodeEndRange) == -1 &&
42026 rangeEndRange.compareBoundaryPoints(
42027 Range.START_TO_START, nodeStartRange) == 1;
42031 rangeCompareNode : function(range, node)
42033 var nodeRange = node.ownerDocument.createRange();
42035 nodeRange.selectNode(node);
42037 nodeRange.selectNodeContents(node);
42041 range.collapse(true);
42043 nodeRange.collapse(true);
42045 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42046 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42048 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42050 var nodeIsBefore = ss == 1;
42051 var nodeIsAfter = ee == -1;
42053 if (nodeIsBefore && nodeIsAfter)
42055 if (!nodeIsBefore && nodeIsAfter)
42056 return 1; //right trailed.
42058 if (nodeIsBefore && !nodeIsAfter)
42059 return 2; // left trailed.
42064 // private? - in a new class?
42065 cleanUpPaste : function()
42067 // cleans up the whole document..
42068 Roo.log('cleanuppaste');
42070 this.cleanUpChildren(this.doc.body);
42071 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42072 if (clean != this.doc.body.innerHTML) {
42073 this.doc.body.innerHTML = clean;
42078 cleanWordChars : function(input) {// change the chars to hex code
42079 var he = Roo.HtmlEditorCore;
42081 var output = input;
42082 Roo.each(he.swapCodes, function(sw) {
42083 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42085 output = output.replace(swapper, sw[1]);
42092 cleanUpChildren : function (n)
42094 if (!n.childNodes.length) {
42097 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42098 this.cleanUpChild(n.childNodes[i]);
42105 cleanUpChild : function (node)
42108 //console.log(node);
42109 if (node.nodeName == "#text") {
42110 // clean up silly Windows -- stuff?
42113 if (node.nodeName == "#comment") {
42114 node.parentNode.removeChild(node);
42115 // clean up silly Windows -- stuff?
42118 var lcname = node.tagName.toLowerCase();
42119 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42120 // whitelist of tags..
42122 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42124 node.parentNode.removeChild(node);
42129 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42131 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42132 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42134 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42135 // remove_keep_children = true;
42138 if (remove_keep_children) {
42139 this.cleanUpChildren(node);
42140 // inserts everything just before this node...
42141 while (node.childNodes.length) {
42142 var cn = node.childNodes[0];
42143 node.removeChild(cn);
42144 node.parentNode.insertBefore(cn, node);
42146 node.parentNode.removeChild(node);
42150 if (!node.attributes || !node.attributes.length) {
42151 this.cleanUpChildren(node);
42155 function cleanAttr(n,v)
42158 if (v.match(/^\./) || v.match(/^\//)) {
42161 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42164 if (v.match(/^#/)) {
42167 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42168 node.removeAttribute(n);
42172 var cwhite = this.cwhite;
42173 var cblack = this.cblack;
42175 function cleanStyle(n,v)
42177 if (v.match(/expression/)) { //XSS?? should we even bother..
42178 node.removeAttribute(n);
42182 var parts = v.split(/;/);
42185 Roo.each(parts, function(p) {
42186 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42190 var l = p.split(':').shift().replace(/\s+/g,'');
42191 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42193 if ( cwhite.length && cblack.indexOf(l) > -1) {
42194 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42195 //node.removeAttribute(n);
42199 // only allow 'c whitelisted system attributes'
42200 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42201 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42202 //node.removeAttribute(n);
42212 if (clean.length) {
42213 node.setAttribute(n, clean.join(';'));
42215 node.removeAttribute(n);
42221 for (var i = node.attributes.length-1; i > -1 ; i--) {
42222 var a = node.attributes[i];
42225 if (a.name.toLowerCase().substr(0,2)=='on') {
42226 node.removeAttribute(a.name);
42229 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42230 node.removeAttribute(a.name);
42233 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42234 cleanAttr(a.name,a.value); // fixme..
42237 if (a.name == 'style') {
42238 cleanStyle(a.name,a.value);
42241 /// clean up MS crap..
42242 // tecnically this should be a list of valid class'es..
42245 if (a.name == 'class') {
42246 if (a.value.match(/^Mso/)) {
42247 node.className = '';
42250 if (a.value.match(/body/)) {
42251 node.className = '';
42262 this.cleanUpChildren(node);
42268 * Clean up MS wordisms...
42270 cleanWord : function(node)
42275 this.cleanWord(this.doc.body);
42278 if (node.nodeName == "#text") {
42279 // clean up silly Windows -- stuff?
42282 if (node.nodeName == "#comment") {
42283 node.parentNode.removeChild(node);
42284 // clean up silly Windows -- stuff?
42288 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42289 node.parentNode.removeChild(node);
42293 // remove - but keep children..
42294 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42295 while (node.childNodes.length) {
42296 var cn = node.childNodes[0];
42297 node.removeChild(cn);
42298 node.parentNode.insertBefore(cn, node);
42300 node.parentNode.removeChild(node);
42301 this.iterateChildren(node, this.cleanWord);
42305 if (node.className.length) {
42307 var cn = node.className.split(/\W+/);
42309 Roo.each(cn, function(cls) {
42310 if (cls.match(/Mso[a-zA-Z]+/)) {
42315 node.className = cna.length ? cna.join(' ') : '';
42317 node.removeAttribute("class");
42321 if (node.hasAttribute("lang")) {
42322 node.removeAttribute("lang");
42325 if (node.hasAttribute("style")) {
42327 var styles = node.getAttribute("style").split(";");
42329 Roo.each(styles, function(s) {
42330 if (!s.match(/:/)) {
42333 var kv = s.split(":");
42334 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42337 // what ever is left... we allow.
42340 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42341 if (!nstyle.length) {
42342 node.removeAttribute('style');
42345 this.iterateChildren(node, this.cleanWord);
42351 * iterateChildren of a Node, calling fn each time, using this as the scole..
42352 * @param {DomNode} node node to iterate children of.
42353 * @param {Function} fn method of this class to call on each item.
42355 iterateChildren : function(node, fn)
42357 if (!node.childNodes.length) {
42360 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42361 fn.call(this, node.childNodes[i])
42367 * cleanTableWidths.
42369 * Quite often pasting from word etc.. results in tables with column and widths.
42370 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42373 cleanTableWidths : function(node)
42378 this.cleanTableWidths(this.doc.body);
42383 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42386 Roo.log(node.tagName);
42387 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42388 this.iterateChildren(node, this.cleanTableWidths);
42391 if (node.hasAttribute('width')) {
42392 node.removeAttribute('width');
42396 if (node.hasAttribute("style")) {
42399 var styles = node.getAttribute("style").split(";");
42401 Roo.each(styles, function(s) {
42402 if (!s.match(/:/)) {
42405 var kv = s.split(":");
42406 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42409 // what ever is left... we allow.
42412 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42413 if (!nstyle.length) {
42414 node.removeAttribute('style');
42418 this.iterateChildren(node, this.cleanTableWidths);
42426 domToHTML : function(currentElement, depth, nopadtext) {
42428 depth = depth || 0;
42429 nopadtext = nopadtext || false;
42431 if (!currentElement) {
42432 return this.domToHTML(this.doc.body);
42435 //Roo.log(currentElement);
42437 var allText = false;
42438 var nodeName = currentElement.nodeName;
42439 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42441 if (nodeName == '#text') {
42443 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42448 if (nodeName != 'BODY') {
42451 // Prints the node tagName, such as <A>, <IMG>, etc
42454 for(i = 0; i < currentElement.attributes.length;i++) {
42456 var aname = currentElement.attributes.item(i).name;
42457 if (!currentElement.attributes.item(i).value.length) {
42460 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42463 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42472 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42475 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42480 // Traverse the tree
42482 var currentElementChild = currentElement.childNodes.item(i);
42483 var allText = true;
42484 var innerHTML = '';
42486 while (currentElementChild) {
42487 // Formatting code (indent the tree so it looks nice on the screen)
42488 var nopad = nopadtext;
42489 if (lastnode == 'SPAN') {
42493 if (currentElementChild.nodeName == '#text') {
42494 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42495 toadd = nopadtext ? toadd : toadd.trim();
42496 if (!nopad && toadd.length > 80) {
42497 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42499 innerHTML += toadd;
42502 currentElementChild = currentElement.childNodes.item(i);
42508 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42510 // Recursively traverse the tree structure of the child node
42511 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42512 lastnode = currentElementChild.nodeName;
42514 currentElementChild=currentElement.childNodes.item(i);
42520 // The remaining code is mostly for formatting the tree
42521 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42526 ret+= "</"+tagName+">";
42532 applyBlacklists : function()
42534 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42535 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42539 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42540 if (b.indexOf(tag) > -1) {
42543 this.white.push(tag);
42547 Roo.each(w, function(tag) {
42548 if (b.indexOf(tag) > -1) {
42551 if (this.white.indexOf(tag) > -1) {
42554 this.white.push(tag);
42559 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42560 if (w.indexOf(tag) > -1) {
42563 this.black.push(tag);
42567 Roo.each(b, function(tag) {
42568 if (w.indexOf(tag) > -1) {
42571 if (this.black.indexOf(tag) > -1) {
42574 this.black.push(tag);
42579 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42580 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42584 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42585 if (b.indexOf(tag) > -1) {
42588 this.cwhite.push(tag);
42592 Roo.each(w, function(tag) {
42593 if (b.indexOf(tag) > -1) {
42596 if (this.cwhite.indexOf(tag) > -1) {
42599 this.cwhite.push(tag);
42604 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42605 if (w.indexOf(tag) > -1) {
42608 this.cblack.push(tag);
42612 Roo.each(b, function(tag) {
42613 if (w.indexOf(tag) > -1) {
42616 if (this.cblack.indexOf(tag) > -1) {
42619 this.cblack.push(tag);
42624 setStylesheets : function(stylesheets)
42626 if(typeof(stylesheets) == 'string'){
42627 Roo.get(this.iframe.contentDocument.head).createChild({
42629 rel : 'stylesheet',
42638 Roo.each(stylesheets, function(s) {
42643 Roo.get(_this.iframe.contentDocument.head).createChild({
42645 rel : 'stylesheet',
42654 removeStylesheets : function()
42658 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42663 // hide stuff that is not compatible
42677 * @event specialkey
42681 * @cfg {String} fieldClass @hide
42684 * @cfg {String} focusClass @hide
42687 * @cfg {String} autoCreate @hide
42690 * @cfg {String} inputType @hide
42693 * @cfg {String} invalidClass @hide
42696 * @cfg {String} invalidText @hide
42699 * @cfg {String} msgFx @hide
42702 * @cfg {String} validateOnBlur @hide
42706 Roo.HtmlEditorCore.white = [
42707 'area', 'br', 'img', 'input', 'hr', 'wbr',
42709 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42710 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42711 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42712 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42713 'table', 'ul', 'xmp',
42715 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42718 'dir', 'menu', 'ol', 'ul', 'dl',
42724 Roo.HtmlEditorCore.black = [
42725 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42727 'base', 'basefont', 'bgsound', 'blink', 'body',
42728 'frame', 'frameset', 'head', 'html', 'ilayer',
42729 'iframe', 'layer', 'link', 'meta', 'object',
42730 'script', 'style' ,'title', 'xml' // clean later..
42732 Roo.HtmlEditorCore.clean = [
42733 'script', 'style', 'title', 'xml'
42735 Roo.HtmlEditorCore.remove = [
42740 Roo.HtmlEditorCore.ablack = [
42744 Roo.HtmlEditorCore.aclean = [
42745 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42749 Roo.HtmlEditorCore.pwhite= [
42750 'http', 'https', 'mailto'
42753 // white listed style attributes.
42754 Roo.HtmlEditorCore.cwhite= [
42755 // 'text-align', /// default is to allow most things..
42761 // black listed style attributes.
42762 Roo.HtmlEditorCore.cblack= [
42763 // 'font-size' -- this can be set by the project
42767 Roo.HtmlEditorCore.swapCodes =[
42778 //<script type="text/javascript">
42781 * Ext JS Library 1.1.1
42782 * Copyright(c) 2006-2007, Ext JS, LLC.
42788 Roo.form.HtmlEditor = function(config){
42792 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42794 if (!this.toolbars) {
42795 this.toolbars = [];
42797 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42803 * @class Roo.form.HtmlEditor
42804 * @extends Roo.form.Field
42805 * Provides a lightweight HTML Editor component.
42807 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42809 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42810 * supported by this editor.</b><br/><br/>
42811 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42812 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42814 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42816 * @cfg {Boolean} clearUp
42820 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42825 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42830 * @cfg {Number} height (in pixels)
42834 * @cfg {Number} width (in pixels)
42839 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42842 stylesheets: false,
42846 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42851 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42857 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42862 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42870 // private properties
42871 validationEvent : false,
42873 initialized : false,
42876 onFocus : Roo.emptyFn,
42878 hideMode:'offsets',
42880 actionMode : 'container', // defaults to hiding it...
42882 defaultAutoCreate : { // modified by initCompnoent..
42884 style:"width:500px;height:300px;",
42885 autocomplete: "new-password"
42889 initComponent : function(){
42892 * @event initialize
42893 * Fires when the editor is fully initialized (including the iframe)
42894 * @param {HtmlEditor} this
42899 * Fires when the editor is first receives the focus. Any insertion must wait
42900 * until after this event.
42901 * @param {HtmlEditor} this
42905 * @event beforesync
42906 * Fires before the textarea is updated with content from the editor iframe. Return false
42907 * to cancel the sync.
42908 * @param {HtmlEditor} this
42909 * @param {String} html
42913 * @event beforepush
42914 * Fires before the iframe editor is updated with content from the textarea. Return false
42915 * to cancel the push.
42916 * @param {HtmlEditor} this
42917 * @param {String} html
42922 * Fires when the textarea is updated with content from the editor iframe.
42923 * @param {HtmlEditor} this
42924 * @param {String} html
42929 * Fires when the iframe editor is updated with content from the textarea.
42930 * @param {HtmlEditor} this
42931 * @param {String} html
42935 * @event editmodechange
42936 * Fires when the editor switches edit modes
42937 * @param {HtmlEditor} this
42938 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42940 editmodechange: true,
42942 * @event editorevent
42943 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42944 * @param {HtmlEditor} this
42948 * @event firstfocus
42949 * Fires when on first focus - needed by toolbars..
42950 * @param {HtmlEditor} this
42955 * Auto save the htmlEditor value as a file into Events
42956 * @param {HtmlEditor} this
42960 * @event savedpreview
42961 * preview the saved version of htmlEditor
42962 * @param {HtmlEditor} this
42964 savedpreview: true,
42967 * @event stylesheetsclick
42968 * Fires when press the Sytlesheets button
42969 * @param {Roo.HtmlEditorCore} this
42971 stylesheetsclick: true
42973 this.defaultAutoCreate = {
42975 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42976 autocomplete: "new-password"
42981 * Protected method that will not generally be called directly. It
42982 * is called when the editor creates its toolbar. Override this method if you need to
42983 * add custom toolbar buttons.
42984 * @param {HtmlEditor} editor
42986 createToolbar : function(editor){
42987 Roo.log("create toolbars");
42988 if (!editor.toolbars || !editor.toolbars.length) {
42989 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42992 for (var i =0 ; i < editor.toolbars.length;i++) {
42993 editor.toolbars[i] = Roo.factory(
42994 typeof(editor.toolbars[i]) == 'string' ?
42995 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42996 Roo.form.HtmlEditor);
42997 editor.toolbars[i].init(editor);
43005 onRender : function(ct, position)
43008 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43010 this.wrap = this.el.wrap({
43011 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43014 this.editorcore.onRender(ct, position);
43016 if (this.resizable) {
43017 this.resizeEl = new Roo.Resizable(this.wrap, {
43021 minHeight : this.height,
43022 height: this.height,
43023 handles : this.resizable,
43026 resize : function(r, w, h) {
43027 _t.onResize(w,h); // -something
43033 this.createToolbar(this);
43037 this.setSize(this.wrap.getSize());
43039 if (this.resizeEl) {
43040 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43041 // should trigger onReize..
43044 this.keyNav = new Roo.KeyNav(this.el, {
43046 "tab" : function(e){
43047 e.preventDefault();
43049 var value = this.getValue();
43051 var start = this.el.dom.selectionStart;
43052 var end = this.el.dom.selectionEnd;
43056 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43057 this.el.dom.setSelectionRange(end + 1, end + 1);
43061 var f = value.substring(0, start).split("\t");
43063 if(f.pop().length != 0){
43067 this.setValue(f.join("\t") + value.substring(end));
43068 this.el.dom.setSelectionRange(start - 1, start - 1);
43072 "home" : function(e){
43073 e.preventDefault();
43075 var curr = this.el.dom.selectionStart;
43076 var lines = this.getValue().split("\n");
43083 this.el.dom.setSelectionRange(0, 0);
43089 for (var i = 0; i < lines.length;i++) {
43090 pos += lines[i].length;
43100 pos -= lines[i].length;
43106 this.el.dom.setSelectionRange(pos, pos);
43110 this.el.dom.selectionStart = pos;
43111 this.el.dom.selectionEnd = curr;
43114 "end" : function(e){
43115 e.preventDefault();
43117 var curr = this.el.dom.selectionStart;
43118 var lines = this.getValue().split("\n");
43125 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43131 for (var i = 0; i < lines.length;i++) {
43133 pos += lines[i].length;
43147 this.el.dom.setSelectionRange(pos, pos);
43151 this.el.dom.selectionStart = curr;
43152 this.el.dom.selectionEnd = pos;
43157 doRelay : function(foo, bar, hname){
43158 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43164 // if(this.autosave && this.w){
43165 // this.autoSaveFn = setInterval(this.autosave, 1000);
43170 onResize : function(w, h)
43172 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43177 if(typeof w == 'number'){
43178 var aw = w - this.wrap.getFrameWidth('lr');
43179 this.el.setWidth(this.adjustWidth('textarea', aw));
43182 if(typeof h == 'number'){
43184 for (var i =0; i < this.toolbars.length;i++) {
43185 // fixme - ask toolbars for heights?
43186 tbh += this.toolbars[i].tb.el.getHeight();
43187 if (this.toolbars[i].footer) {
43188 tbh += this.toolbars[i].footer.el.getHeight();
43195 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43196 ah -= 5; // knock a few pixes off for look..
43198 this.el.setHeight(this.adjustWidth('textarea', ah));
43202 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43203 this.editorcore.onResize(ew,eh);
43208 * Toggles the editor between standard and source edit mode.
43209 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43211 toggleSourceEdit : function(sourceEditMode)
43213 this.editorcore.toggleSourceEdit(sourceEditMode);
43215 if(this.editorcore.sourceEditMode){
43216 Roo.log('editor - showing textarea');
43219 // Roo.log(this.syncValue());
43220 this.editorcore.syncValue();
43221 this.el.removeClass('x-hidden');
43222 this.el.dom.removeAttribute('tabIndex');
43225 for (var i = 0; i < this.toolbars.length; i++) {
43226 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43227 this.toolbars[i].tb.hide();
43228 this.toolbars[i].footer.hide();
43233 Roo.log('editor - hiding textarea');
43235 // Roo.log(this.pushValue());
43236 this.editorcore.pushValue();
43238 this.el.addClass('x-hidden');
43239 this.el.dom.setAttribute('tabIndex', -1);
43241 for (var i = 0; i < this.toolbars.length; i++) {
43242 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43243 this.toolbars[i].tb.show();
43244 this.toolbars[i].footer.show();
43248 //this.deferFocus();
43251 this.setSize(this.wrap.getSize());
43252 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43254 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43257 // private (for BoxComponent)
43258 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43260 // private (for BoxComponent)
43261 getResizeEl : function(){
43265 // private (for BoxComponent)
43266 getPositionEl : function(){
43271 initEvents : function(){
43272 this.originalValue = this.getValue();
43276 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43279 markInvalid : Roo.emptyFn,
43281 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43284 clearInvalid : Roo.emptyFn,
43286 setValue : function(v){
43287 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43288 this.editorcore.pushValue();
43293 deferFocus : function(){
43294 this.focus.defer(10, this);
43298 focus : function(){
43299 this.editorcore.focus();
43305 onDestroy : function(){
43311 for (var i =0; i < this.toolbars.length;i++) {
43312 // fixme - ask toolbars for heights?
43313 this.toolbars[i].onDestroy();
43316 this.wrap.dom.innerHTML = '';
43317 this.wrap.remove();
43322 onFirstFocus : function(){
43323 //Roo.log("onFirstFocus");
43324 this.editorcore.onFirstFocus();
43325 for (var i =0; i < this.toolbars.length;i++) {
43326 this.toolbars[i].onFirstFocus();
43332 syncValue : function()
43334 this.editorcore.syncValue();
43337 pushValue : function()
43339 this.editorcore.pushValue();
43342 setStylesheets : function(stylesheets)
43344 this.editorcore.setStylesheets(stylesheets);
43347 removeStylesheets : function()
43349 this.editorcore.removeStylesheets();
43353 // hide stuff that is not compatible
43367 * @event specialkey
43371 * @cfg {String} fieldClass @hide
43374 * @cfg {String} focusClass @hide
43377 * @cfg {String} autoCreate @hide
43380 * @cfg {String} inputType @hide
43383 * @cfg {String} invalidClass @hide
43386 * @cfg {String} invalidText @hide
43389 * @cfg {String} msgFx @hide
43392 * @cfg {String} validateOnBlur @hide
43396 // <script type="text/javascript">
43399 * Ext JS Library 1.1.1
43400 * Copyright(c) 2006-2007, Ext JS, LLC.
43406 * @class Roo.form.HtmlEditorToolbar1
43411 new Roo.form.HtmlEditor({
43414 new Roo.form.HtmlEditorToolbar1({
43415 disable : { fonts: 1 , format: 1, ..., ... , ...],
43421 * @cfg {Object} disable List of elements to disable..
43422 * @cfg {Array} btns List of additional buttons.
43426 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43429 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43432 Roo.apply(this, config);
43434 // default disabled, based on 'good practice'..
43435 this.disable = this.disable || {};
43436 Roo.applyIf(this.disable, {
43439 specialElements : true
43443 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43444 // dont call parent... till later.
43447 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43454 editorcore : false,
43456 * @cfg {Object} disable List of toolbar elements to disable
43463 * @cfg {String} createLinkText The default text for the create link prompt
43465 createLinkText : 'Please enter the URL for the link:',
43467 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43469 defaultLinkValue : 'http:/'+'/',
43473 * @cfg {Array} fontFamilies An array of available font families
43491 // "á" , ?? a acute?
43496 "°" // , // degrees
43498 // "é" , // e ecute
43499 // "ú" , // u ecute?
43502 specialElements : [
43504 text: "Insert Table",
43507 ihtml : '<table><tr><td>Cell</td></tr></table>'
43511 text: "Insert Image",
43514 ihtml : '<img src="about:blank"/>'
43523 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43524 "input:submit", "input:button", "select", "textarea", "label" ],
43527 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43529 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43537 * @cfg {String} defaultFont default font to use.
43539 defaultFont: 'tahoma',
43541 fontSelect : false,
43544 formatCombo : false,
43546 init : function(editor)
43548 this.editor = editor;
43549 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43550 var editorcore = this.editorcore;
43554 var fid = editorcore.frameId;
43556 function btn(id, toggle, handler){
43557 var xid = fid + '-'+ id ;
43561 cls : 'x-btn-icon x-edit-'+id,
43562 enableToggle:toggle !== false,
43563 scope: _t, // was editor...
43564 handler:handler||_t.relayBtnCmd,
43565 clickEvent:'mousedown',
43566 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43573 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43575 // stop form submits
43576 tb.el.on('click', function(e){
43577 e.preventDefault(); // what does this do?
43580 if(!this.disable.font) { // && !Roo.isSafari){
43581 /* why no safari for fonts
43582 editor.fontSelect = tb.el.createChild({
43585 cls:'x-font-select',
43586 html: this.createFontOptions()
43589 editor.fontSelect.on('change', function(){
43590 var font = editor.fontSelect.dom.value;
43591 editor.relayCmd('fontname', font);
43592 editor.deferFocus();
43596 editor.fontSelect.dom,
43602 if(!this.disable.formats){
43603 this.formatCombo = new Roo.form.ComboBox({
43604 store: new Roo.data.SimpleStore({
43607 data : this.formats // from states.js
43611 //autoCreate : {tag: "div", size: "20"},
43612 displayField:'tag',
43616 triggerAction: 'all',
43617 emptyText:'Add tag',
43618 selectOnFocus:true,
43621 'select': function(c, r, i) {
43622 editorcore.insertTag(r.get('tag'));
43628 tb.addField(this.formatCombo);
43632 if(!this.disable.format){
43637 btn('strikethrough')
43640 if(!this.disable.fontSize){
43645 btn('increasefontsize', false, editorcore.adjustFont),
43646 btn('decreasefontsize', false, editorcore.adjustFont)
43651 if(!this.disable.colors){
43654 id:editorcore.frameId +'-forecolor',
43655 cls:'x-btn-icon x-edit-forecolor',
43656 clickEvent:'mousedown',
43657 tooltip: this.buttonTips['forecolor'] || undefined,
43659 menu : new Roo.menu.ColorMenu({
43660 allowReselect: true,
43661 focus: Roo.emptyFn,
43664 selectHandler: function(cp, color){
43665 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43666 editor.deferFocus();
43669 clickEvent:'mousedown'
43672 id:editorcore.frameId +'backcolor',
43673 cls:'x-btn-icon x-edit-backcolor',
43674 clickEvent:'mousedown',
43675 tooltip: this.buttonTips['backcolor'] || undefined,
43677 menu : new Roo.menu.ColorMenu({
43678 focus: Roo.emptyFn,
43681 allowReselect: true,
43682 selectHandler: function(cp, color){
43684 editorcore.execCmd('useCSS', false);
43685 editorcore.execCmd('hilitecolor', color);
43686 editorcore.execCmd('useCSS', true);
43687 editor.deferFocus();
43689 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43690 Roo.isSafari || Roo.isIE ? '#'+color : color);
43691 editor.deferFocus();
43695 clickEvent:'mousedown'
43700 // now add all the items...
43703 if(!this.disable.alignments){
43706 btn('justifyleft'),
43707 btn('justifycenter'),
43708 btn('justifyright')
43712 //if(!Roo.isSafari){
43713 if(!this.disable.links){
43716 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43720 if(!this.disable.lists){
43723 btn('insertorderedlist'),
43724 btn('insertunorderedlist')
43727 if(!this.disable.sourceEdit){
43730 btn('sourceedit', true, function(btn){
43731 this.toggleSourceEdit(btn.pressed);
43738 // special menu.. - needs to be tidied up..
43739 if (!this.disable.special) {
43742 cls: 'x-edit-none',
43748 for (var i =0; i < this.specialChars.length; i++) {
43749 smenu.menu.items.push({
43751 html: this.specialChars[i],
43752 handler: function(a,b) {
43753 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43754 //editor.insertAtCursor(a.html);
43768 if (!this.disable.cleanStyles) {
43770 cls: 'x-btn-icon x-btn-clear',
43776 for (var i =0; i < this.cleanStyles.length; i++) {
43777 cmenu.menu.items.push({
43778 actiontype : this.cleanStyles[i],
43779 html: 'Remove ' + this.cleanStyles[i],
43780 handler: function(a,b) {
43783 var c = Roo.get(editorcore.doc.body);
43784 c.select('[style]').each(function(s) {
43785 s.dom.style.removeProperty(a.actiontype);
43787 editorcore.syncValue();
43792 cmenu.menu.items.push({
43793 actiontype : 'tablewidths',
43794 html: 'Remove Table Widths',
43795 handler: function(a,b) {
43796 editorcore.cleanTableWidths();
43797 editorcore.syncValue();
43801 cmenu.menu.items.push({
43802 actiontype : 'word',
43803 html: 'Remove MS Word Formating',
43804 handler: function(a,b) {
43805 editorcore.cleanWord();
43806 editorcore.syncValue();
43811 cmenu.menu.items.push({
43812 actiontype : 'all',
43813 html: 'Remove All Styles',
43814 handler: function(a,b) {
43816 var c = Roo.get(editorcore.doc.body);
43817 c.select('[style]').each(function(s) {
43818 s.dom.removeAttribute('style');
43820 editorcore.syncValue();
43825 cmenu.menu.items.push({
43826 actiontype : 'all',
43827 html: 'Remove All CSS Classes',
43828 handler: function(a,b) {
43830 var c = Roo.get(editorcore.doc.body);
43831 c.select('[class]').each(function(s) {
43832 s.dom.className = '';
43834 editorcore.syncValue();
43839 cmenu.menu.items.push({
43840 actiontype : 'tidy',
43841 html: 'Tidy HTML Source',
43842 handler: function(a,b) {
43843 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43844 editorcore.syncValue();
43853 if (!this.disable.specialElements) {
43856 cls: 'x-edit-none',
43861 for (var i =0; i < this.specialElements.length; i++) {
43862 semenu.menu.items.push(
43864 handler: function(a,b) {
43865 editor.insertAtCursor(this.ihtml);
43867 }, this.specialElements[i])
43879 for(var i =0; i< this.btns.length;i++) {
43880 var b = Roo.factory(this.btns[i],Roo.form);
43881 b.cls = 'x-edit-none';
43883 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43884 b.cls += ' x-init-enable';
43887 b.scope = editorcore;
43895 // disable everything...
43897 this.tb.items.each(function(item){
43900 item.id != editorcore.frameId+ '-sourceedit' &&
43901 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43907 this.rendered = true;
43909 // the all the btns;
43910 editor.on('editorevent', this.updateToolbar, this);
43911 // other toolbars need to implement this..
43912 //editor.on('editmodechange', this.updateToolbar, this);
43916 relayBtnCmd : function(btn) {
43917 this.editorcore.relayCmd(btn.cmd);
43919 // private used internally
43920 createLink : function(){
43921 Roo.log("create link?");
43922 var url = prompt(this.createLinkText, this.defaultLinkValue);
43923 if(url && url != 'http:/'+'/'){
43924 this.editorcore.relayCmd('createlink', url);
43930 * Protected method that will not generally be called directly. It triggers
43931 * a toolbar update by reading the markup state of the current selection in the editor.
43933 updateToolbar: function(){
43935 if(!this.editorcore.activated){
43936 this.editor.onFirstFocus();
43940 var btns = this.tb.items.map,
43941 doc = this.editorcore.doc,
43942 frameId = this.editorcore.frameId;
43944 if(!this.disable.font && !Roo.isSafari){
43946 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43947 if(name != this.fontSelect.dom.value){
43948 this.fontSelect.dom.value = name;
43952 if(!this.disable.format){
43953 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43954 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43955 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43956 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
43958 if(!this.disable.alignments){
43959 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43960 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43961 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43963 if(!Roo.isSafari && !this.disable.lists){
43964 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43965 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43968 var ans = this.editorcore.getAllAncestors();
43969 if (this.formatCombo) {
43972 var store = this.formatCombo.store;
43973 this.formatCombo.setValue("");
43974 for (var i =0; i < ans.length;i++) {
43975 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43977 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43985 // hides menus... - so this cant be on a menu...
43986 Roo.menu.MenuMgr.hideAll();
43988 //this.editorsyncValue();
43992 createFontOptions : function(){
43993 var buf = [], fs = this.fontFamilies, ff, lc;
43997 for(var i = 0, len = fs.length; i< len; i++){
43999 lc = ff.toLowerCase();
44001 '<option value="',lc,'" style="font-family:',ff,';"',
44002 (this.defaultFont == lc ? ' selected="true">' : '>'),
44007 return buf.join('');
44010 toggleSourceEdit : function(sourceEditMode){
44012 Roo.log("toolbar toogle");
44013 if(sourceEditMode === undefined){
44014 sourceEditMode = !this.sourceEditMode;
44016 this.sourceEditMode = sourceEditMode === true;
44017 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44018 // just toggle the button?
44019 if(btn.pressed !== this.sourceEditMode){
44020 btn.toggle(this.sourceEditMode);
44024 if(sourceEditMode){
44025 Roo.log("disabling buttons");
44026 this.tb.items.each(function(item){
44027 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44033 Roo.log("enabling buttons");
44034 if(this.editorcore.initialized){
44035 this.tb.items.each(function(item){
44041 Roo.log("calling toggole on editor");
44042 // tell the editor that it's been pressed..
44043 this.editor.toggleSourceEdit(sourceEditMode);
44047 * Object collection of toolbar tooltips for the buttons in the editor. The key
44048 * is the command id associated with that button and the value is a valid QuickTips object.
44053 title: 'Bold (Ctrl+B)',
44054 text: 'Make the selected text bold.',
44055 cls: 'x-html-editor-tip'
44058 title: 'Italic (Ctrl+I)',
44059 text: 'Make the selected text italic.',
44060 cls: 'x-html-editor-tip'
44068 title: 'Bold (Ctrl+B)',
44069 text: 'Make the selected text bold.',
44070 cls: 'x-html-editor-tip'
44073 title: 'Italic (Ctrl+I)',
44074 text: 'Make the selected text italic.',
44075 cls: 'x-html-editor-tip'
44078 title: 'Underline (Ctrl+U)',
44079 text: 'Underline the selected text.',
44080 cls: 'x-html-editor-tip'
44083 title: 'Strikethrough',
44084 text: 'Strikethrough the selected text.',
44085 cls: 'x-html-editor-tip'
44087 increasefontsize : {
44088 title: 'Grow Text',
44089 text: 'Increase the font size.',
44090 cls: 'x-html-editor-tip'
44092 decreasefontsize : {
44093 title: 'Shrink Text',
44094 text: 'Decrease the font size.',
44095 cls: 'x-html-editor-tip'
44098 title: 'Text Highlight Color',
44099 text: 'Change the background color of the selected text.',
44100 cls: 'x-html-editor-tip'
44103 title: 'Font Color',
44104 text: 'Change the color of the selected text.',
44105 cls: 'x-html-editor-tip'
44108 title: 'Align Text Left',
44109 text: 'Align text to the left.',
44110 cls: 'x-html-editor-tip'
44113 title: 'Center Text',
44114 text: 'Center text in the editor.',
44115 cls: 'x-html-editor-tip'
44118 title: 'Align Text Right',
44119 text: 'Align text to the right.',
44120 cls: 'x-html-editor-tip'
44122 insertunorderedlist : {
44123 title: 'Bullet List',
44124 text: 'Start a bulleted list.',
44125 cls: 'x-html-editor-tip'
44127 insertorderedlist : {
44128 title: 'Numbered List',
44129 text: 'Start a numbered list.',
44130 cls: 'x-html-editor-tip'
44133 title: 'Hyperlink',
44134 text: 'Make the selected text a hyperlink.',
44135 cls: 'x-html-editor-tip'
44138 title: 'Source Edit',
44139 text: 'Switch to source editing mode.',
44140 cls: 'x-html-editor-tip'
44144 onDestroy : function(){
44147 this.tb.items.each(function(item){
44149 item.menu.removeAll();
44151 item.menu.el.destroy();
44159 onFirstFocus: function() {
44160 this.tb.items.each(function(item){
44169 // <script type="text/javascript">
44172 * Ext JS Library 1.1.1
44173 * Copyright(c) 2006-2007, Ext JS, LLC.
44180 * @class Roo.form.HtmlEditor.ToolbarContext
44185 new Roo.form.HtmlEditor({
44188 { xtype: 'ToolbarStandard', styles : {} }
44189 { xtype: 'ToolbarContext', disable : {} }
44195 * @config : {Object} disable List of elements to disable.. (not done yet.)
44196 * @config : {Object} styles Map of styles available.
44200 Roo.form.HtmlEditor.ToolbarContext = function(config)
44203 Roo.apply(this, config);
44204 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44205 // dont call parent... till later.
44206 this.styles = this.styles || {};
44211 Roo.form.HtmlEditor.ToolbarContext.types = {
44223 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44289 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44294 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44304 style : 'fontFamily',
44305 displayField: 'display',
44306 optname : 'font-family',
44355 // should we really allow this??
44356 // should this just be
44367 style : 'fontFamily',
44368 displayField: 'display',
44369 optname : 'font-family',
44376 style : 'fontFamily',
44377 displayField: 'display',
44378 optname : 'font-family',
44385 style : 'fontFamily',
44386 displayField: 'display',
44387 optname : 'font-family',
44398 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44399 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44401 Roo.form.HtmlEditor.ToolbarContext.options = {
44403 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44404 [ 'Courier New', 'Courier New'],
44405 [ 'Tahoma', 'Tahoma'],
44406 [ 'Times New Roman,serif', 'Times'],
44407 [ 'Verdana','Verdana' ]
44411 // fixme - these need to be configurable..
44414 //Roo.form.HtmlEditor.ToolbarContext.types
44417 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44424 editorcore : false,
44426 * @cfg {Object} disable List of toolbar elements to disable
44431 * @cfg {Object} styles List of styles
44432 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44434 * These must be defined in the page, so they get rendered correctly..
44445 init : function(editor)
44447 this.editor = editor;
44448 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44449 var editorcore = this.editorcore;
44451 var fid = editorcore.frameId;
44453 function btn(id, toggle, handler){
44454 var xid = fid + '-'+ id ;
44458 cls : 'x-btn-icon x-edit-'+id,
44459 enableToggle:toggle !== false,
44460 scope: editorcore, // was editor...
44461 handler:handler||editorcore.relayBtnCmd,
44462 clickEvent:'mousedown',
44463 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44467 // create a new element.
44468 var wdiv = editor.wrap.createChild({
44470 }, editor.wrap.dom.firstChild.nextSibling, true);
44472 // can we do this more than once??
44474 // stop form submits
44477 // disable everything...
44478 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44479 this.toolbars = {};
44481 for (var i in ty) {
44483 this.toolbars[i] = this.buildToolbar(ty[i],i);
44485 this.tb = this.toolbars.BODY;
44487 this.buildFooter();
44488 this.footer.show();
44489 editor.on('hide', function( ) { this.footer.hide() }, this);
44490 editor.on('show', function( ) { this.footer.show() }, this);
44493 this.rendered = true;
44495 // the all the btns;
44496 editor.on('editorevent', this.updateToolbar, this);
44497 // other toolbars need to implement this..
44498 //editor.on('editmodechange', this.updateToolbar, this);
44504 * Protected method that will not generally be called directly. It triggers
44505 * a toolbar update by reading the markup state of the current selection in the editor.
44507 * Note you can force an update by calling on('editorevent', scope, false)
44509 updateToolbar: function(editor,ev,sel){
44512 // capture mouse up - this is handy for selecting images..
44513 // perhaps should go somewhere else...
44514 if(!this.editorcore.activated){
44515 this.editor.onFirstFocus();
44521 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44522 // selectNode - might want to handle IE?
44524 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44525 ev.target && ev.target.tagName == 'IMG') {
44526 // they have click on an image...
44527 // let's see if we can change the selection...
44530 var nodeRange = sel.ownerDocument.createRange();
44532 nodeRange.selectNode(sel);
44534 nodeRange.selectNodeContents(sel);
44536 //nodeRange.collapse(true);
44537 var s = this.editorcore.win.getSelection();
44538 s.removeAllRanges();
44539 s.addRange(nodeRange);
44543 var updateFooter = sel ? false : true;
44546 var ans = this.editorcore.getAllAncestors();
44549 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44552 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44553 sel = sel ? sel : this.editorcore.doc.body;
44554 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44557 // pick a menu that exists..
44558 var tn = sel.tagName.toUpperCase();
44559 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44561 tn = sel.tagName.toUpperCase();
44563 var lastSel = this.tb.selectedNode;
44565 this.tb.selectedNode = sel;
44567 // if current menu does not match..
44569 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44572 ///console.log("show: " + tn);
44573 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44576 this.tb.items.first().el.innerHTML = tn + ': ';
44579 // update attributes
44580 if (this.tb.fields) {
44581 this.tb.fields.each(function(e) {
44583 e.setValue(sel.style[e.stylename]);
44586 e.setValue(sel.getAttribute(e.attrname));
44590 var hasStyles = false;
44591 for(var i in this.styles) {
44598 var st = this.tb.fields.item(0);
44600 st.store.removeAll();
44603 var cn = sel.className.split(/\s+/);
44606 if (this.styles['*']) {
44608 Roo.each(this.styles['*'], function(v) {
44609 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44612 if (this.styles[tn]) {
44613 Roo.each(this.styles[tn], function(v) {
44614 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44618 st.store.loadData(avs);
44622 // flag our selected Node.
44623 this.tb.selectedNode = sel;
44626 Roo.menu.MenuMgr.hideAll();
44630 if (!updateFooter) {
44631 //this.footDisp.dom.innerHTML = '';
44634 // update the footer
44638 this.footerEls = ans.reverse();
44639 Roo.each(this.footerEls, function(a,i) {
44640 if (!a) { return; }
44641 html += html.length ? ' > ' : '';
44643 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44648 var sz = this.footDisp.up('td').getSize();
44649 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44650 this.footDisp.dom.style.marginLeft = '5px';
44652 this.footDisp.dom.style.overflow = 'hidden';
44654 this.footDisp.dom.innerHTML = html;
44656 //this.editorsyncValue();
44663 onDestroy : function(){
44666 this.tb.items.each(function(item){
44668 item.menu.removeAll();
44670 item.menu.el.destroy();
44678 onFirstFocus: function() {
44679 // need to do this for all the toolbars..
44680 this.tb.items.each(function(item){
44684 buildToolbar: function(tlist, nm)
44686 var editor = this.editor;
44687 var editorcore = this.editorcore;
44688 // create a new element.
44689 var wdiv = editor.wrap.createChild({
44691 }, editor.wrap.dom.firstChild.nextSibling, true);
44694 var tb = new Roo.Toolbar(wdiv);
44697 tb.add(nm+ ": ");
44700 for(var i in this.styles) {
44705 if (styles && styles.length) {
44707 // this needs a multi-select checkbox...
44708 tb.addField( new Roo.form.ComboBox({
44709 store: new Roo.data.SimpleStore({
44711 fields: ['val', 'selected'],
44714 name : '-roo-edit-className',
44715 attrname : 'className',
44716 displayField: 'val',
44720 triggerAction: 'all',
44721 emptyText:'Select Style',
44722 selectOnFocus:true,
44725 'select': function(c, r, i) {
44726 // initial support only for on class per el..
44727 tb.selectedNode.className = r ? r.get('val') : '';
44728 editorcore.syncValue();
44735 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44736 var tbops = tbc.options;
44738 for (var i in tlist) {
44740 var item = tlist[i];
44741 tb.add(item.title + ": ");
44744 //optname == used so you can configure the options available..
44745 var opts = item.opts ? item.opts : false;
44746 if (item.optname) {
44747 opts = tbops[item.optname];
44752 // opts == pulldown..
44753 tb.addField( new Roo.form.ComboBox({
44754 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44756 fields: ['val', 'display'],
44759 name : '-roo-edit-' + i,
44761 stylename : item.style ? item.style : false,
44762 displayField: item.displayField ? item.displayField : 'val',
44763 valueField : 'val',
44765 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44767 triggerAction: 'all',
44768 emptyText:'Select',
44769 selectOnFocus:true,
44770 width: item.width ? item.width : 130,
44772 'select': function(c, r, i) {
44774 tb.selectedNode.style[c.stylename] = r.get('val');
44777 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44786 tb.addField( new Roo.form.TextField({
44789 //allowBlank:false,
44794 tb.addField( new Roo.form.TextField({
44795 name: '-roo-edit-' + i,
44802 'change' : function(f, nv, ov) {
44803 tb.selectedNode.setAttribute(f.attrname, nv);
44816 text: 'Stylesheets',
44819 click : function ()
44821 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44829 text: 'Remove Tag',
44832 click : function ()
44835 // undo does not work.
44837 var sn = tb.selectedNode;
44839 var pn = sn.parentNode;
44841 var stn = sn.childNodes[0];
44842 var en = sn.childNodes[sn.childNodes.length - 1 ];
44843 while (sn.childNodes.length) {
44844 var node = sn.childNodes[0];
44845 sn.removeChild(node);
44847 pn.insertBefore(node, sn);
44850 pn.removeChild(sn);
44851 var range = editorcore.createRange();
44853 range.setStart(stn,0);
44854 range.setEnd(en,0); //????
44855 //range.selectNode(sel);
44858 var selection = editorcore.getSelection();
44859 selection.removeAllRanges();
44860 selection.addRange(range);
44864 //_this.updateToolbar(null, null, pn);
44865 _this.updateToolbar(null, null, null);
44866 _this.footDisp.dom.innerHTML = '';
44876 tb.el.on('click', function(e){
44877 e.preventDefault(); // what does this do?
44879 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44882 // dont need to disable them... as they will get hidden
44887 buildFooter : function()
44890 var fel = this.editor.wrap.createChild();
44891 this.footer = new Roo.Toolbar(fel);
44892 // toolbar has scrolly on left / right?
44893 var footDisp= new Roo.Toolbar.Fill();
44899 handler : function() {
44900 _t.footDisp.scrollTo('left',0,true)
44904 this.footer.add( footDisp );
44909 handler : function() {
44911 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44915 var fel = Roo.get(footDisp.el);
44916 fel.addClass('x-editor-context');
44917 this.footDispWrap = fel;
44918 this.footDispWrap.overflow = 'hidden';
44920 this.footDisp = fel.createChild();
44921 this.footDispWrap.on('click', this.onContextClick, this)
44925 onContextClick : function (ev,dom)
44927 ev.preventDefault();
44928 var cn = dom.className;
44930 if (!cn.match(/x-ed-loc-/)) {
44933 var n = cn.split('-').pop();
44934 var ans = this.footerEls;
44938 var range = this.editorcore.createRange();
44940 range.selectNodeContents(sel);
44941 //range.selectNode(sel);
44944 var selection = this.editorcore.getSelection();
44945 selection.removeAllRanges();
44946 selection.addRange(range);
44950 this.updateToolbar(null, null, sel);
44967 * Ext JS Library 1.1.1
44968 * Copyright(c) 2006-2007, Ext JS, LLC.
44970 * Originally Released Under LGPL - original licence link has changed is not relivant.
44973 * <script type="text/javascript">
44977 * @class Roo.form.BasicForm
44978 * @extends Roo.util.Observable
44979 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44981 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44982 * @param {Object} config Configuration options
44984 Roo.form.BasicForm = function(el, config){
44985 this.allItems = [];
44986 this.childForms = [];
44987 Roo.apply(this, config);
44989 * The Roo.form.Field items in this form.
44990 * @type MixedCollection
44994 this.items = new Roo.util.MixedCollection(false, function(o){
44995 return o.id || (o.id = Roo.id());
44999 * @event beforeaction
45000 * Fires before any action is performed. Return false to cancel the action.
45001 * @param {Form} this
45002 * @param {Action} action The action to be performed
45004 beforeaction: true,
45006 * @event actionfailed
45007 * Fires when an action fails.
45008 * @param {Form} this
45009 * @param {Action} action The action that failed
45011 actionfailed : true,
45013 * @event actioncomplete
45014 * Fires when an action is completed.
45015 * @param {Form} this
45016 * @param {Action} action The action that completed
45018 actioncomplete : true
45023 Roo.form.BasicForm.superclass.constructor.call(this);
45026 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45028 * @cfg {String} method
45029 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45032 * @cfg {DataReader} reader
45033 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45034 * This is optional as there is built-in support for processing JSON.
45037 * @cfg {DataReader} errorReader
45038 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45039 * This is completely optional as there is built-in support for processing JSON.
45042 * @cfg {String} url
45043 * The URL to use for form actions if one isn't supplied in the action options.
45046 * @cfg {Boolean} fileUpload
45047 * Set to true if this form is a file upload.
45051 * @cfg {Object} baseParams
45052 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45057 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45062 activeAction : null,
45065 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45066 * or setValues() data instead of when the form was first created.
45068 trackResetOnLoad : false,
45072 * childForms - used for multi-tab forms
45075 childForms : false,
45078 * allItems - full list of fields.
45084 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45085 * element by passing it or its id or mask the form itself by passing in true.
45088 waitMsgTarget : false,
45091 initEl : function(el){
45092 this.el = Roo.get(el);
45093 this.id = this.el.id || Roo.id();
45094 this.el.on('submit', this.onSubmit, this);
45095 this.el.addClass('x-form');
45099 onSubmit : function(e){
45104 * Returns true if client-side validation on the form is successful.
45107 isValid : function(){
45109 this.items.each(function(f){
45118 * Returns true if any fields in this form have changed since their original load.
45121 isDirty : function(){
45123 this.items.each(function(f){
45133 * Performs a predefined action (submit or load) or custom actions you define on this form.
45134 * @param {String} actionName The name of the action type
45135 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45136 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45137 * accept other config options):
45139 Property Type Description
45140 ---------------- --------------- ----------------------------------------------------------------------------------
45141 url String The url for the action (defaults to the form's url)
45142 method String The form method to use (defaults to the form's method, or POST if not defined)
45143 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45144 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45145 validate the form on the client (defaults to false)
45147 * @return {BasicForm} this
45149 doAction : function(action, options){
45150 if(typeof action == 'string'){
45151 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45153 if(this.fireEvent('beforeaction', this, action) !== false){
45154 this.beforeAction(action);
45155 action.run.defer(100, action);
45161 * Shortcut to do a submit action.
45162 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45163 * @return {BasicForm} this
45165 submit : function(options){
45166 this.doAction('submit', options);
45171 * Shortcut to do a load action.
45172 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45173 * @return {BasicForm} this
45175 load : function(options){
45176 this.doAction('load', options);
45181 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45182 * @param {Record} record The record to edit
45183 * @return {BasicForm} this
45185 updateRecord : function(record){
45186 record.beginEdit();
45187 var fs = record.fields;
45188 fs.each(function(f){
45189 var field = this.findField(f.name);
45191 record.set(f.name, field.getValue());
45199 * Loads an Roo.data.Record into this form.
45200 * @param {Record} record The record to load
45201 * @return {BasicForm} this
45203 loadRecord : function(record){
45204 this.setValues(record.data);
45209 beforeAction : function(action){
45210 var o = action.options;
45213 if(this.waitMsgTarget === true){
45214 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45215 }else if(this.waitMsgTarget){
45216 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45217 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45219 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45225 afterAction : function(action, success){
45226 this.activeAction = null;
45227 var o = action.options;
45229 if(this.waitMsgTarget === true){
45231 }else if(this.waitMsgTarget){
45232 this.waitMsgTarget.unmask();
45234 Roo.MessageBox.updateProgress(1);
45235 Roo.MessageBox.hide();
45242 Roo.callback(o.success, o.scope, [this, action]);
45243 this.fireEvent('actioncomplete', this, action);
45247 // failure condition..
45248 // we have a scenario where updates need confirming.
45249 // eg. if a locking scenario exists..
45250 // we look for { errors : { needs_confirm : true }} in the response.
45252 (typeof(action.result) != 'undefined') &&
45253 (typeof(action.result.errors) != 'undefined') &&
45254 (typeof(action.result.errors.needs_confirm) != 'undefined')
45257 Roo.MessageBox.confirm(
45258 "Change requires confirmation",
45259 action.result.errorMsg,
45264 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45274 Roo.callback(o.failure, o.scope, [this, action]);
45275 // show an error message if no failed handler is set..
45276 if (!this.hasListener('actionfailed')) {
45277 Roo.MessageBox.alert("Error",
45278 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45279 action.result.errorMsg :
45280 "Saving Failed, please check your entries or try again"
45284 this.fireEvent('actionfailed', this, action);
45290 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45291 * @param {String} id The value to search for
45294 findField : function(id){
45295 var field = this.items.get(id);
45297 this.items.each(function(f){
45298 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45304 return field || null;
45308 * Add a secondary form to this one,
45309 * Used to provide tabbed forms. One form is primary, with hidden values
45310 * which mirror the elements from the other forms.
45312 * @param {Roo.form.Form} form to add.
45315 addForm : function(form)
45318 if (this.childForms.indexOf(form) > -1) {
45322 this.childForms.push(form);
45324 Roo.each(form.allItems, function (fe) {
45326 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45327 if (this.findField(n)) { // already added..
45330 var add = new Roo.form.Hidden({
45333 add.render(this.el);
45340 * Mark fields in this form invalid in bulk.
45341 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45342 * @return {BasicForm} this
45344 markInvalid : function(errors){
45345 if(errors instanceof Array){
45346 for(var i = 0, len = errors.length; i < len; i++){
45347 var fieldError = errors[i];
45348 var f = this.findField(fieldError.id);
45350 f.markInvalid(fieldError.msg);
45356 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45357 field.markInvalid(errors[id]);
45361 Roo.each(this.childForms || [], function (f) {
45362 f.markInvalid(errors);
45369 * Set values for fields in this form in bulk.
45370 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45371 * @return {BasicForm} this
45373 setValues : function(values){
45374 if(values instanceof Array){ // array of objects
45375 for(var i = 0, len = values.length; i < len; i++){
45377 var f = this.findField(v.id);
45379 f.setValue(v.value);
45380 if(this.trackResetOnLoad){
45381 f.originalValue = f.getValue();
45385 }else{ // object hash
45388 if(typeof values[id] != 'function' && (field = this.findField(id))){
45390 if (field.setFromData &&
45391 field.valueField &&
45392 field.displayField &&
45393 // combos' with local stores can
45394 // be queried via setValue()
45395 // to set their value..
45396 (field.store && !field.store.isLocal)
45400 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45401 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45402 field.setFromData(sd);
45405 field.setValue(values[id]);
45409 if(this.trackResetOnLoad){
45410 field.originalValue = field.getValue();
45416 Roo.each(this.childForms || [], function (f) {
45417 f.setValues(values);
45424 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45425 * they are returned as an array.
45426 * @param {Boolean} asString
45429 getValues : function(asString){
45430 if (this.childForms) {
45431 // copy values from the child forms
45432 Roo.each(this.childForms, function (f) {
45433 this.setValues(f.getValues());
45439 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45440 if(asString === true){
45443 return Roo.urlDecode(fs);
45447 * Returns the fields in this form as an object with key/value pairs.
45448 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45451 getFieldValues : function(with_hidden)
45453 if (this.childForms) {
45454 // copy values from the child forms
45455 // should this call getFieldValues - probably not as we do not currently copy
45456 // hidden fields when we generate..
45457 Roo.each(this.childForms, function (f) {
45458 this.setValues(f.getValues());
45463 this.items.each(function(f){
45464 if (!f.getName()) {
45467 var v = f.getValue();
45468 if (f.inputType =='radio') {
45469 if (typeof(ret[f.getName()]) == 'undefined') {
45470 ret[f.getName()] = ''; // empty..
45473 if (!f.el.dom.checked) {
45477 v = f.el.dom.value;
45481 // not sure if this supported any more..
45482 if ((typeof(v) == 'object') && f.getRawValue) {
45483 v = f.getRawValue() ; // dates..
45485 // combo boxes where name != hiddenName...
45486 if (f.name != f.getName()) {
45487 ret[f.name] = f.getRawValue();
45489 ret[f.getName()] = v;
45496 * Clears all invalid messages in this form.
45497 * @return {BasicForm} this
45499 clearInvalid : function(){
45500 this.items.each(function(f){
45504 Roo.each(this.childForms || [], function (f) {
45513 * Resets this form.
45514 * @return {BasicForm} this
45516 reset : function(){
45517 this.items.each(function(f){
45521 Roo.each(this.childForms || [], function (f) {
45530 * Add Roo.form components to this form.
45531 * @param {Field} field1
45532 * @param {Field} field2 (optional)
45533 * @param {Field} etc (optional)
45534 * @return {BasicForm} this
45537 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45543 * Removes a field from the items collection (does NOT remove its markup).
45544 * @param {Field} field
45545 * @return {BasicForm} this
45547 remove : function(field){
45548 this.items.remove(field);
45553 * Looks at the fields in this form, checks them for an id attribute,
45554 * and calls applyTo on the existing dom element with that id.
45555 * @return {BasicForm} this
45557 render : function(){
45558 this.items.each(function(f){
45559 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45567 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45568 * @param {Object} values
45569 * @return {BasicForm} this
45571 applyToFields : function(o){
45572 this.items.each(function(f){
45579 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45580 * @param {Object} values
45581 * @return {BasicForm} this
45583 applyIfToFields : function(o){
45584 this.items.each(function(f){
45592 Roo.BasicForm = Roo.form.BasicForm;/*
45594 * Ext JS Library 1.1.1
45595 * Copyright(c) 2006-2007, Ext JS, LLC.
45597 * Originally Released Under LGPL - original licence link has changed is not relivant.
45600 * <script type="text/javascript">
45604 * @class Roo.form.Form
45605 * @extends Roo.form.BasicForm
45606 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45608 * @param {Object} config Configuration options
45610 Roo.form.Form = function(config){
45612 if (config.items) {
45613 xitems = config.items;
45614 delete config.items;
45618 Roo.form.Form.superclass.constructor.call(this, null, config);
45619 this.url = this.url || this.action;
45621 this.root = new Roo.form.Layout(Roo.applyIf({
45625 this.active = this.root;
45627 * Array of all the buttons that have been added to this form via {@link addButton}
45631 this.allItems = [];
45634 * @event clientvalidation
45635 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45636 * @param {Form} this
45637 * @param {Boolean} valid true if the form has passed client-side validation
45639 clientvalidation: true,
45642 * Fires when the form is rendered
45643 * @param {Roo.form.Form} form
45648 if (this.progressUrl) {
45649 // push a hidden field onto the list of fields..
45653 name : 'UPLOAD_IDENTIFIER'
45658 Roo.each(xitems, this.addxtype, this);
45664 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45666 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45669 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45672 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45674 buttonAlign:'center',
45677 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45682 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45683 * This property cascades to child containers if not set.
45688 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45689 * fires a looping event with that state. This is required to bind buttons to the valid
45690 * state using the config value formBind:true on the button.
45692 monitorValid : false,
45695 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45700 * @cfg {String} progressUrl - Url to return progress data
45703 progressUrl : false,
45706 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45707 * fields are added and the column is closed. If no fields are passed the column remains open
45708 * until end() is called.
45709 * @param {Object} config The config to pass to the column
45710 * @param {Field} field1 (optional)
45711 * @param {Field} field2 (optional)
45712 * @param {Field} etc (optional)
45713 * @return Column The column container object
45715 column : function(c){
45716 var col = new Roo.form.Column(c);
45718 if(arguments.length > 1){ // duplicate code required because of Opera
45719 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45726 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45727 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45728 * until end() is called.
45729 * @param {Object} config The config to pass to the fieldset
45730 * @param {Field} field1 (optional)
45731 * @param {Field} field2 (optional)
45732 * @param {Field} etc (optional)
45733 * @return FieldSet The fieldset container object
45735 fieldset : function(c){
45736 var fs = new Roo.form.FieldSet(c);
45738 if(arguments.length > 1){ // duplicate code required because of Opera
45739 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45746 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45747 * fields are added and the container is closed. If no fields are passed the container remains open
45748 * until end() is called.
45749 * @param {Object} config The config to pass to the Layout
45750 * @param {Field} field1 (optional)
45751 * @param {Field} field2 (optional)
45752 * @param {Field} etc (optional)
45753 * @return Layout The container object
45755 container : function(c){
45756 var l = new Roo.form.Layout(c);
45758 if(arguments.length > 1){ // duplicate code required because of Opera
45759 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45766 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45767 * @param {Object} container A Roo.form.Layout or subclass of Layout
45768 * @return {Form} this
45770 start : function(c){
45771 // cascade label info
45772 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45773 this.active.stack.push(c);
45774 c.ownerCt = this.active;
45780 * Closes the current open container
45781 * @return {Form} this
45784 if(this.active == this.root){
45787 this.active = this.active.ownerCt;
45792 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45793 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45794 * as the label of the field.
45795 * @param {Field} field1
45796 * @param {Field} field2 (optional)
45797 * @param {Field} etc. (optional)
45798 * @return {Form} this
45801 this.active.stack.push.apply(this.active.stack, arguments);
45802 this.allItems.push.apply(this.allItems,arguments);
45804 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45805 if(a[i].isFormField){
45810 Roo.form.Form.superclass.add.apply(this, r);
45820 * Find any element that has been added to a form, using it's ID or name
45821 * This can include framesets, columns etc. along with regular fields..
45822 * @param {String} id - id or name to find.
45824 * @return {Element} e - or false if nothing found.
45826 findbyId : function(id)
45832 Roo.each(this.allItems, function(f){
45833 if (f.id == id || f.name == id ){
45844 * Render this form into the passed container. This should only be called once!
45845 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45846 * @return {Form} this
45848 render : function(ct)
45854 var o = this.autoCreate || {
45856 method : this.method || 'POST',
45857 id : this.id || Roo.id()
45859 this.initEl(ct.createChild(o));
45861 this.root.render(this.el);
45865 this.items.each(function(f){
45866 f.render('x-form-el-'+f.id);
45869 if(this.buttons.length > 0){
45870 // tables are required to maintain order and for correct IE layout
45871 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45872 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45873 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45875 var tr = tb.getElementsByTagName('tr')[0];
45876 for(var i = 0, len = this.buttons.length; i < len; i++) {
45877 var b = this.buttons[i];
45878 var td = document.createElement('td');
45879 td.className = 'x-form-btn-td';
45880 b.render(tr.appendChild(td));
45883 if(this.monitorValid){ // initialize after render
45884 this.startMonitoring();
45886 this.fireEvent('rendered', this);
45891 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45892 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45893 * object or a valid Roo.DomHelper element config
45894 * @param {Function} handler The function called when the button is clicked
45895 * @param {Object} scope (optional) The scope of the handler function
45896 * @return {Roo.Button}
45898 addButton : function(config, handler, scope){
45902 minWidth: this.minButtonWidth,
45905 if(typeof config == "string"){
45908 Roo.apply(bc, config);
45910 var btn = new Roo.Button(null, bc);
45911 this.buttons.push(btn);
45916 * Adds a series of form elements (using the xtype property as the factory method.
45917 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45918 * @param {Object} config
45921 addxtype : function()
45923 var ar = Array.prototype.slice.call(arguments, 0);
45925 for(var i = 0; i < ar.length; i++) {
45927 continue; // skip -- if this happends something invalid got sent, we
45928 // should ignore it, as basically that interface element will not show up
45929 // and that should be pretty obvious!!
45932 if (Roo.form[ar[i].xtype]) {
45934 var fe = Roo.factory(ar[i], Roo.form);
45940 fe.store.form = this;
45945 this.allItems.push(fe);
45946 if (fe.items && fe.addxtype) {
45947 fe.addxtype.apply(fe, fe.items);
45957 // console.log('adding ' + ar[i].xtype);
45959 if (ar[i].xtype == 'Button') {
45960 //console.log('adding button');
45961 //console.log(ar[i]);
45962 this.addButton(ar[i]);
45963 this.allItems.push(fe);
45967 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45968 alert('end is not supported on xtype any more, use items');
45970 // //console.log('adding end');
45978 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45979 * option "monitorValid"
45981 startMonitoring : function(){
45984 Roo.TaskMgr.start({
45985 run : this.bindHandler,
45986 interval : this.monitorPoll || 200,
45993 * Stops monitoring of the valid state of this form
45995 stopMonitoring : function(){
45996 this.bound = false;
46000 bindHandler : function(){
46002 return false; // stops binding
46005 this.items.each(function(f){
46006 if(!f.isValid(true)){
46011 for(var i = 0, len = this.buttons.length; i < len; i++){
46012 var btn = this.buttons[i];
46013 if(btn.formBind === true && btn.disabled === valid){
46014 btn.setDisabled(!valid);
46017 this.fireEvent('clientvalidation', this, valid);
46031 Roo.Form = Roo.form.Form;
46034 * Ext JS Library 1.1.1
46035 * Copyright(c) 2006-2007, Ext JS, LLC.
46037 * Originally Released Under LGPL - original licence link has changed is not relivant.
46040 * <script type="text/javascript">
46043 // as we use this in bootstrap.
46044 Roo.namespace('Roo.form');
46046 * @class Roo.form.Action
46047 * Internal Class used to handle form actions
46049 * @param {Roo.form.BasicForm} el The form element or its id
46050 * @param {Object} config Configuration options
46055 // define the action interface
46056 Roo.form.Action = function(form, options){
46058 this.options = options || {};
46061 * Client Validation Failed
46064 Roo.form.Action.CLIENT_INVALID = 'client';
46066 * Server Validation Failed
46069 Roo.form.Action.SERVER_INVALID = 'server';
46071 * Connect to Server Failed
46074 Roo.form.Action.CONNECT_FAILURE = 'connect';
46076 * Reading Data from Server Failed
46079 Roo.form.Action.LOAD_FAILURE = 'load';
46081 Roo.form.Action.prototype = {
46083 failureType : undefined,
46084 response : undefined,
46085 result : undefined,
46087 // interface method
46088 run : function(options){
46092 // interface method
46093 success : function(response){
46097 // interface method
46098 handleResponse : function(response){
46102 // default connection failure
46103 failure : function(response){
46105 this.response = response;
46106 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46107 this.form.afterAction(this, false);
46110 processResponse : function(response){
46111 this.response = response;
46112 if(!response.responseText){
46115 this.result = this.handleResponse(response);
46116 return this.result;
46119 // utility functions used internally
46120 getUrl : function(appendParams){
46121 var url = this.options.url || this.form.url || this.form.el.dom.action;
46123 var p = this.getParams();
46125 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46131 getMethod : function(){
46132 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46135 getParams : function(){
46136 var bp = this.form.baseParams;
46137 var p = this.options.params;
46139 if(typeof p == "object"){
46140 p = Roo.urlEncode(Roo.applyIf(p, bp));
46141 }else if(typeof p == 'string' && bp){
46142 p += '&' + Roo.urlEncode(bp);
46145 p = Roo.urlEncode(bp);
46150 createCallback : function(){
46152 success: this.success,
46153 failure: this.failure,
46155 timeout: (this.form.timeout*1000),
46156 upload: this.form.fileUpload ? this.success : undefined
46161 Roo.form.Action.Submit = function(form, options){
46162 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46165 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46168 haveProgress : false,
46169 uploadComplete : false,
46171 // uploadProgress indicator.
46172 uploadProgress : function()
46174 if (!this.form.progressUrl) {
46178 if (!this.haveProgress) {
46179 Roo.MessageBox.progress("Uploading", "Uploading");
46181 if (this.uploadComplete) {
46182 Roo.MessageBox.hide();
46186 this.haveProgress = true;
46188 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46190 var c = new Roo.data.Connection();
46192 url : this.form.progressUrl,
46197 success : function(req){
46198 //console.log(data);
46202 rdata = Roo.decode(req.responseText)
46204 Roo.log("Invalid data from server..");
46208 if (!rdata || !rdata.success) {
46210 Roo.MessageBox.alert(Roo.encode(rdata));
46213 var data = rdata.data;
46215 if (this.uploadComplete) {
46216 Roo.MessageBox.hide();
46221 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46222 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46225 this.uploadProgress.defer(2000,this);
46228 failure: function(data) {
46229 Roo.log('progress url failed ');
46240 // run get Values on the form, so it syncs any secondary forms.
46241 this.form.getValues();
46243 var o = this.options;
46244 var method = this.getMethod();
46245 var isPost = method == 'POST';
46246 if(o.clientValidation === false || this.form.isValid()){
46248 if (this.form.progressUrl) {
46249 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46250 (new Date() * 1) + '' + Math.random());
46255 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46256 form:this.form.el.dom,
46257 url:this.getUrl(!isPost),
46259 params:isPost ? this.getParams() : null,
46260 isUpload: this.form.fileUpload
46263 this.uploadProgress();
46265 }else if (o.clientValidation !== false){ // client validation failed
46266 this.failureType = Roo.form.Action.CLIENT_INVALID;
46267 this.form.afterAction(this, false);
46271 success : function(response)
46273 this.uploadComplete= true;
46274 if (this.haveProgress) {
46275 Roo.MessageBox.hide();
46279 var result = this.processResponse(response);
46280 if(result === true || result.success){
46281 this.form.afterAction(this, true);
46285 this.form.markInvalid(result.errors);
46286 this.failureType = Roo.form.Action.SERVER_INVALID;
46288 this.form.afterAction(this, false);
46290 failure : function(response)
46292 this.uploadComplete= true;
46293 if (this.haveProgress) {
46294 Roo.MessageBox.hide();
46297 this.response = response;
46298 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46299 this.form.afterAction(this, false);
46302 handleResponse : function(response){
46303 if(this.form.errorReader){
46304 var rs = this.form.errorReader.read(response);
46307 for(var i = 0, len = rs.records.length; i < len; i++) {
46308 var r = rs.records[i];
46309 errors[i] = r.data;
46312 if(errors.length < 1){
46316 success : rs.success,
46322 ret = Roo.decode(response.responseText);
46326 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46336 Roo.form.Action.Load = function(form, options){
46337 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46338 this.reader = this.form.reader;
46341 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46346 Roo.Ajax.request(Roo.apply(
46347 this.createCallback(), {
46348 method:this.getMethod(),
46349 url:this.getUrl(false),
46350 params:this.getParams()
46354 success : function(response){
46356 var result = this.processResponse(response);
46357 if(result === true || !result.success || !result.data){
46358 this.failureType = Roo.form.Action.LOAD_FAILURE;
46359 this.form.afterAction(this, false);
46362 this.form.clearInvalid();
46363 this.form.setValues(result.data);
46364 this.form.afterAction(this, true);
46367 handleResponse : function(response){
46368 if(this.form.reader){
46369 var rs = this.form.reader.read(response);
46370 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46372 success : rs.success,
46376 return Roo.decode(response.responseText);
46380 Roo.form.Action.ACTION_TYPES = {
46381 'load' : Roo.form.Action.Load,
46382 'submit' : Roo.form.Action.Submit
46385 * Ext JS Library 1.1.1
46386 * Copyright(c) 2006-2007, Ext JS, LLC.
46388 * Originally Released Under LGPL - original licence link has changed is not relivant.
46391 * <script type="text/javascript">
46395 * @class Roo.form.Layout
46396 * @extends Roo.Component
46397 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46399 * @param {Object} config Configuration options
46401 Roo.form.Layout = function(config){
46403 if (config.items) {
46404 xitems = config.items;
46405 delete config.items;
46407 Roo.form.Layout.superclass.constructor.call(this, config);
46409 Roo.each(xitems, this.addxtype, this);
46413 Roo.extend(Roo.form.Layout, Roo.Component, {
46415 * @cfg {String/Object} autoCreate
46416 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46419 * @cfg {String/Object/Function} style
46420 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46421 * a function which returns such a specification.
46424 * @cfg {String} labelAlign
46425 * Valid values are "left," "top" and "right" (defaults to "left")
46428 * @cfg {Number} labelWidth
46429 * Fixed width in pixels of all field labels (defaults to undefined)
46432 * @cfg {Boolean} clear
46433 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46437 * @cfg {String} labelSeparator
46438 * The separator to use after field labels (defaults to ':')
46440 labelSeparator : ':',
46442 * @cfg {Boolean} hideLabels
46443 * True to suppress the display of field labels in this layout (defaults to false)
46445 hideLabels : false,
46448 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46453 onRender : function(ct, position){
46454 if(this.el){ // from markup
46455 this.el = Roo.get(this.el);
46456 }else { // generate
46457 var cfg = this.getAutoCreate();
46458 this.el = ct.createChild(cfg, position);
46461 this.el.applyStyles(this.style);
46463 if(this.labelAlign){
46464 this.el.addClass('x-form-label-'+this.labelAlign);
46466 if(this.hideLabels){
46467 this.labelStyle = "display:none";
46468 this.elementStyle = "padding-left:0;";
46470 if(typeof this.labelWidth == 'number'){
46471 this.labelStyle = "width:"+this.labelWidth+"px;";
46472 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46474 if(this.labelAlign == 'top'){
46475 this.labelStyle = "width:auto;";
46476 this.elementStyle = "padding-left:0;";
46479 var stack = this.stack;
46480 var slen = stack.length;
46482 if(!this.fieldTpl){
46483 var t = new Roo.Template(
46484 '<div class="x-form-item {5}">',
46485 '<label for="{0}" style="{2}">{1}{4}</label>',
46486 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46488 '</div><div class="x-form-clear-left"></div>'
46490 t.disableFormats = true;
46492 Roo.form.Layout.prototype.fieldTpl = t;
46494 for(var i = 0; i < slen; i++) {
46495 if(stack[i].isFormField){
46496 this.renderField(stack[i]);
46498 this.renderComponent(stack[i]);
46503 this.el.createChild({cls:'x-form-clear'});
46508 renderField : function(f){
46509 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46512 f.labelStyle||this.labelStyle||'', //2
46513 this.elementStyle||'', //3
46514 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46515 f.itemCls||this.itemCls||'' //5
46516 ], true).getPrevSibling());
46520 renderComponent : function(c){
46521 c.render(c.isLayout ? this.el : this.el.createChild());
46524 * Adds a object form elements (using the xtype property as the factory method.)
46525 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46526 * @param {Object} config
46528 addxtype : function(o)
46530 // create the lement.
46531 o.form = this.form;
46532 var fe = Roo.factory(o, Roo.form);
46533 this.form.allItems.push(fe);
46534 this.stack.push(fe);
46536 if (fe.isFormField) {
46537 this.form.items.add(fe);
46545 * @class Roo.form.Column
46546 * @extends Roo.form.Layout
46547 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46549 * @param {Object} config Configuration options
46551 Roo.form.Column = function(config){
46552 Roo.form.Column.superclass.constructor.call(this, config);
46555 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46557 * @cfg {Number/String} width
46558 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46561 * @cfg {String/Object} autoCreate
46562 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46566 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46569 onRender : function(ct, position){
46570 Roo.form.Column.superclass.onRender.call(this, ct, position);
46572 this.el.setWidth(this.width);
46579 * @class Roo.form.Row
46580 * @extends Roo.form.Layout
46581 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46583 * @param {Object} config Configuration options
46587 Roo.form.Row = function(config){
46588 Roo.form.Row.superclass.constructor.call(this, config);
46591 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46593 * @cfg {Number/String} width
46594 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46597 * @cfg {Number/String} height
46598 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46600 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46604 onRender : function(ct, position){
46605 //console.log('row render');
46607 var t = new Roo.Template(
46608 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46609 '<label for="{0}" style="{2}">{1}{4}</label>',
46610 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46614 t.disableFormats = true;
46616 Roo.form.Layout.prototype.rowTpl = t;
46618 this.fieldTpl = this.rowTpl;
46620 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46621 var labelWidth = 100;
46623 if ((this.labelAlign != 'top')) {
46624 if (typeof this.labelWidth == 'number') {
46625 labelWidth = this.labelWidth
46627 this.padWidth = 20 + labelWidth;
46631 Roo.form.Column.superclass.onRender.call(this, ct, position);
46633 this.el.setWidth(this.width);
46636 this.el.setHeight(this.height);
46641 renderField : function(f){
46642 f.fieldEl = this.fieldTpl.append(this.el, [
46643 f.id, f.fieldLabel,
46644 f.labelStyle||this.labelStyle||'',
46645 this.elementStyle||'',
46646 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46647 f.itemCls||this.itemCls||'',
46648 f.width ? f.width + this.padWidth : 160 + this.padWidth
46655 * @class Roo.form.FieldSet
46656 * @extends Roo.form.Layout
46657 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46659 * @param {Object} config Configuration options
46661 Roo.form.FieldSet = function(config){
46662 Roo.form.FieldSet.superclass.constructor.call(this, config);
46665 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46667 * @cfg {String} legend
46668 * The text to display as the legend for the FieldSet (defaults to '')
46671 * @cfg {String/Object} autoCreate
46672 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46676 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46679 onRender : function(ct, position){
46680 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46682 this.setLegend(this.legend);
46687 setLegend : function(text){
46689 this.el.child('legend').update(text);
46694 * Ext JS Library 1.1.1
46695 * Copyright(c) 2006-2007, Ext JS, LLC.
46697 * Originally Released Under LGPL - original licence link has changed is not relivant.
46700 * <script type="text/javascript">
46703 * @class Roo.form.VTypes
46704 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46707 Roo.form.VTypes = function(){
46708 // closure these in so they are only created once.
46709 var alpha = /^[a-zA-Z_]+$/;
46710 var alphanum = /^[a-zA-Z0-9_]+$/;
46711 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46712 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46714 // All these messages and functions are configurable
46717 * The function used to validate email addresses
46718 * @param {String} value The email address
46720 'email' : function(v){
46721 return email.test(v);
46724 * The error text to display when the email validation function returns false
46727 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46729 * The keystroke filter mask to be applied on email input
46732 'emailMask' : /[a-z0-9_\.\-@]/i,
46735 * The function used to validate URLs
46736 * @param {String} value The URL
46738 'url' : function(v){
46739 return url.test(v);
46742 * The error text to display when the url validation function returns false
46745 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46748 * The function used to validate alpha values
46749 * @param {String} value The value
46751 'alpha' : function(v){
46752 return alpha.test(v);
46755 * The error text to display when the alpha validation function returns false
46758 'alphaText' : 'This field should only contain letters and _',
46760 * The keystroke filter mask to be applied on alpha input
46763 'alphaMask' : /[a-z_]/i,
46766 * The function used to validate alphanumeric values
46767 * @param {String} value The value
46769 'alphanum' : function(v){
46770 return alphanum.test(v);
46773 * The error text to display when the alphanumeric validation function returns false
46776 'alphanumText' : 'This field should only contain letters, numbers and _',
46778 * The keystroke filter mask to be applied on alphanumeric input
46781 'alphanumMask' : /[a-z0-9_]/i
46783 }();//<script type="text/javascript">
46786 * @class Roo.form.FCKeditor
46787 * @extends Roo.form.TextArea
46788 * Wrapper around the FCKEditor http://www.fckeditor.net
46790 * Creates a new FCKeditor
46791 * @param {Object} config Configuration options
46793 Roo.form.FCKeditor = function(config){
46794 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46797 * @event editorinit
46798 * Fired when the editor is initialized - you can add extra handlers here..
46799 * @param {FCKeditor} this
46800 * @param {Object} the FCK object.
46807 Roo.form.FCKeditor.editors = { };
46808 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46810 //defaultAutoCreate : {
46811 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46815 * @cfg {Object} fck options - see fck manual for details.
46820 * @cfg {Object} fck toolbar set (Basic or Default)
46822 toolbarSet : 'Basic',
46824 * @cfg {Object} fck BasePath
46826 basePath : '/fckeditor/',
46834 onRender : function(ct, position)
46837 this.defaultAutoCreate = {
46839 style:"width:300px;height:60px;",
46840 autocomplete: "new-password"
46843 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46846 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46847 if(this.preventScrollbars){
46848 this.el.setStyle("overflow", "hidden");
46850 this.el.setHeight(this.growMin);
46853 //console.log('onrender' + this.getId() );
46854 Roo.form.FCKeditor.editors[this.getId()] = this;
46857 this.replaceTextarea() ;
46861 getEditor : function() {
46862 return this.fckEditor;
46865 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46866 * @param {Mixed} value The value to set
46870 setValue : function(value)
46872 //console.log('setValue: ' + value);
46874 if(typeof(value) == 'undefined') { // not sure why this is happending...
46877 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46879 //if(!this.el || !this.getEditor()) {
46880 // this.value = value;
46881 //this.setValue.defer(100,this,[value]);
46885 if(!this.getEditor()) {
46889 this.getEditor().SetData(value);
46896 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46897 * @return {Mixed} value The field value
46899 getValue : function()
46902 if (this.frame && this.frame.dom.style.display == 'none') {
46903 return Roo.form.FCKeditor.superclass.getValue.call(this);
46906 if(!this.el || !this.getEditor()) {
46908 // this.getValue.defer(100,this);
46913 var value=this.getEditor().GetData();
46914 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46915 return Roo.form.FCKeditor.superclass.getValue.call(this);
46921 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46922 * @return {Mixed} value The field value
46924 getRawValue : function()
46926 if (this.frame && this.frame.dom.style.display == 'none') {
46927 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46930 if(!this.el || !this.getEditor()) {
46931 //this.getRawValue.defer(100,this);
46938 var value=this.getEditor().GetData();
46939 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46940 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46944 setSize : function(w,h) {
46948 //if (this.frame && this.frame.dom.style.display == 'none') {
46949 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46952 //if(!this.el || !this.getEditor()) {
46953 // this.setSize.defer(100,this, [w,h]);
46959 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46961 this.frame.dom.setAttribute('width', w);
46962 this.frame.dom.setAttribute('height', h);
46963 this.frame.setSize(w,h);
46967 toggleSourceEdit : function(value) {
46971 this.el.dom.style.display = value ? '' : 'none';
46972 this.frame.dom.style.display = value ? 'none' : '';
46977 focus: function(tag)
46979 if (this.frame.dom.style.display == 'none') {
46980 return Roo.form.FCKeditor.superclass.focus.call(this);
46982 if(!this.el || !this.getEditor()) {
46983 this.focus.defer(100,this, [tag]);
46990 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46991 this.getEditor().Focus();
46993 if (!this.getEditor().Selection.GetSelection()) {
46994 this.focus.defer(100,this, [tag]);
46999 var r = this.getEditor().EditorDocument.createRange();
47000 r.setStart(tgs[0],0);
47001 r.setEnd(tgs[0],0);
47002 this.getEditor().Selection.GetSelection().removeAllRanges();
47003 this.getEditor().Selection.GetSelection().addRange(r);
47004 this.getEditor().Focus();
47011 replaceTextarea : function()
47013 if ( document.getElementById( this.getId() + '___Frame' ) )
47015 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47017 // We must check the elements firstly using the Id and then the name.
47018 var oTextarea = document.getElementById( this.getId() );
47020 var colElementsByName = document.getElementsByName( this.getId() ) ;
47022 oTextarea.style.display = 'none' ;
47024 if ( oTextarea.tabIndex ) {
47025 this.TabIndex = oTextarea.tabIndex ;
47028 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47029 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47030 this.frame = Roo.get(this.getId() + '___Frame')
47033 _getConfigHtml : function()
47037 for ( var o in this.fckconfig ) {
47038 sConfig += sConfig.length > 0 ? '&' : '';
47039 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47042 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47046 _getIFrameHtml : function()
47048 var sFile = 'fckeditor.html' ;
47049 /* no idea what this is about..
47052 if ( (/fcksource=true/i).test( window.top.location.search ) )
47053 sFile = 'fckeditor.original.html' ;
47058 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47059 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47062 var html = '<iframe id="' + this.getId() +
47063 '___Frame" src="' + sLink +
47064 '" width="' + this.width +
47065 '" height="' + this.height + '"' +
47066 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47067 ' frameborder="0" scrolling="no"></iframe>' ;
47072 _insertHtmlBefore : function( html, element )
47074 if ( element.insertAdjacentHTML ) {
47076 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47078 var oRange = document.createRange() ;
47079 oRange.setStartBefore( element ) ;
47080 var oFragment = oRange.createContextualFragment( html );
47081 element.parentNode.insertBefore( oFragment, element ) ;
47094 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47096 function FCKeditor_OnComplete(editorInstance){
47097 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47098 f.fckEditor = editorInstance;
47099 //console.log("loaded");
47100 f.fireEvent('editorinit', f, editorInstance);
47120 //<script type="text/javascript">
47122 * @class Roo.form.GridField
47123 * @extends Roo.form.Field
47124 * Embed a grid (or editable grid into a form)
47127 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47129 * xgrid.store = Roo.data.Store
47130 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47131 * xgrid.store.reader = Roo.data.JsonReader
47135 * Creates a new GridField
47136 * @param {Object} config Configuration options
47138 Roo.form.GridField = function(config){
47139 Roo.form.GridField.superclass.constructor.call(this, config);
47143 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47145 * @cfg {Number} width - used to restrict width of grid..
47149 * @cfg {Number} height - used to restrict height of grid..
47153 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47159 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47160 * {tag: "input", type: "checkbox", autocomplete: "off"})
47162 // defaultAutoCreate : { tag: 'div' },
47163 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47165 * @cfg {String} addTitle Text to include for adding a title.
47169 onResize : function(){
47170 Roo.form.Field.superclass.onResize.apply(this, arguments);
47173 initEvents : function(){
47174 // Roo.form.Checkbox.superclass.initEvents.call(this);
47175 // has no events...
47180 getResizeEl : function(){
47184 getPositionEl : function(){
47189 onRender : function(ct, position){
47191 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47192 var style = this.style;
47195 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47196 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47197 this.viewEl = this.wrap.createChild({ tag: 'div' });
47199 this.viewEl.applyStyles(style);
47202 this.viewEl.setWidth(this.width);
47205 this.viewEl.setHeight(this.height);
47207 //if(this.inputValue !== undefined){
47208 //this.setValue(this.value);
47211 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47214 this.grid.render();
47215 this.grid.getDataSource().on('remove', this.refreshValue, this);
47216 this.grid.getDataSource().on('update', this.refreshValue, this);
47217 this.grid.on('afteredit', this.refreshValue, this);
47223 * Sets the value of the item.
47224 * @param {String} either an object or a string..
47226 setValue : function(v){
47228 v = v || []; // empty set..
47229 // this does not seem smart - it really only affects memoryproxy grids..
47230 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47231 var ds = this.grid.getDataSource();
47232 // assumes a json reader..
47234 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47235 ds.loadData( data);
47237 // clear selection so it does not get stale.
47238 if (this.grid.sm) {
47239 this.grid.sm.clearSelections();
47242 Roo.form.GridField.superclass.setValue.call(this, v);
47243 this.refreshValue();
47244 // should load data in the grid really....
47248 refreshValue: function() {
47250 this.grid.getDataSource().each(function(r) {
47253 this.el.dom.value = Roo.encode(val);
47261 * Ext JS Library 1.1.1
47262 * Copyright(c) 2006-2007, Ext JS, LLC.
47264 * Originally Released Under LGPL - original licence link has changed is not relivant.
47267 * <script type="text/javascript">
47270 * @class Roo.form.DisplayField
47271 * @extends Roo.form.Field
47272 * A generic Field to display non-editable data.
47274 * Creates a new Display Field item.
47275 * @param {Object} config Configuration options
47277 Roo.form.DisplayField = function(config){
47278 Roo.form.DisplayField.superclass.constructor.call(this, config);
47282 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47283 inputType: 'hidden',
47289 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47291 focusClass : undefined,
47293 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47295 fieldClass: 'x-form-field',
47298 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47300 valueRenderer: undefined,
47304 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47305 * {tag: "input", type: "checkbox", autocomplete: "off"})
47308 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47310 onResize : function(){
47311 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47315 initEvents : function(){
47316 // Roo.form.Checkbox.superclass.initEvents.call(this);
47317 // has no events...
47322 getResizeEl : function(){
47326 getPositionEl : function(){
47331 onRender : function(ct, position){
47333 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47334 //if(this.inputValue !== undefined){
47335 this.wrap = this.el.wrap();
47337 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47339 if (this.bodyStyle) {
47340 this.viewEl.applyStyles(this.bodyStyle);
47342 //this.viewEl.setStyle('padding', '2px');
47344 this.setValue(this.value);
47349 initValue : Roo.emptyFn,
47354 onClick : function(){
47359 * Sets the checked state of the checkbox.
47360 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47362 setValue : function(v){
47364 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47365 // this might be called before we have a dom element..
47366 if (!this.viewEl) {
47369 this.viewEl.dom.innerHTML = html;
47370 Roo.form.DisplayField.superclass.setValue.call(this, v);
47380 * @class Roo.form.DayPicker
47381 * @extends Roo.form.Field
47382 * A Day picker show [M] [T] [W] ....
47384 * Creates a new Day Picker
47385 * @param {Object} config Configuration options
47387 Roo.form.DayPicker= function(config){
47388 Roo.form.DayPicker.superclass.constructor.call(this, config);
47392 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47394 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47396 focusClass : undefined,
47398 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47400 fieldClass: "x-form-field",
47403 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47404 * {tag: "input", type: "checkbox", autocomplete: "off"})
47406 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47409 actionMode : 'viewEl',
47413 inputType : 'hidden',
47416 inputElement: false, // real input element?
47417 basedOn: false, // ????
47419 isFormField: true, // not sure where this is needed!!!!
47421 onResize : function(){
47422 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47423 if(!this.boxLabel){
47424 this.el.alignTo(this.wrap, 'c-c');
47428 initEvents : function(){
47429 Roo.form.Checkbox.superclass.initEvents.call(this);
47430 this.el.on("click", this.onClick, this);
47431 this.el.on("change", this.onClick, this);
47435 getResizeEl : function(){
47439 getPositionEl : function(){
47445 onRender : function(ct, position){
47446 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47448 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47450 var r1 = '<table><tr>';
47451 var r2 = '<tr class="x-form-daypick-icons">';
47452 for (var i=0; i < 7; i++) {
47453 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47454 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47457 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47458 viewEl.select('img').on('click', this.onClick, this);
47459 this.viewEl = viewEl;
47462 // this will not work on Chrome!!!
47463 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47464 this.el.on('propertychange', this.setFromHidden, this); //ie
47472 initValue : Roo.emptyFn,
47475 * Returns the checked state of the checkbox.
47476 * @return {Boolean} True if checked, else false
47478 getValue : function(){
47479 return this.el.dom.value;
47484 onClick : function(e){
47485 //this.setChecked(!this.checked);
47486 Roo.get(e.target).toggleClass('x-menu-item-checked');
47487 this.refreshValue();
47488 //if(this.el.dom.checked != this.checked){
47489 // this.setValue(this.el.dom.checked);
47494 refreshValue : function()
47497 this.viewEl.select('img',true).each(function(e,i,n) {
47498 val += e.is(".x-menu-item-checked") ? String(n) : '';
47500 this.setValue(val, true);
47504 * Sets the checked state of the checkbox.
47505 * On is always based on a string comparison between inputValue and the param.
47506 * @param {Boolean/String} value - the value to set
47507 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47509 setValue : function(v,suppressEvent){
47510 if (!this.el.dom) {
47513 var old = this.el.dom.value ;
47514 this.el.dom.value = v;
47515 if (suppressEvent) {
47519 // update display..
47520 this.viewEl.select('img',true).each(function(e,i,n) {
47522 var on = e.is(".x-menu-item-checked");
47523 var newv = v.indexOf(String(n)) > -1;
47525 e.toggleClass('x-menu-item-checked');
47531 this.fireEvent('change', this, v, old);
47536 // handle setting of hidden value by some other method!!?!?
47537 setFromHidden: function()
47542 //console.log("SET FROM HIDDEN");
47543 //alert('setFrom hidden');
47544 this.setValue(this.el.dom.value);
47547 onDestroy : function()
47550 Roo.get(this.viewEl).remove();
47553 Roo.form.DayPicker.superclass.onDestroy.call(this);
47557 * RooJS Library 1.1.1
47558 * Copyright(c) 2008-2011 Alan Knowles
47565 * @class Roo.form.ComboCheck
47566 * @extends Roo.form.ComboBox
47567 * A combobox for multiple select items.
47569 * FIXME - could do with a reset button..
47572 * Create a new ComboCheck
47573 * @param {Object} config Configuration options
47575 Roo.form.ComboCheck = function(config){
47576 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47577 // should verify some data...
47579 // hiddenName = required..
47580 // displayField = required
47581 // valudField == required
47582 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47584 Roo.each(req, function(e) {
47585 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47586 throw "Roo.form.ComboCheck : missing value for: " + e;
47593 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47598 selectedClass: 'x-menu-item-checked',
47601 onRender : function(ct, position){
47607 var cls = 'x-combo-list';
47610 this.tpl = new Roo.Template({
47611 html : '<div class="'+cls+'-item x-menu-check-item">' +
47612 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47613 '<span>{' + this.displayField + '}</span>' +
47620 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47621 this.view.singleSelect = false;
47622 this.view.multiSelect = true;
47623 this.view.toggleSelect = true;
47624 this.pageTb.add(new Roo.Toolbar.Fill(), {
47627 handler: function()
47634 onViewOver : function(e, t){
47640 onViewClick : function(doFocus,index){
47644 select: function () {
47645 //Roo.log("SELECT CALLED");
47648 selectByValue : function(xv, scrollIntoView){
47649 var ar = this.getValueArray();
47652 Roo.each(ar, function(v) {
47653 if(v === undefined || v === null){
47656 var r = this.findRecord(this.valueField, v);
47658 sels.push(this.store.indexOf(r))
47662 this.view.select(sels);
47668 onSelect : function(record, index){
47669 // Roo.log("onselect Called");
47670 // this is only called by the clear button now..
47671 this.view.clearSelections();
47672 this.setValue('[]');
47673 if (this.value != this.valueBefore) {
47674 this.fireEvent('change', this, this.value, this.valueBefore);
47675 this.valueBefore = this.value;
47678 getValueArray : function()
47683 //Roo.log(this.value);
47684 if (typeof(this.value) == 'undefined') {
47687 var ar = Roo.decode(this.value);
47688 return ar instanceof Array ? ar : []; //?? valid?
47691 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47696 expand : function ()
47699 Roo.form.ComboCheck.superclass.expand.call(this);
47700 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47701 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47706 collapse : function(){
47707 Roo.form.ComboCheck.superclass.collapse.call(this);
47708 var sl = this.view.getSelectedIndexes();
47709 var st = this.store;
47713 Roo.each(sl, function(i) {
47715 nv.push(r.get(this.valueField));
47717 this.setValue(Roo.encode(nv));
47718 if (this.value != this.valueBefore) {
47720 this.fireEvent('change', this, this.value, this.valueBefore);
47721 this.valueBefore = this.value;
47726 setValue : function(v){
47730 var vals = this.getValueArray();
47732 Roo.each(vals, function(k) {
47733 var r = this.findRecord(this.valueField, k);
47735 tv.push(r.data[this.displayField]);
47736 }else if(this.valueNotFoundText !== undefined){
47737 tv.push( this.valueNotFoundText );
47742 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47743 this.hiddenField.value = v;
47749 * Ext JS Library 1.1.1
47750 * Copyright(c) 2006-2007, Ext JS, LLC.
47752 * Originally Released Under LGPL - original licence link has changed is not relivant.
47755 * <script type="text/javascript">
47759 * @class Roo.form.Signature
47760 * @extends Roo.form.Field
47764 * @param {Object} config Configuration options
47767 Roo.form.Signature = function(config){
47768 Roo.form.Signature.superclass.constructor.call(this, config);
47770 this.addEvents({// not in used??
47773 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47774 * @param {Roo.form.Signature} combo This combo box
47779 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47780 * @param {Roo.form.ComboBox} combo This combo box
47781 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47787 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47789 * @cfg {Object} labels Label to use when rendering a form.
47793 * confirm : "Confirm"
47798 confirm : "Confirm"
47801 * @cfg {Number} width The signature panel width (defaults to 300)
47805 * @cfg {Number} height The signature panel height (defaults to 100)
47809 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47811 allowBlank : false,
47814 // {Object} signPanel The signature SVG panel element (defaults to {})
47816 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47817 isMouseDown : false,
47818 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47819 isConfirmed : false,
47820 // {String} signatureTmp SVG mapping string (defaults to empty string)
47824 defaultAutoCreate : { // modified by initCompnoent..
47830 onRender : function(ct, position){
47832 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47834 this.wrap = this.el.wrap({
47835 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47838 this.createToolbar(this);
47839 this.signPanel = this.wrap.createChild({
47841 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47845 this.svgID = Roo.id();
47846 this.svgEl = this.signPanel.createChild({
47847 xmlns : 'http://www.w3.org/2000/svg',
47849 id : this.svgID + "-svg",
47851 height: this.height,
47852 viewBox: '0 0 '+this.width+' '+this.height,
47856 id: this.svgID + "-svg-r",
47858 height: this.height,
47863 id: this.svgID + "-svg-l",
47865 y1: (this.height*0.8), // start set the line in 80% of height
47866 x2: this.width, // end
47867 y2: (this.height*0.8), // end set the line in 80% of height
47869 'stroke-width': "1",
47870 'stroke-dasharray': "3",
47871 'shape-rendering': "crispEdges",
47872 'pointer-events': "none"
47876 id: this.svgID + "-svg-p",
47878 'stroke-width': "3",
47880 'pointer-events': 'none'
47885 this.svgBox = this.svgEl.dom.getScreenCTM();
47887 createSVG : function(){
47888 var svg = this.signPanel;
47889 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47892 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47893 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47894 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47895 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47896 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47897 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47898 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47901 isTouchEvent : function(e){
47902 return e.type.match(/^touch/);
47904 getCoords : function (e) {
47905 var pt = this.svgEl.dom.createSVGPoint();
47908 if (this.isTouchEvent(e)) {
47909 pt.x = e.targetTouches[0].clientX;
47910 pt.y = e.targetTouches[0].clientY;
47912 var a = this.svgEl.dom.getScreenCTM();
47913 var b = a.inverse();
47914 var mx = pt.matrixTransform(b);
47915 return mx.x + ',' + mx.y;
47917 //mouse event headler
47918 down : function (e) {
47919 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47920 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47922 this.isMouseDown = true;
47924 e.preventDefault();
47926 move : function (e) {
47927 if (this.isMouseDown) {
47928 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47929 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47932 e.preventDefault();
47934 up : function (e) {
47935 this.isMouseDown = false;
47936 var sp = this.signatureTmp.split(' ');
47939 if(!sp[sp.length-2].match(/^L/)){
47943 this.signatureTmp = sp.join(" ");
47946 if(this.getValue() != this.signatureTmp){
47947 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47948 this.isConfirmed = false;
47950 e.preventDefault();
47954 * Protected method that will not generally be called directly. It
47955 * is called when the editor creates its toolbar. Override this method if you need to
47956 * add custom toolbar buttons.
47957 * @param {HtmlEditor} editor
47959 createToolbar : function(editor){
47960 function btn(id, toggle, handler){
47961 var xid = fid + '-'+ id ;
47965 cls : 'x-btn-icon x-edit-'+id,
47966 enableToggle:toggle !== false,
47967 scope: editor, // was editor...
47968 handler:handler||editor.relayBtnCmd,
47969 clickEvent:'mousedown',
47970 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47976 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47980 cls : ' x-signature-btn x-signature-'+id,
47981 scope: editor, // was editor...
47982 handler: this.reset,
47983 clickEvent:'mousedown',
47984 text: this.labels.clear
47991 cls : ' x-signature-btn x-signature-'+id,
47992 scope: editor, // was editor...
47993 handler: this.confirmHandler,
47994 clickEvent:'mousedown',
47995 text: this.labels.confirm
48002 * when user is clicked confirm then show this image.....
48004 * @return {String} Image Data URI
48006 getImageDataURI : function(){
48007 var svg = this.svgEl.dom.parentNode.innerHTML;
48008 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48013 * @return {Boolean} this.isConfirmed
48015 getConfirmed : function(){
48016 return this.isConfirmed;
48020 * @return {Number} this.width
48022 getWidth : function(){
48027 * @return {Number} this.height
48029 getHeight : function(){
48030 return this.height;
48033 getSignature : function(){
48034 return this.signatureTmp;
48037 reset : function(){
48038 this.signatureTmp = '';
48039 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48040 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48041 this.isConfirmed = false;
48042 Roo.form.Signature.superclass.reset.call(this);
48044 setSignature : function(s){
48045 this.signatureTmp = s;
48046 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48047 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48049 this.isConfirmed = false;
48050 Roo.form.Signature.superclass.reset.call(this);
48053 // Roo.log(this.signPanel.dom.contentWindow.up())
48056 setConfirmed : function(){
48060 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48063 confirmHandler : function(){
48064 if(!this.getSignature()){
48068 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48069 this.setValue(this.getSignature());
48070 this.isConfirmed = true;
48072 this.fireEvent('confirm', this);
48075 // Subclasses should provide the validation implementation by overriding this
48076 validateValue : function(value){
48077 if(this.allowBlank){
48081 if(this.isConfirmed){
48088 * Ext JS Library 1.1.1
48089 * Copyright(c) 2006-2007, Ext JS, LLC.
48091 * Originally Released Under LGPL - original licence link has changed is not relivant.
48094 * <script type="text/javascript">
48099 * @class Roo.form.ComboBox
48100 * @extends Roo.form.TriggerField
48101 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48103 * Create a new ComboBox.
48104 * @param {Object} config Configuration options
48106 Roo.form.Select = function(config){
48107 Roo.form.Select.superclass.constructor.call(this, config);
48111 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48113 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48116 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48117 * rendering into an Roo.Editor, defaults to false)
48120 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48121 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48124 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48127 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48128 * the dropdown list (defaults to undefined, with no header element)
48132 * @cfg {String/Roo.Template} tpl The template to use to render the output
48136 defaultAutoCreate : {tag: "select" },
48138 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48140 listWidth: undefined,
48142 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48143 * mode = 'remote' or 'text' if mode = 'local')
48145 displayField: undefined,
48147 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48148 * mode = 'remote' or 'value' if mode = 'local').
48149 * Note: use of a valueField requires the user make a selection
48150 * in order for a value to be mapped.
48152 valueField: undefined,
48156 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48157 * field's data value (defaults to the underlying DOM element's name)
48159 hiddenName: undefined,
48161 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48165 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48167 selectedClass: 'x-combo-selected',
48169 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48170 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48171 * which displays a downward arrow icon).
48173 triggerClass : 'x-form-arrow-trigger',
48175 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48179 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48180 * anchor positions (defaults to 'tl-bl')
48182 listAlign: 'tl-bl?',
48184 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48188 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48189 * query specified by the allQuery config option (defaults to 'query')
48191 triggerAction: 'query',
48193 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48194 * (defaults to 4, does not apply if editable = false)
48198 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48199 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48203 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48204 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48208 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48209 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48213 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48214 * when editable = true (defaults to false)
48216 selectOnFocus:false,
48218 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48220 queryParam: 'query',
48222 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48223 * when mode = 'remote' (defaults to 'Loading...')
48225 loadingText: 'Loading...',
48227 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48231 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48235 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48236 * traditional select (defaults to true)
48240 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48244 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48248 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48249 * listWidth has a higher value)
48253 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48254 * allow the user to set arbitrary text into the field (defaults to false)
48256 forceSelection:false,
48258 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48259 * if typeAhead = true (defaults to 250)
48261 typeAheadDelay : 250,
48263 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48264 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48266 valueNotFoundText : undefined,
48269 * @cfg {String} defaultValue The value displayed after loading the store.
48274 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48276 blockFocus : false,
48279 * @cfg {Boolean} disableClear Disable showing of clear button.
48281 disableClear : false,
48283 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48285 alwaysQuery : false,
48291 // element that contains real text value.. (when hidden is used..)
48294 onRender : function(ct, position){
48295 Roo.form.Field.prototype.onRender.call(this, ct, position);
48298 this.store.on('beforeload', this.onBeforeLoad, this);
48299 this.store.on('load', this.onLoad, this);
48300 this.store.on('loadexception', this.onLoadException, this);
48301 this.store.load({});
48309 initEvents : function(){
48310 //Roo.form.ComboBox.superclass.initEvents.call(this);
48314 onDestroy : function(){
48317 this.store.un('beforeload', this.onBeforeLoad, this);
48318 this.store.un('load', this.onLoad, this);
48319 this.store.un('loadexception', this.onLoadException, this);
48321 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48325 fireKey : function(e){
48326 if(e.isNavKeyPress() && !this.list.isVisible()){
48327 this.fireEvent("specialkey", this, e);
48332 onResize: function(w, h){
48340 * Allow or prevent the user from directly editing the field text. If false is passed,
48341 * the user will only be able to select from the items defined in the dropdown list. This method
48342 * is the runtime equivalent of setting the 'editable' config option at config time.
48343 * @param {Boolean} value True to allow the user to directly edit the field text
48345 setEditable : function(value){
48350 onBeforeLoad : function(){
48352 Roo.log("Select before load");
48355 this.innerList.update(this.loadingText ?
48356 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48357 //this.restrictHeight();
48358 this.selectedIndex = -1;
48362 onLoad : function(){
48365 var dom = this.el.dom;
48366 dom.innerHTML = '';
48367 var od = dom.ownerDocument;
48369 if (this.emptyText) {
48370 var op = od.createElement('option');
48371 op.setAttribute('value', '');
48372 op.innerHTML = String.format('{0}', this.emptyText);
48373 dom.appendChild(op);
48375 if(this.store.getCount() > 0){
48377 var vf = this.valueField;
48378 var df = this.displayField;
48379 this.store.data.each(function(r) {
48380 // which colmsn to use... testing - cdoe / title..
48381 var op = od.createElement('option');
48382 op.setAttribute('value', r.data[vf]);
48383 op.innerHTML = String.format('{0}', r.data[df]);
48384 dom.appendChild(op);
48386 if (typeof(this.defaultValue != 'undefined')) {
48387 this.setValue(this.defaultValue);
48392 //this.onEmptyResults();
48397 onLoadException : function()
48399 dom.innerHTML = '';
48401 Roo.log("Select on load exception");
48405 Roo.log(this.store.reader.jsonData);
48406 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48407 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48413 onTypeAhead : function(){
48418 onSelect : function(record, index){
48419 Roo.log('on select?');
48421 if(this.fireEvent('beforeselect', this, record, index) !== false){
48422 this.setFromData(index > -1 ? record.data : false);
48424 this.fireEvent('select', this, record, index);
48429 * Returns the currently selected field value or empty string if no value is set.
48430 * @return {String} value The selected value
48432 getValue : function(){
48433 var dom = this.el.dom;
48434 this.value = dom.options[dom.selectedIndex].value;
48440 * Clears any text/value currently set in the field
48442 clearValue : function(){
48444 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48449 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48450 * will be displayed in the field. If the value does not match the data value of an existing item,
48451 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48452 * Otherwise the field will be blank (although the value will still be set).
48453 * @param {String} value The value to match
48455 setValue : function(v){
48456 var d = this.el.dom;
48457 for (var i =0; i < d.options.length;i++) {
48458 if (v == d.options[i].value) {
48459 d.selectedIndex = i;
48467 * @property {Object} the last set data for the element
48472 * Sets the value of the field based on a object which is related to the record format for the store.
48473 * @param {Object} value the value to set as. or false on reset?
48475 setFromData : function(o){
48476 Roo.log('setfrom data?');
48482 reset : function(){
48486 findRecord : function(prop, value){
48491 if(this.store.getCount() > 0){
48492 this.store.each(function(r){
48493 if(r.data[prop] == value){
48503 getName: function()
48505 // returns hidden if it's set..
48506 if (!this.rendered) {return ''};
48507 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48515 onEmptyResults : function(){
48516 Roo.log('empty results');
48521 * Returns true if the dropdown list is expanded, else false.
48523 isExpanded : function(){
48528 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48529 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48530 * @param {String} value The data value of the item to select
48531 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48532 * selected item if it is not currently in view (defaults to true)
48533 * @return {Boolean} True if the value matched an item in the list, else false
48535 selectByValue : function(v, scrollIntoView){
48536 Roo.log('select By Value');
48539 if(v !== undefined && v !== null){
48540 var r = this.findRecord(this.valueField || this.displayField, v);
48542 this.select(this.store.indexOf(r), scrollIntoView);
48550 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48551 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48552 * @param {Number} index The zero-based index of the list item to select
48553 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48554 * selected item if it is not currently in view (defaults to true)
48556 select : function(index, scrollIntoView){
48557 Roo.log('select ');
48560 this.selectedIndex = index;
48561 this.view.select(index);
48562 if(scrollIntoView !== false){
48563 var el = this.view.getNode(index);
48565 this.innerList.scrollChildIntoView(el, false);
48573 validateBlur : function(){
48580 initQuery : function(){
48581 this.doQuery(this.getRawValue());
48585 doForce : function(){
48586 if(this.el.dom.value.length > 0){
48587 this.el.dom.value =
48588 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48594 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48595 * query allowing the query action to be canceled if needed.
48596 * @param {String} query The SQL query to execute
48597 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48598 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48599 * saved in the current store (defaults to false)
48601 doQuery : function(q, forceAll){
48603 Roo.log('doQuery?');
48604 if(q === undefined || q === null){
48609 forceAll: forceAll,
48613 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48617 forceAll = qe.forceAll;
48618 if(forceAll === true || (q.length >= this.minChars)){
48619 if(this.lastQuery != q || this.alwaysQuery){
48620 this.lastQuery = q;
48621 if(this.mode == 'local'){
48622 this.selectedIndex = -1;
48624 this.store.clearFilter();
48626 this.store.filter(this.displayField, q);
48630 this.store.baseParams[this.queryParam] = q;
48632 params: this.getParams(q)
48637 this.selectedIndex = -1;
48644 getParams : function(q){
48646 //p[this.queryParam] = q;
48649 p.limit = this.pageSize;
48655 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48657 collapse : function(){
48662 collapseIf : function(e){
48667 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48669 expand : function(){
48677 * @cfg {Boolean} grow
48681 * @cfg {Number} growMin
48685 * @cfg {Number} growMax
48693 setWidth : function()
48697 getResizeEl : function(){
48700 });//<script type="text/javasscript">
48704 * @class Roo.DDView
48705 * A DnD enabled version of Roo.View.
48706 * @param {Element/String} container The Element in which to create the View.
48707 * @param {String} tpl The template string used to create the markup for each element of the View
48708 * @param {Object} config The configuration properties. These include all the config options of
48709 * {@link Roo.View} plus some specific to this class.<br>
48711 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48712 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48714 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48715 .x-view-drag-insert-above {
48716 border-top:1px dotted #3366cc;
48718 .x-view-drag-insert-below {
48719 border-bottom:1px dotted #3366cc;
48725 Roo.DDView = function(container, tpl, config) {
48726 Roo.DDView.superclass.constructor.apply(this, arguments);
48727 this.getEl().setStyle("outline", "0px none");
48728 this.getEl().unselectable();
48729 if (this.dragGroup) {
48730 this.setDraggable(this.dragGroup.split(","));
48732 if (this.dropGroup) {
48733 this.setDroppable(this.dropGroup.split(","));
48735 if (this.deletable) {
48736 this.setDeletable();
48738 this.isDirtyFlag = false;
48744 Roo.extend(Roo.DDView, Roo.View, {
48745 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48746 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48747 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48748 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48752 reset: Roo.emptyFn,
48754 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48756 validate: function() {
48760 destroy: function() {
48761 this.purgeListeners();
48762 this.getEl.removeAllListeners();
48763 this.getEl().remove();
48764 if (this.dragZone) {
48765 if (this.dragZone.destroy) {
48766 this.dragZone.destroy();
48769 if (this.dropZone) {
48770 if (this.dropZone.destroy) {
48771 this.dropZone.destroy();
48776 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48777 getName: function() {
48781 /** Loads the View from a JSON string representing the Records to put into the Store. */
48782 setValue: function(v) {
48784 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48787 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48788 this.store.proxy = new Roo.data.MemoryProxy(data);
48792 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48793 getValue: function() {
48795 this.store.each(function(rec) {
48796 result += rec.id + ',';
48798 return result.substr(0, result.length - 1) + ')';
48801 getIds: function() {
48802 var i = 0, result = new Array(this.store.getCount());
48803 this.store.each(function(rec) {
48804 result[i++] = rec.id;
48809 isDirty: function() {
48810 return this.isDirtyFlag;
48814 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48815 * whole Element becomes the target, and this causes the drop gesture to append.
48817 getTargetFromEvent : function(e) {
48818 var target = e.getTarget();
48819 while ((target !== null) && (target.parentNode != this.el.dom)) {
48820 target = target.parentNode;
48823 target = this.el.dom.lastChild || this.el.dom;
48829 * Create the drag data which consists of an object which has the property "ddel" as
48830 * the drag proxy element.
48832 getDragData : function(e) {
48833 var target = this.findItemFromChild(e.getTarget());
48835 this.handleSelection(e);
48836 var selNodes = this.getSelectedNodes();
48839 copy: this.copy || (this.allowCopy && e.ctrlKey),
48843 var selectedIndices = this.getSelectedIndexes();
48844 for (var i = 0; i < selectedIndices.length; i++) {
48845 dragData.records.push(this.store.getAt(selectedIndices[i]));
48847 if (selNodes.length == 1) {
48848 dragData.ddel = target.cloneNode(true); // the div element
48850 var div = document.createElement('div'); // create the multi element drag "ghost"
48851 div.className = 'multi-proxy';
48852 for (var i = 0, len = selNodes.length; i < len; i++) {
48853 div.appendChild(selNodes[i].cloneNode(true));
48855 dragData.ddel = div;
48857 //console.log(dragData)
48858 //console.log(dragData.ddel.innerHTML)
48861 //console.log('nodragData')
48865 /** Specify to which ddGroup items in this DDView may be dragged. */
48866 setDraggable: function(ddGroup) {
48867 if (ddGroup instanceof Array) {
48868 Roo.each(ddGroup, this.setDraggable, this);
48871 if (this.dragZone) {
48872 this.dragZone.addToGroup(ddGroup);
48874 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48875 containerScroll: true,
48879 // Draggability implies selection. DragZone's mousedown selects the element.
48880 if (!this.multiSelect) { this.singleSelect = true; }
48882 // Wire the DragZone's handlers up to methods in *this*
48883 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48887 /** Specify from which ddGroup this DDView accepts drops. */
48888 setDroppable: function(ddGroup) {
48889 if (ddGroup instanceof Array) {
48890 Roo.each(ddGroup, this.setDroppable, this);
48893 if (this.dropZone) {
48894 this.dropZone.addToGroup(ddGroup);
48896 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48897 containerScroll: true,
48901 // Wire the DropZone's handlers up to methods in *this*
48902 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48903 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48904 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48905 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48906 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48910 /** Decide whether to drop above or below a View node. */
48911 getDropPoint : function(e, n, dd){
48912 if (n == this.el.dom) { return "above"; }
48913 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48914 var c = t + (b - t) / 2;
48915 var y = Roo.lib.Event.getPageY(e);
48923 onNodeEnter : function(n, dd, e, data){
48927 onNodeOver : function(n, dd, e, data){
48928 var pt = this.getDropPoint(e, n, dd);
48929 // set the insert point style on the target node
48930 var dragElClass = this.dropNotAllowed;
48933 if (pt == "above"){
48934 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48935 targetElClass = "x-view-drag-insert-above";
48937 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48938 targetElClass = "x-view-drag-insert-below";
48940 if (this.lastInsertClass != targetElClass){
48941 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48942 this.lastInsertClass = targetElClass;
48945 return dragElClass;
48948 onNodeOut : function(n, dd, e, data){
48949 this.removeDropIndicators(n);
48952 onNodeDrop : function(n, dd, e, data){
48953 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48956 var pt = this.getDropPoint(e, n, dd);
48957 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48958 if (pt == "below") { insertAt++; }
48959 for (var i = 0; i < data.records.length; i++) {
48960 var r = data.records[i];
48961 var dup = this.store.getById(r.id);
48962 if (dup && (dd != this.dragZone)) {
48963 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48966 this.store.insert(insertAt++, r.copy());
48968 data.source.isDirtyFlag = true;
48970 this.store.insert(insertAt++, r);
48972 this.isDirtyFlag = true;
48975 this.dragZone.cachedTarget = null;
48979 removeDropIndicators : function(n){
48981 Roo.fly(n).removeClass([
48982 "x-view-drag-insert-above",
48983 "x-view-drag-insert-below"]);
48984 this.lastInsertClass = "_noclass";
48989 * Utility method. Add a delete option to the DDView's context menu.
48990 * @param {String} imageUrl The URL of the "delete" icon image.
48992 setDeletable: function(imageUrl) {
48993 if (!this.singleSelect && !this.multiSelect) {
48994 this.singleSelect = true;
48996 var c = this.getContextMenu();
48997 this.contextMenu.on("itemclick", function(item) {
49000 this.remove(this.getSelectedIndexes());
49004 this.contextMenu.add({
49011 /** Return the context menu for this DDView. */
49012 getContextMenu: function() {
49013 if (!this.contextMenu) {
49014 // Create the View's context menu
49015 this.contextMenu = new Roo.menu.Menu({
49016 id: this.id + "-contextmenu"
49018 this.el.on("contextmenu", this.showContextMenu, this);
49020 return this.contextMenu;
49023 disableContextMenu: function() {
49024 if (this.contextMenu) {
49025 this.el.un("contextmenu", this.showContextMenu, this);
49029 showContextMenu: function(e, item) {
49030 item = this.findItemFromChild(e.getTarget());
49033 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49034 this.contextMenu.showAt(e.getXY());
49039 * Remove {@link Roo.data.Record}s at the specified indices.
49040 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49042 remove: function(selectedIndices) {
49043 selectedIndices = [].concat(selectedIndices);
49044 for (var i = 0; i < selectedIndices.length; i++) {
49045 var rec = this.store.getAt(selectedIndices[i]);
49046 this.store.remove(rec);
49051 * Double click fires the event, but also, if this is draggable, and there is only one other
49052 * related DropZone, it transfers the selected node.
49054 onDblClick : function(e){
49055 var item = this.findItemFromChild(e.getTarget());
49057 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49060 if (this.dragGroup) {
49061 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49062 while (targets.indexOf(this.dropZone) > -1) {
49063 targets.remove(this.dropZone);
49065 if (targets.length == 1) {
49066 this.dragZone.cachedTarget = null;
49067 var el = Roo.get(targets[0].getEl());
49068 var box = el.getBox(true);
49069 targets[0].onNodeDrop(el.dom, {
49071 xy: [box.x, box.y + box.height - 1]
49072 }, null, this.getDragData(e));
49078 handleSelection: function(e) {
49079 this.dragZone.cachedTarget = null;
49080 var item = this.findItemFromChild(e.getTarget());
49082 this.clearSelections(true);
49085 if (item && (this.multiSelect || this.singleSelect)){
49086 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49087 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49088 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49089 this.unselect(item);
49091 this.select(item, this.multiSelect && e.ctrlKey);
49092 this.lastSelection = item;
49097 onItemClick : function(item, index, e){
49098 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49104 unselect : function(nodeInfo, suppressEvent){
49105 var node = this.getNode(nodeInfo);
49106 if(node && this.isSelected(node)){
49107 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49108 Roo.fly(node).removeClass(this.selectedClass);
49109 this.selections.remove(node);
49110 if(!suppressEvent){
49111 this.fireEvent("selectionchange", this, this.selections);
49119 * Ext JS Library 1.1.1
49120 * Copyright(c) 2006-2007, Ext JS, LLC.
49122 * Originally Released Under LGPL - original licence link has changed is not relivant.
49125 * <script type="text/javascript">
49129 * @class Roo.LayoutManager
49130 * @extends Roo.util.Observable
49131 * Base class for layout managers.
49133 Roo.LayoutManager = function(container, config){
49134 Roo.LayoutManager.superclass.constructor.call(this);
49135 this.el = Roo.get(container);
49136 // ie scrollbar fix
49137 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49138 document.body.scroll = "no";
49139 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49140 this.el.position('relative');
49142 this.id = this.el.id;
49143 this.el.addClass("x-layout-container");
49144 /** false to disable window resize monitoring @type Boolean */
49145 this.monitorWindowResize = true;
49150 * Fires when a layout is performed.
49151 * @param {Roo.LayoutManager} this
49155 * @event regionresized
49156 * Fires when the user resizes a region.
49157 * @param {Roo.LayoutRegion} region The resized region
49158 * @param {Number} newSize The new size (width for east/west, height for north/south)
49160 "regionresized" : true,
49162 * @event regioncollapsed
49163 * Fires when a region is collapsed.
49164 * @param {Roo.LayoutRegion} region The collapsed region
49166 "regioncollapsed" : true,
49168 * @event regionexpanded
49169 * Fires when a region is expanded.
49170 * @param {Roo.LayoutRegion} region The expanded region
49172 "regionexpanded" : true
49174 this.updating = false;
49175 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49178 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49180 * Returns true if this layout is currently being updated
49181 * @return {Boolean}
49183 isUpdating : function(){
49184 return this.updating;
49188 * Suspend the LayoutManager from doing auto-layouts while
49189 * making multiple add or remove calls
49191 beginUpdate : function(){
49192 this.updating = true;
49196 * Restore auto-layouts and optionally disable the manager from performing a layout
49197 * @param {Boolean} noLayout true to disable a layout update
49199 endUpdate : function(noLayout){
49200 this.updating = false;
49206 layout: function(){
49210 onRegionResized : function(region, newSize){
49211 this.fireEvent("regionresized", region, newSize);
49215 onRegionCollapsed : function(region){
49216 this.fireEvent("regioncollapsed", region);
49219 onRegionExpanded : function(region){
49220 this.fireEvent("regionexpanded", region);
49224 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49225 * performs box-model adjustments.
49226 * @return {Object} The size as an object {width: (the width), height: (the height)}
49228 getViewSize : function(){
49230 if(this.el.dom != document.body){
49231 size = this.el.getSize();
49233 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49235 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49236 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49241 * Returns the Element this layout is bound to.
49242 * @return {Roo.Element}
49244 getEl : function(){
49249 * Returns the specified region.
49250 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49251 * @return {Roo.LayoutRegion}
49253 getRegion : function(target){
49254 return this.regions[target.toLowerCase()];
49257 onWindowResize : function(){
49258 if(this.monitorWindowResize){
49264 * Ext JS Library 1.1.1
49265 * Copyright(c) 2006-2007, Ext JS, LLC.
49267 * Originally Released Under LGPL - original licence link has changed is not relivant.
49270 * <script type="text/javascript">
49273 * @class Roo.BorderLayout
49274 * @extends Roo.LayoutManager
49275 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49276 * please see: <br><br>
49277 * <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>
49278 * <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>
49281 var layout = new Roo.BorderLayout(document.body, {
49315 preferredTabWidth: 150
49320 var CP = Roo.ContentPanel;
49322 layout.beginUpdate();
49323 layout.add("north", new CP("north", "North"));
49324 layout.add("south", new CP("south", {title: "South", closable: true}));
49325 layout.add("west", new CP("west", {title: "West"}));
49326 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49327 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49328 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49329 layout.getRegion("center").showPanel("center1");
49330 layout.endUpdate();
49333 <b>The container the layout is rendered into can be either the body element or any other element.
49334 If it is not the body element, the container needs to either be an absolute positioned element,
49335 or you will need to add "position:relative" to the css of the container. You will also need to specify
49336 the container size if it is not the body element.</b>
49339 * Create a new BorderLayout
49340 * @param {String/HTMLElement/Element} container The container this layout is bound to
49341 * @param {Object} config Configuration options
49343 Roo.BorderLayout = function(container, config){
49344 config = config || {};
49345 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49346 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49347 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49348 var target = this.factory.validRegions[i];
49349 if(config[target]){
49350 this.addRegion(target, config[target]);
49355 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49357 * Creates and adds a new region if it doesn't already exist.
49358 * @param {String} target The target region key (north, south, east, west or center).
49359 * @param {Object} config The regions config object
49360 * @return {BorderLayoutRegion} The new region
49362 addRegion : function(target, config){
49363 if(!this.regions[target]){
49364 var r = this.factory.create(target, this, config);
49365 this.bindRegion(target, r);
49367 return this.regions[target];
49371 bindRegion : function(name, r){
49372 this.regions[name] = r;
49373 r.on("visibilitychange", this.layout, this);
49374 r.on("paneladded", this.layout, this);
49375 r.on("panelremoved", this.layout, this);
49376 r.on("invalidated", this.layout, this);
49377 r.on("resized", this.onRegionResized, this);
49378 r.on("collapsed", this.onRegionCollapsed, this);
49379 r.on("expanded", this.onRegionExpanded, this);
49383 * Performs a layout update.
49385 layout : function(){
49386 if(this.updating) return;
49387 var size = this.getViewSize();
49388 var w = size.width;
49389 var h = size.height;
49394 //var x = 0, y = 0;
49396 var rs = this.regions;
49397 var north = rs["north"];
49398 var south = rs["south"];
49399 var west = rs["west"];
49400 var east = rs["east"];
49401 var center = rs["center"];
49402 //if(this.hideOnLayout){ // not supported anymore
49403 //c.el.setStyle("display", "none");
49405 if(north && north.isVisible()){
49406 var b = north.getBox();
49407 var m = north.getMargins();
49408 b.width = w - (m.left+m.right);
49411 centerY = b.height + b.y + m.bottom;
49412 centerH -= centerY;
49413 north.updateBox(this.safeBox(b));
49415 if(south && south.isVisible()){
49416 var b = south.getBox();
49417 var m = south.getMargins();
49418 b.width = w - (m.left+m.right);
49420 var totalHeight = (b.height + m.top + m.bottom);
49421 b.y = h - totalHeight + m.top;
49422 centerH -= totalHeight;
49423 south.updateBox(this.safeBox(b));
49425 if(west && west.isVisible()){
49426 var b = west.getBox();
49427 var m = west.getMargins();
49428 b.height = centerH - (m.top+m.bottom);
49430 b.y = centerY + m.top;
49431 var totalWidth = (b.width + m.left + m.right);
49432 centerX += totalWidth;
49433 centerW -= totalWidth;
49434 west.updateBox(this.safeBox(b));
49436 if(east && east.isVisible()){
49437 var b = east.getBox();
49438 var m = east.getMargins();
49439 b.height = centerH - (m.top+m.bottom);
49440 var totalWidth = (b.width + m.left + m.right);
49441 b.x = w - totalWidth + m.left;
49442 b.y = centerY + m.top;
49443 centerW -= totalWidth;
49444 east.updateBox(this.safeBox(b));
49447 var m = center.getMargins();
49449 x: centerX + m.left,
49450 y: centerY + m.top,
49451 width: centerW - (m.left+m.right),
49452 height: centerH - (m.top+m.bottom)
49454 //if(this.hideOnLayout){
49455 //center.el.setStyle("display", "block");
49457 center.updateBox(this.safeBox(centerBox));
49460 this.fireEvent("layout", this);
49464 safeBox : function(box){
49465 box.width = Math.max(0, box.width);
49466 box.height = Math.max(0, box.height);
49471 * Adds a ContentPanel (or subclass) to this layout.
49472 * @param {String} target The target region key (north, south, east, west or center).
49473 * @param {Roo.ContentPanel} panel The panel to add
49474 * @return {Roo.ContentPanel} The added panel
49476 add : function(target, panel){
49478 target = target.toLowerCase();
49479 return this.regions[target].add(panel);
49483 * Remove a ContentPanel (or subclass) to this layout.
49484 * @param {String} target The target region key (north, south, east, west or center).
49485 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49486 * @return {Roo.ContentPanel} The removed panel
49488 remove : function(target, panel){
49489 target = target.toLowerCase();
49490 return this.regions[target].remove(panel);
49494 * Searches all regions for a panel with the specified id
49495 * @param {String} panelId
49496 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49498 findPanel : function(panelId){
49499 var rs = this.regions;
49500 for(var target in rs){
49501 if(typeof rs[target] != "function"){
49502 var p = rs[target].getPanel(panelId);
49512 * Searches all regions for a panel with the specified id and activates (shows) it.
49513 * @param {String/ContentPanel} panelId The panels id or the panel itself
49514 * @return {Roo.ContentPanel} The shown panel or null
49516 showPanel : function(panelId) {
49517 var rs = this.regions;
49518 for(var target in rs){
49519 var r = rs[target];
49520 if(typeof r != "function"){
49521 if(r.hasPanel(panelId)){
49522 return r.showPanel(panelId);
49530 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49531 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49533 restoreState : function(provider){
49535 provider = Roo.state.Manager;
49537 var sm = new Roo.LayoutStateManager();
49538 sm.init(this, provider);
49542 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49543 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49544 * a valid ContentPanel config object. Example:
49546 // Create the main layout
49547 var layout = new Roo.BorderLayout('main-ct', {
49558 // Create and add multiple ContentPanels at once via configs
49561 id: 'source-files',
49563 title:'Ext Source Files',
49576 * @param {Object} regions An object containing ContentPanel configs by region name
49578 batchAdd : function(regions){
49579 this.beginUpdate();
49580 for(var rname in regions){
49581 var lr = this.regions[rname];
49583 this.addTypedPanels(lr, regions[rname]);
49590 addTypedPanels : function(lr, ps){
49591 if(typeof ps == 'string'){
49592 lr.add(new Roo.ContentPanel(ps));
49594 else if(ps instanceof Array){
49595 for(var i =0, len = ps.length; i < len; i++){
49596 this.addTypedPanels(lr, ps[i]);
49599 else if(!ps.events){ // raw config?
49601 delete ps.el; // prevent conflict
49602 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49604 else { // panel object assumed!
49609 * Adds a xtype elements to the layout.
49613 xtype : 'ContentPanel',
49620 xtype : 'NestedLayoutPanel',
49626 items : [ ... list of content panels or nested layout panels.. ]
49630 * @param {Object} cfg Xtype definition of item to add.
49632 addxtype : function(cfg)
49634 // basically accepts a pannel...
49635 // can accept a layout region..!?!?
49636 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49638 if (!cfg.xtype.match(/Panel$/)) {
49643 if (typeof(cfg.region) == 'undefined') {
49644 Roo.log("Failed to add Panel, region was not set");
49648 var region = cfg.region;
49654 xitems = cfg.items;
49661 case 'ContentPanel': // ContentPanel (el, cfg)
49662 case 'ScrollPanel': // ContentPanel (el, cfg)
49664 if(cfg.autoCreate) {
49665 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49667 var el = this.el.createChild();
49668 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49671 this.add(region, ret);
49675 case 'TreePanel': // our new panel!
49676 cfg.el = this.el.createChild();
49677 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49678 this.add(region, ret);
49681 case 'NestedLayoutPanel':
49682 // create a new Layout (which is a Border Layout...
49683 var el = this.el.createChild();
49684 var clayout = cfg.layout;
49686 clayout.items = clayout.items || [];
49687 // replace this exitems with the clayout ones..
49688 xitems = clayout.items;
49691 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49692 cfg.background = false;
49694 var layout = new Roo.BorderLayout(el, clayout);
49696 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49697 //console.log('adding nested layout panel ' + cfg.toSource());
49698 this.add(region, ret);
49699 nb = {}; /// find first...
49704 // needs grid and region
49706 //var el = this.getRegion(region).el.createChild();
49707 var el = this.el.createChild();
49708 // create the grid first...
49710 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49712 if (region == 'center' && this.active ) {
49713 cfg.background = false;
49715 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49717 this.add(region, ret);
49718 if (cfg.background) {
49719 ret.on('activate', function(gp) {
49720 if (!gp.grid.rendered) {
49735 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49737 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49738 this.add(region, ret);
49741 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49745 // GridPanel (grid, cfg)
49748 this.beginUpdate();
49752 Roo.each(xitems, function(i) {
49753 region = nb && i.region ? i.region : false;
49755 var add = ret.addxtype(i);
49758 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49759 if (!i.background) {
49760 abn[region] = nb[region] ;
49767 // make the last non-background panel active..
49768 //if (nb) { Roo.log(abn); }
49771 for(var r in abn) {
49772 region = this.getRegion(r);
49774 // tried using nb[r], but it does not work..
49776 region.showPanel(abn[r]);
49787 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49788 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49789 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49790 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49793 var CP = Roo.ContentPanel;
49795 var layout = Roo.BorderLayout.create({
49799 panels: [new CP("north", "North")]
49808 panels: [new CP("west", {title: "West"})]
49817 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49826 panels: [new CP("south", {title: "South", closable: true})]
49833 preferredTabWidth: 150,
49835 new CP("center1", {title: "Close Me", closable: true}),
49836 new CP("center2", {title: "Center Panel", closable: false})
49841 layout.getRegion("center").showPanel("center1");
49846 Roo.BorderLayout.create = function(config, targetEl){
49847 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49848 layout.beginUpdate();
49849 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49850 for(var j = 0, jlen = regions.length; j < jlen; j++){
49851 var lr = regions[j];
49852 if(layout.regions[lr] && config[lr].panels){
49853 var r = layout.regions[lr];
49854 var ps = config[lr].panels;
49855 layout.addTypedPanels(r, ps);
49858 layout.endUpdate();
49863 Roo.BorderLayout.RegionFactory = {
49865 validRegions : ["north","south","east","west","center"],
49868 create : function(target, mgr, config){
49869 target = target.toLowerCase();
49870 if(config.lightweight || config.basic){
49871 return new Roo.BasicLayoutRegion(mgr, config, target);
49875 return new Roo.NorthLayoutRegion(mgr, config);
49877 return new Roo.SouthLayoutRegion(mgr, config);
49879 return new Roo.EastLayoutRegion(mgr, config);
49881 return new Roo.WestLayoutRegion(mgr, config);
49883 return new Roo.CenterLayoutRegion(mgr, config);
49885 throw 'Layout region "'+target+'" not supported.';
49889 * Ext JS Library 1.1.1
49890 * Copyright(c) 2006-2007, Ext JS, LLC.
49892 * Originally Released Under LGPL - original licence link has changed is not relivant.
49895 * <script type="text/javascript">
49899 * @class Roo.BasicLayoutRegion
49900 * @extends Roo.util.Observable
49901 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49902 * and does not have a titlebar, tabs or any other features. All it does is size and position
49903 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49905 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49907 this.position = pos;
49910 * @scope Roo.BasicLayoutRegion
49914 * @event beforeremove
49915 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49916 * @param {Roo.LayoutRegion} this
49917 * @param {Roo.ContentPanel} panel The panel
49918 * @param {Object} e The cancel event object
49920 "beforeremove" : true,
49922 * @event invalidated
49923 * Fires when the layout for this region is changed.
49924 * @param {Roo.LayoutRegion} this
49926 "invalidated" : true,
49928 * @event visibilitychange
49929 * Fires when this region is shown or hidden
49930 * @param {Roo.LayoutRegion} this
49931 * @param {Boolean} visibility true or false
49933 "visibilitychange" : true,
49935 * @event paneladded
49936 * Fires when a panel is added.
49937 * @param {Roo.LayoutRegion} this
49938 * @param {Roo.ContentPanel} panel The panel
49940 "paneladded" : true,
49942 * @event panelremoved
49943 * Fires when a panel is removed.
49944 * @param {Roo.LayoutRegion} this
49945 * @param {Roo.ContentPanel} panel The panel
49947 "panelremoved" : true,
49950 * Fires when this region is collapsed.
49951 * @param {Roo.LayoutRegion} this
49953 "collapsed" : true,
49956 * Fires when this region is expanded.
49957 * @param {Roo.LayoutRegion} this
49962 * Fires when this region is slid into view.
49963 * @param {Roo.LayoutRegion} this
49965 "slideshow" : true,
49968 * Fires when this region slides out of view.
49969 * @param {Roo.LayoutRegion} this
49971 "slidehide" : true,
49973 * @event panelactivated
49974 * Fires when a panel is activated.
49975 * @param {Roo.LayoutRegion} this
49976 * @param {Roo.ContentPanel} panel The activated panel
49978 "panelactivated" : true,
49981 * Fires when the user resizes this region.
49982 * @param {Roo.LayoutRegion} this
49983 * @param {Number} newSize The new size (width for east/west, height for north/south)
49987 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49988 this.panels = new Roo.util.MixedCollection();
49989 this.panels.getKey = this.getPanelId.createDelegate(this);
49991 this.activePanel = null;
49992 // ensure listeners are added...
49994 if (config.listeners || config.events) {
49995 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49996 listeners : config.listeners || {},
49997 events : config.events || {}
50001 if(skipConfig !== true){
50002 this.applyConfig(config);
50006 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
50007 getPanelId : function(p){
50011 applyConfig : function(config){
50012 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50013 this.config = config;
50018 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50019 * the width, for horizontal (north, south) the height.
50020 * @param {Number} newSize The new width or height
50022 resizeTo : function(newSize){
50023 var el = this.el ? this.el :
50024 (this.activePanel ? this.activePanel.getEl() : null);
50026 switch(this.position){
50029 el.setWidth(newSize);
50030 this.fireEvent("resized", this, newSize);
50034 el.setHeight(newSize);
50035 this.fireEvent("resized", this, newSize);
50041 getBox : function(){
50042 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50045 getMargins : function(){
50046 return this.margins;
50049 updateBox : function(box){
50051 var el = this.activePanel.getEl();
50052 el.dom.style.left = box.x + "px";
50053 el.dom.style.top = box.y + "px";
50054 this.activePanel.setSize(box.width, box.height);
50058 * Returns the container element for this region.
50059 * @return {Roo.Element}
50061 getEl : function(){
50062 return this.activePanel;
50066 * Returns true if this region is currently visible.
50067 * @return {Boolean}
50069 isVisible : function(){
50070 return this.activePanel ? true : false;
50073 setActivePanel : function(panel){
50074 panel = this.getPanel(panel);
50075 if(this.activePanel && this.activePanel != panel){
50076 this.activePanel.setActiveState(false);
50077 this.activePanel.getEl().setLeftTop(-10000,-10000);
50079 this.activePanel = panel;
50080 panel.setActiveState(true);
50082 panel.setSize(this.box.width, this.box.height);
50084 this.fireEvent("panelactivated", this, panel);
50085 this.fireEvent("invalidated");
50089 * Show the specified panel.
50090 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50091 * @return {Roo.ContentPanel} The shown panel or null
50093 showPanel : function(panel){
50094 if(panel = this.getPanel(panel)){
50095 this.setActivePanel(panel);
50101 * Get the active panel for this region.
50102 * @return {Roo.ContentPanel} The active panel or null
50104 getActivePanel : function(){
50105 return this.activePanel;
50109 * Add the passed ContentPanel(s)
50110 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50111 * @return {Roo.ContentPanel} The panel added (if only one was added)
50113 add : function(panel){
50114 if(arguments.length > 1){
50115 for(var i = 0, len = arguments.length; i < len; i++) {
50116 this.add(arguments[i]);
50120 if(this.hasPanel(panel)){
50121 this.showPanel(panel);
50124 var el = panel.getEl();
50125 if(el.dom.parentNode != this.mgr.el.dom){
50126 this.mgr.el.dom.appendChild(el.dom);
50128 if(panel.setRegion){
50129 panel.setRegion(this);
50131 this.panels.add(panel);
50132 el.setStyle("position", "absolute");
50133 if(!panel.background){
50134 this.setActivePanel(panel);
50135 if(this.config.initialSize && this.panels.getCount()==1){
50136 this.resizeTo(this.config.initialSize);
50139 this.fireEvent("paneladded", this, panel);
50144 * Returns true if the panel is in this region.
50145 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50146 * @return {Boolean}
50148 hasPanel : function(panel){
50149 if(typeof panel == "object"){ // must be panel obj
50150 panel = panel.getId();
50152 return this.getPanel(panel) ? true : false;
50156 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50157 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50158 * @param {Boolean} preservePanel Overrides the config preservePanel option
50159 * @return {Roo.ContentPanel} The panel that was removed
50161 remove : function(panel, preservePanel){
50162 panel = this.getPanel(panel);
50167 this.fireEvent("beforeremove", this, panel, e);
50168 if(e.cancel === true){
50171 var panelId = panel.getId();
50172 this.panels.removeKey(panelId);
50177 * Returns the panel specified or null if it's not in this region.
50178 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50179 * @return {Roo.ContentPanel}
50181 getPanel : function(id){
50182 if(typeof id == "object"){ // must be panel obj
50185 return this.panels.get(id);
50189 * Returns this regions position (north/south/east/west/center).
50192 getPosition: function(){
50193 return this.position;
50197 * Ext JS Library 1.1.1
50198 * Copyright(c) 2006-2007, Ext JS, LLC.
50200 * Originally Released Under LGPL - original licence link has changed is not relivant.
50203 * <script type="text/javascript">
50207 * @class Roo.LayoutRegion
50208 * @extends Roo.BasicLayoutRegion
50209 * This class represents a region in a layout manager.
50210 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50211 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50212 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50213 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50214 * @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})
50215 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50216 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50217 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50218 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50219 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50220 * @cfg {String} title The title for the region (overrides panel titles)
50221 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50222 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50223 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50224 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50225 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50226 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50227 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50228 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50229 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50230 * @cfg {Boolean} showPin True to show a pin button
50231 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50232 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50233 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50234 * @cfg {Number} width For East/West panels
50235 * @cfg {Number} height For North/South panels
50236 * @cfg {Boolean} split To show the splitter
50237 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50239 Roo.LayoutRegion = function(mgr, config, pos){
50240 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50241 var dh = Roo.DomHelper;
50242 /** This region's container element
50243 * @type Roo.Element */
50244 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50245 /** This region's title element
50246 * @type Roo.Element */
50248 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50249 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50250 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50252 this.titleEl.enableDisplayMode();
50253 /** This region's title text element
50254 * @type HTMLElement */
50255 this.titleTextEl = this.titleEl.dom.firstChild;
50256 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50257 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50258 this.closeBtn.enableDisplayMode();
50259 this.closeBtn.on("click", this.closeClicked, this);
50260 this.closeBtn.hide();
50262 this.createBody(config);
50263 this.visible = true;
50264 this.collapsed = false;
50266 if(config.hideWhenEmpty){
50268 this.on("paneladded", this.validateVisibility, this);
50269 this.on("panelremoved", this.validateVisibility, this);
50271 this.applyConfig(config);
50274 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50276 createBody : function(){
50277 /** This region's body element
50278 * @type Roo.Element */
50279 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50282 applyConfig : function(c){
50283 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50284 var dh = Roo.DomHelper;
50285 if(c.titlebar !== false){
50286 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50287 this.collapseBtn.on("click", this.collapse, this);
50288 this.collapseBtn.enableDisplayMode();
50290 if(c.showPin === true || this.showPin){
50291 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50292 this.stickBtn.enableDisplayMode();
50293 this.stickBtn.on("click", this.expand, this);
50294 this.stickBtn.hide();
50297 /** This region's collapsed element
50298 * @type Roo.Element */
50299 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50300 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50302 if(c.floatable !== false){
50303 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50304 this.collapsedEl.on("click", this.collapseClick, this);
50307 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50308 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50309 id: "message", unselectable: "on", style:{"float":"left"}});
50310 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50312 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50313 this.expandBtn.on("click", this.expand, this);
50315 if(this.collapseBtn){
50316 this.collapseBtn.setVisible(c.collapsible == true);
50318 this.cmargins = c.cmargins || this.cmargins ||
50319 (this.position == "west" || this.position == "east" ?
50320 {top: 0, left: 2, right:2, bottom: 0} :
50321 {top: 2, left: 0, right:0, bottom: 2});
50322 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50323 this.bottomTabs = c.tabPosition != "top";
50324 this.autoScroll = c.autoScroll || false;
50325 if(this.autoScroll){
50326 this.bodyEl.setStyle("overflow", "auto");
50328 this.bodyEl.setStyle("overflow", "hidden");
50330 //if(c.titlebar !== false){
50331 if((!c.titlebar && !c.title) || c.titlebar === false){
50332 this.titleEl.hide();
50334 this.titleEl.show();
50336 this.titleTextEl.innerHTML = c.title;
50340 this.duration = c.duration || .30;
50341 this.slideDuration = c.slideDuration || .45;
50344 this.collapse(true);
50351 * Returns true if this region is currently visible.
50352 * @return {Boolean}
50354 isVisible : function(){
50355 return this.visible;
50359 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50360 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50362 setCollapsedTitle : function(title){
50363 title = title || " ";
50364 if(this.collapsedTitleTextEl){
50365 this.collapsedTitleTextEl.innerHTML = title;
50369 getBox : function(){
50371 if(!this.collapsed){
50372 b = this.el.getBox(false, true);
50374 b = this.collapsedEl.getBox(false, true);
50379 getMargins : function(){
50380 return this.collapsed ? this.cmargins : this.margins;
50383 highlight : function(){
50384 this.el.addClass("x-layout-panel-dragover");
50387 unhighlight : function(){
50388 this.el.removeClass("x-layout-panel-dragover");
50391 updateBox : function(box){
50393 if(!this.collapsed){
50394 this.el.dom.style.left = box.x + "px";
50395 this.el.dom.style.top = box.y + "px";
50396 this.updateBody(box.width, box.height);
50398 this.collapsedEl.dom.style.left = box.x + "px";
50399 this.collapsedEl.dom.style.top = box.y + "px";
50400 this.collapsedEl.setSize(box.width, box.height);
50403 this.tabs.autoSizeTabs();
50407 updateBody : function(w, h){
50409 this.el.setWidth(w);
50410 w -= this.el.getBorderWidth("rl");
50411 if(this.config.adjustments){
50412 w += this.config.adjustments[0];
50416 this.el.setHeight(h);
50417 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50418 h -= this.el.getBorderWidth("tb");
50419 if(this.config.adjustments){
50420 h += this.config.adjustments[1];
50422 this.bodyEl.setHeight(h);
50424 h = this.tabs.syncHeight(h);
50427 if(this.panelSize){
50428 w = w !== null ? w : this.panelSize.width;
50429 h = h !== null ? h : this.panelSize.height;
50431 if(this.activePanel){
50432 var el = this.activePanel.getEl();
50433 w = w !== null ? w : el.getWidth();
50434 h = h !== null ? h : el.getHeight();
50435 this.panelSize = {width: w, height: h};
50436 this.activePanel.setSize(w, h);
50438 if(Roo.isIE && this.tabs){
50439 this.tabs.el.repaint();
50444 * Returns the container element for this region.
50445 * @return {Roo.Element}
50447 getEl : function(){
50452 * Hides this region.
50455 if(!this.collapsed){
50456 this.el.dom.style.left = "-2000px";
50459 this.collapsedEl.dom.style.left = "-2000px";
50460 this.collapsedEl.hide();
50462 this.visible = false;
50463 this.fireEvent("visibilitychange", this, false);
50467 * Shows this region if it was previously hidden.
50470 if(!this.collapsed){
50473 this.collapsedEl.show();
50475 this.visible = true;
50476 this.fireEvent("visibilitychange", this, true);
50479 closeClicked : function(){
50480 if(this.activePanel){
50481 this.remove(this.activePanel);
50485 collapseClick : function(e){
50487 e.stopPropagation();
50490 e.stopPropagation();
50496 * Collapses this region.
50497 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50499 collapse : function(skipAnim){
50500 if(this.collapsed) return;
50501 this.collapsed = true;
50503 this.split.el.hide();
50505 if(this.config.animate && skipAnim !== true){
50506 this.fireEvent("invalidated", this);
50507 this.animateCollapse();
50509 this.el.setLocation(-20000,-20000);
50511 this.collapsedEl.show();
50512 this.fireEvent("collapsed", this);
50513 this.fireEvent("invalidated", this);
50517 animateCollapse : function(){
50522 * Expands this region if it was previously collapsed.
50523 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50524 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50526 expand : function(e, skipAnim){
50527 if(e) e.stopPropagation();
50528 if(!this.collapsed || this.el.hasActiveFx()) return;
50530 this.afterSlideIn();
50533 this.collapsed = false;
50534 if(this.config.animate && skipAnim !== true){
50535 this.animateExpand();
50539 this.split.el.show();
50541 this.collapsedEl.setLocation(-2000,-2000);
50542 this.collapsedEl.hide();
50543 this.fireEvent("invalidated", this);
50544 this.fireEvent("expanded", this);
50548 animateExpand : function(){
50552 initTabs : function()
50554 this.bodyEl.setStyle("overflow", "hidden");
50555 var ts = new Roo.TabPanel(
50558 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50559 disableTooltips: this.config.disableTabTips,
50560 toolbar : this.config.toolbar
50563 if(this.config.hideTabs){
50564 ts.stripWrap.setDisplayed(false);
50567 ts.resizeTabs = this.config.resizeTabs === true;
50568 ts.minTabWidth = this.config.minTabWidth || 40;
50569 ts.maxTabWidth = this.config.maxTabWidth || 250;
50570 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50571 ts.monitorResize = false;
50572 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50573 ts.bodyEl.addClass('x-layout-tabs-body');
50574 this.panels.each(this.initPanelAsTab, this);
50577 initPanelAsTab : function(panel){
50578 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50579 this.config.closeOnTab && panel.isClosable());
50580 if(panel.tabTip !== undefined){
50581 ti.setTooltip(panel.tabTip);
50583 ti.on("activate", function(){
50584 this.setActivePanel(panel);
50586 if(this.config.closeOnTab){
50587 ti.on("beforeclose", function(t, e){
50589 this.remove(panel);
50595 updatePanelTitle : function(panel, title){
50596 if(this.activePanel == panel){
50597 this.updateTitle(title);
50600 var ti = this.tabs.getTab(panel.getEl().id);
50602 if(panel.tabTip !== undefined){
50603 ti.setTooltip(panel.tabTip);
50608 updateTitle : function(title){
50609 if(this.titleTextEl && !this.config.title){
50610 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50614 setActivePanel : function(panel){
50615 panel = this.getPanel(panel);
50616 if(this.activePanel && this.activePanel != panel){
50617 this.activePanel.setActiveState(false);
50619 this.activePanel = panel;
50620 panel.setActiveState(true);
50621 if(this.panelSize){
50622 panel.setSize(this.panelSize.width, this.panelSize.height);
50625 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50627 this.updateTitle(panel.getTitle());
50629 this.fireEvent("invalidated", this);
50631 this.fireEvent("panelactivated", this, panel);
50635 * Shows the specified panel.
50636 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50637 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50639 showPanel : function(panel)
50641 panel = this.getPanel(panel);
50644 var tab = this.tabs.getTab(panel.getEl().id);
50645 if(tab.isHidden()){
50646 this.tabs.unhideTab(tab.id);
50650 this.setActivePanel(panel);
50657 * Get the active panel for this region.
50658 * @return {Roo.ContentPanel} The active panel or null
50660 getActivePanel : function(){
50661 return this.activePanel;
50664 validateVisibility : function(){
50665 if(this.panels.getCount() < 1){
50666 this.updateTitle(" ");
50667 this.closeBtn.hide();
50670 if(!this.isVisible()){
50677 * Adds the passed ContentPanel(s) to this region.
50678 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50679 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50681 add : function(panel){
50682 if(arguments.length > 1){
50683 for(var i = 0, len = arguments.length; i < len; i++) {
50684 this.add(arguments[i]);
50688 if(this.hasPanel(panel)){
50689 this.showPanel(panel);
50692 panel.setRegion(this);
50693 this.panels.add(panel);
50694 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50695 this.bodyEl.dom.appendChild(panel.getEl().dom);
50696 if(panel.background !== true){
50697 this.setActivePanel(panel);
50699 this.fireEvent("paneladded", this, panel);
50705 this.initPanelAsTab(panel);
50707 if(panel.background !== true){
50708 this.tabs.activate(panel.getEl().id);
50710 this.fireEvent("paneladded", this, panel);
50715 * Hides the tab for the specified panel.
50716 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50718 hidePanel : function(panel){
50719 if(this.tabs && (panel = this.getPanel(panel))){
50720 this.tabs.hideTab(panel.getEl().id);
50725 * Unhides the tab for a previously hidden panel.
50726 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50728 unhidePanel : function(panel){
50729 if(this.tabs && (panel = this.getPanel(panel))){
50730 this.tabs.unhideTab(panel.getEl().id);
50734 clearPanels : function(){
50735 while(this.panels.getCount() > 0){
50736 this.remove(this.panels.first());
50741 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50742 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50743 * @param {Boolean} preservePanel Overrides the config preservePanel option
50744 * @return {Roo.ContentPanel} The panel that was removed
50746 remove : function(panel, preservePanel){
50747 panel = this.getPanel(panel);
50752 this.fireEvent("beforeremove", this, panel, e);
50753 if(e.cancel === true){
50756 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50757 var panelId = panel.getId();
50758 this.panels.removeKey(panelId);
50760 document.body.appendChild(panel.getEl().dom);
50763 this.tabs.removeTab(panel.getEl().id);
50764 }else if (!preservePanel){
50765 this.bodyEl.dom.removeChild(panel.getEl().dom);
50767 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50768 var p = this.panels.first();
50769 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50770 tempEl.appendChild(p.getEl().dom);
50771 this.bodyEl.update("");
50772 this.bodyEl.dom.appendChild(p.getEl().dom);
50774 this.updateTitle(p.getTitle());
50776 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50777 this.setActivePanel(p);
50779 panel.setRegion(null);
50780 if(this.activePanel == panel){
50781 this.activePanel = null;
50783 if(this.config.autoDestroy !== false && preservePanel !== true){
50784 try{panel.destroy();}catch(e){}
50786 this.fireEvent("panelremoved", this, panel);
50791 * Returns the TabPanel component used by this region
50792 * @return {Roo.TabPanel}
50794 getTabs : function(){
50798 createTool : function(parentEl, className){
50799 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50800 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50801 btn.addClassOnOver("x-layout-tools-button-over");
50806 * Ext JS Library 1.1.1
50807 * Copyright(c) 2006-2007, Ext JS, LLC.
50809 * Originally Released Under LGPL - original licence link has changed is not relivant.
50812 * <script type="text/javascript">
50818 * @class Roo.SplitLayoutRegion
50819 * @extends Roo.LayoutRegion
50820 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50822 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50823 this.cursor = cursor;
50824 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50827 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50828 splitTip : "Drag to resize.",
50829 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50830 useSplitTips : false,
50832 applyConfig : function(config){
50833 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50836 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50837 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50838 /** The SplitBar for this region
50839 * @type Roo.SplitBar */
50840 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50841 this.split.on("moved", this.onSplitMove, this);
50842 this.split.useShim = config.useShim === true;
50843 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50844 if(this.useSplitTips){
50845 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50847 if(config.collapsible){
50848 this.split.el.on("dblclick", this.collapse, this);
50851 if(typeof config.minSize != "undefined"){
50852 this.split.minSize = config.minSize;
50854 if(typeof config.maxSize != "undefined"){
50855 this.split.maxSize = config.maxSize;
50857 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50858 this.hideSplitter();
50863 getHMaxSize : function(){
50864 var cmax = this.config.maxSize || 10000;
50865 var center = this.mgr.getRegion("center");
50866 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50869 getVMaxSize : function(){
50870 var cmax = this.config.maxSize || 10000;
50871 var center = this.mgr.getRegion("center");
50872 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50875 onSplitMove : function(split, newSize){
50876 this.fireEvent("resized", this, newSize);
50880 * Returns the {@link Roo.SplitBar} for this region.
50881 * @return {Roo.SplitBar}
50883 getSplitBar : function(){
50888 this.hideSplitter();
50889 Roo.SplitLayoutRegion.superclass.hide.call(this);
50892 hideSplitter : function(){
50894 this.split.el.setLocation(-2000,-2000);
50895 this.split.el.hide();
50901 this.split.el.show();
50903 Roo.SplitLayoutRegion.superclass.show.call(this);
50906 beforeSlide: function(){
50907 if(Roo.isGecko){// firefox overflow auto bug workaround
50908 this.bodyEl.clip();
50909 if(this.tabs) this.tabs.bodyEl.clip();
50910 if(this.activePanel){
50911 this.activePanel.getEl().clip();
50913 if(this.activePanel.beforeSlide){
50914 this.activePanel.beforeSlide();
50920 afterSlide : function(){
50921 if(Roo.isGecko){// firefox overflow auto bug workaround
50922 this.bodyEl.unclip();
50923 if(this.tabs) this.tabs.bodyEl.unclip();
50924 if(this.activePanel){
50925 this.activePanel.getEl().unclip();
50926 if(this.activePanel.afterSlide){
50927 this.activePanel.afterSlide();
50933 initAutoHide : function(){
50934 if(this.autoHide !== false){
50935 if(!this.autoHideHd){
50936 var st = new Roo.util.DelayedTask(this.slideIn, this);
50937 this.autoHideHd = {
50938 "mouseout": function(e){
50939 if(!e.within(this.el, true)){
50943 "mouseover" : function(e){
50949 this.el.on(this.autoHideHd);
50953 clearAutoHide : function(){
50954 if(this.autoHide !== false){
50955 this.el.un("mouseout", this.autoHideHd.mouseout);
50956 this.el.un("mouseover", this.autoHideHd.mouseover);
50960 clearMonitor : function(){
50961 Roo.get(document).un("click", this.slideInIf, this);
50964 // these names are backwards but not changed for compat
50965 slideOut : function(){
50966 if(this.isSlid || this.el.hasActiveFx()){
50969 this.isSlid = true;
50970 if(this.collapseBtn){
50971 this.collapseBtn.hide();
50973 this.closeBtnState = this.closeBtn.getStyle('display');
50974 this.closeBtn.hide();
50976 this.stickBtn.show();
50979 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50980 this.beforeSlide();
50981 this.el.setStyle("z-index", 10001);
50982 this.el.slideIn(this.getSlideAnchor(), {
50983 callback: function(){
50985 this.initAutoHide();
50986 Roo.get(document).on("click", this.slideInIf, this);
50987 this.fireEvent("slideshow", this);
50994 afterSlideIn : function(){
50995 this.clearAutoHide();
50996 this.isSlid = false;
50997 this.clearMonitor();
50998 this.el.setStyle("z-index", "");
50999 if(this.collapseBtn){
51000 this.collapseBtn.show();
51002 this.closeBtn.setStyle('display', this.closeBtnState);
51004 this.stickBtn.hide();
51006 this.fireEvent("slidehide", this);
51009 slideIn : function(cb){
51010 if(!this.isSlid || this.el.hasActiveFx()){
51014 this.isSlid = false;
51015 this.beforeSlide();
51016 this.el.slideOut(this.getSlideAnchor(), {
51017 callback: function(){
51018 this.el.setLeftTop(-10000, -10000);
51020 this.afterSlideIn();
51028 slideInIf : function(e){
51029 if(!e.within(this.el)){
51034 animateCollapse : function(){
51035 this.beforeSlide();
51036 this.el.setStyle("z-index", 20000);
51037 var anchor = this.getSlideAnchor();
51038 this.el.slideOut(anchor, {
51039 callback : function(){
51040 this.el.setStyle("z-index", "");
51041 this.collapsedEl.slideIn(anchor, {duration:.3});
51043 this.el.setLocation(-10000,-10000);
51045 this.fireEvent("collapsed", this);
51052 animateExpand : function(){
51053 this.beforeSlide();
51054 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51055 this.el.setStyle("z-index", 20000);
51056 this.collapsedEl.hide({
51059 this.el.slideIn(this.getSlideAnchor(), {
51060 callback : function(){
51061 this.el.setStyle("z-index", "");
51064 this.split.el.show();
51066 this.fireEvent("invalidated", this);
51067 this.fireEvent("expanded", this);
51095 getAnchor : function(){
51096 return this.anchors[this.position];
51099 getCollapseAnchor : function(){
51100 return this.canchors[this.position];
51103 getSlideAnchor : function(){
51104 return this.sanchors[this.position];
51107 getAlignAdj : function(){
51108 var cm = this.cmargins;
51109 switch(this.position){
51125 getExpandAdj : function(){
51126 var c = this.collapsedEl, cm = this.cmargins;
51127 switch(this.position){
51129 return [-(cm.right+c.getWidth()+cm.left), 0];
51132 return [cm.right+c.getWidth()+cm.left, 0];
51135 return [0, -(cm.top+cm.bottom+c.getHeight())];
51138 return [0, cm.top+cm.bottom+c.getHeight()];
51144 * Ext JS Library 1.1.1
51145 * Copyright(c) 2006-2007, Ext JS, LLC.
51147 * Originally Released Under LGPL - original licence link has changed is not relivant.
51150 * <script type="text/javascript">
51153 * These classes are private internal classes
51155 Roo.CenterLayoutRegion = function(mgr, config){
51156 Roo.LayoutRegion.call(this, mgr, config, "center");
51157 this.visible = true;
51158 this.minWidth = config.minWidth || 20;
51159 this.minHeight = config.minHeight || 20;
51162 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51164 // center panel can't be hidden
51168 // center panel can't be hidden
51171 getMinWidth: function(){
51172 return this.minWidth;
51175 getMinHeight: function(){
51176 return this.minHeight;
51181 Roo.NorthLayoutRegion = function(mgr, config){
51182 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51184 this.split.placement = Roo.SplitBar.TOP;
51185 this.split.orientation = Roo.SplitBar.VERTICAL;
51186 this.split.el.addClass("x-layout-split-v");
51188 var size = config.initialSize || config.height;
51189 if(typeof size != "undefined"){
51190 this.el.setHeight(size);
51193 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51194 orientation: Roo.SplitBar.VERTICAL,
51195 getBox : function(){
51196 if(this.collapsed){
51197 return this.collapsedEl.getBox();
51199 var box = this.el.getBox();
51201 box.height += this.split.el.getHeight();
51206 updateBox : function(box){
51207 if(this.split && !this.collapsed){
51208 box.height -= this.split.el.getHeight();
51209 this.split.el.setLeft(box.x);
51210 this.split.el.setTop(box.y+box.height);
51211 this.split.el.setWidth(box.width);
51213 if(this.collapsed){
51214 this.updateBody(box.width, null);
51216 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51220 Roo.SouthLayoutRegion = function(mgr, config){
51221 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51223 this.split.placement = Roo.SplitBar.BOTTOM;
51224 this.split.orientation = Roo.SplitBar.VERTICAL;
51225 this.split.el.addClass("x-layout-split-v");
51227 var size = config.initialSize || config.height;
51228 if(typeof size != "undefined"){
51229 this.el.setHeight(size);
51232 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51233 orientation: Roo.SplitBar.VERTICAL,
51234 getBox : function(){
51235 if(this.collapsed){
51236 return this.collapsedEl.getBox();
51238 var box = this.el.getBox();
51240 var sh = this.split.el.getHeight();
51247 updateBox : function(box){
51248 if(this.split && !this.collapsed){
51249 var sh = this.split.el.getHeight();
51252 this.split.el.setLeft(box.x);
51253 this.split.el.setTop(box.y-sh);
51254 this.split.el.setWidth(box.width);
51256 if(this.collapsed){
51257 this.updateBody(box.width, null);
51259 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51263 Roo.EastLayoutRegion = function(mgr, config){
51264 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51266 this.split.placement = Roo.SplitBar.RIGHT;
51267 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51268 this.split.el.addClass("x-layout-split-h");
51270 var size = config.initialSize || config.width;
51271 if(typeof size != "undefined"){
51272 this.el.setWidth(size);
51275 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51276 orientation: Roo.SplitBar.HORIZONTAL,
51277 getBox : function(){
51278 if(this.collapsed){
51279 return this.collapsedEl.getBox();
51281 var box = this.el.getBox();
51283 var sw = this.split.el.getWidth();
51290 updateBox : function(box){
51291 if(this.split && !this.collapsed){
51292 var sw = this.split.el.getWidth();
51294 this.split.el.setLeft(box.x);
51295 this.split.el.setTop(box.y);
51296 this.split.el.setHeight(box.height);
51299 if(this.collapsed){
51300 this.updateBody(null, box.height);
51302 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51306 Roo.WestLayoutRegion = function(mgr, config){
51307 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51309 this.split.placement = Roo.SplitBar.LEFT;
51310 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51311 this.split.el.addClass("x-layout-split-h");
51313 var size = config.initialSize || config.width;
51314 if(typeof size != "undefined"){
51315 this.el.setWidth(size);
51318 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51319 orientation: Roo.SplitBar.HORIZONTAL,
51320 getBox : function(){
51321 if(this.collapsed){
51322 return this.collapsedEl.getBox();
51324 var box = this.el.getBox();
51326 box.width += this.split.el.getWidth();
51331 updateBox : function(box){
51332 if(this.split && !this.collapsed){
51333 var sw = this.split.el.getWidth();
51335 this.split.el.setLeft(box.x+box.width);
51336 this.split.el.setTop(box.y);
51337 this.split.el.setHeight(box.height);
51339 if(this.collapsed){
51340 this.updateBody(null, box.height);
51342 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51347 * Ext JS Library 1.1.1
51348 * Copyright(c) 2006-2007, Ext JS, LLC.
51350 * Originally Released Under LGPL - original licence link has changed is not relivant.
51353 * <script type="text/javascript">
51358 * Private internal class for reading and applying state
51360 Roo.LayoutStateManager = function(layout){
51361 // default empty state
51370 Roo.LayoutStateManager.prototype = {
51371 init : function(layout, provider){
51372 this.provider = provider;
51373 var state = provider.get(layout.id+"-layout-state");
51375 var wasUpdating = layout.isUpdating();
51377 layout.beginUpdate();
51379 for(var key in state){
51380 if(typeof state[key] != "function"){
51381 var rstate = state[key];
51382 var r = layout.getRegion(key);
51385 r.resizeTo(rstate.size);
51387 if(rstate.collapsed == true){
51390 r.expand(null, true);
51396 layout.endUpdate();
51398 this.state = state;
51400 this.layout = layout;
51401 layout.on("regionresized", this.onRegionResized, this);
51402 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51403 layout.on("regionexpanded", this.onRegionExpanded, this);
51406 storeState : function(){
51407 this.provider.set(this.layout.id+"-layout-state", this.state);
51410 onRegionResized : function(region, newSize){
51411 this.state[region.getPosition()].size = newSize;
51415 onRegionCollapsed : function(region){
51416 this.state[region.getPosition()].collapsed = true;
51420 onRegionExpanded : function(region){
51421 this.state[region.getPosition()].collapsed = false;
51426 * Ext JS Library 1.1.1
51427 * Copyright(c) 2006-2007, Ext JS, LLC.
51429 * Originally Released Under LGPL - original licence link has changed is not relivant.
51432 * <script type="text/javascript">
51435 * @class Roo.ContentPanel
51436 * @extends Roo.util.Observable
51437 * A basic ContentPanel element.
51438 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51439 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51440 * @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
51441 * @cfg {Boolean} closable True if the panel can be closed/removed
51442 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51443 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51444 * @cfg {Toolbar} toolbar A toolbar for this panel
51445 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51446 * @cfg {String} title The title for this panel
51447 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51448 * @cfg {String} url Calls {@link #setUrl} with this value
51449 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51450 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51451 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51452 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51455 * Create a new ContentPanel.
51456 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51457 * @param {String/Object} config A string to set only the title or a config object
51458 * @param {String} content (optional) Set the HTML content for this panel
51459 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51461 Roo.ContentPanel = function(el, config, content){
51465 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51469 if (config && config.parentLayout) {
51470 el = config.parentLayout.el.createChild();
51473 if(el.autoCreate){ // xtype is available if this is called from factory
51477 this.el = Roo.get(el);
51478 if(!this.el && config && config.autoCreate){
51479 if(typeof config.autoCreate == "object"){
51480 if(!config.autoCreate.id){
51481 config.autoCreate.id = config.id||el;
51483 this.el = Roo.DomHelper.append(document.body,
51484 config.autoCreate, true);
51486 this.el = Roo.DomHelper.append(document.body,
51487 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51490 this.closable = false;
51491 this.loaded = false;
51492 this.active = false;
51493 if(typeof config == "string"){
51494 this.title = config;
51496 Roo.apply(this, config);
51499 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51500 this.wrapEl = this.el.wrap();
51501 this.toolbar.container = this.el.insertSibling(false, 'before');
51502 this.toolbar = new Roo.Toolbar(this.toolbar);
51505 // xtype created footer. - not sure if will work as we normally have to render first..
51506 if (this.footer && !this.footer.el && this.footer.xtype) {
51507 if (!this.wrapEl) {
51508 this.wrapEl = this.el.wrap();
51511 this.footer.container = this.wrapEl.createChild();
51513 this.footer = Roo.factory(this.footer, Roo);
51518 this.resizeEl = Roo.get(this.resizeEl, true);
51520 this.resizeEl = this.el;
51522 // handle view.xtype
51530 * Fires when this panel is activated.
51531 * @param {Roo.ContentPanel} this
51535 * @event deactivate
51536 * Fires when this panel is activated.
51537 * @param {Roo.ContentPanel} this
51539 "deactivate" : true,
51543 * Fires when this panel is resized if fitToFrame is true.
51544 * @param {Roo.ContentPanel} this
51545 * @param {Number} width The width after any component adjustments
51546 * @param {Number} height The height after any component adjustments
51552 * Fires when this tab is created
51553 * @param {Roo.ContentPanel} this
51564 if(this.autoScroll){
51565 this.resizeEl.setStyle("overflow", "auto");
51567 // fix randome scrolling
51568 this.el.on('scroll', function() {
51569 Roo.log('fix random scolling');
51570 this.scrollTo('top',0);
51573 content = content || this.content;
51575 this.setContent(content);
51577 if(config && config.url){
51578 this.setUrl(this.url, this.params, this.loadOnce);
51583 Roo.ContentPanel.superclass.constructor.call(this);
51585 if (this.view && typeof(this.view.xtype) != 'undefined') {
51586 this.view.el = this.el.appendChild(document.createElement("div"));
51587 this.view = Roo.factory(this.view);
51588 this.view.render && this.view.render(false, '');
51592 this.fireEvent('render', this);
51595 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51597 setRegion : function(region){
51598 this.region = region;
51600 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51602 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51607 * Returns the toolbar for this Panel if one was configured.
51608 * @return {Roo.Toolbar}
51610 getToolbar : function(){
51611 return this.toolbar;
51614 setActiveState : function(active){
51615 this.active = active;
51617 this.fireEvent("deactivate", this);
51619 this.fireEvent("activate", this);
51623 * Updates this panel's element
51624 * @param {String} content The new content
51625 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51627 setContent : function(content, loadScripts){
51628 this.el.update(content, loadScripts);
51631 ignoreResize : function(w, h){
51632 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51635 this.lastSize = {width: w, height: h};
51640 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51641 * @return {Roo.UpdateManager} The UpdateManager
51643 getUpdateManager : function(){
51644 return this.el.getUpdateManager();
51647 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51648 * @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:
51651 url: "your-url.php",
51652 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51653 callback: yourFunction,
51654 scope: yourObject, //(optional scope)
51657 text: "Loading...",
51662 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51663 * 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.
51664 * @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}
51665 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51666 * @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.
51667 * @return {Roo.ContentPanel} this
51670 var um = this.el.getUpdateManager();
51671 um.update.apply(um, arguments);
51677 * 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.
51678 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51679 * @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)
51680 * @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)
51681 * @return {Roo.UpdateManager} The UpdateManager
51683 setUrl : function(url, params, loadOnce){
51684 if(this.refreshDelegate){
51685 this.removeListener("activate", this.refreshDelegate);
51687 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51688 this.on("activate", this.refreshDelegate);
51689 return this.el.getUpdateManager();
51692 _handleRefresh : function(url, params, loadOnce){
51693 if(!loadOnce || !this.loaded){
51694 var updater = this.el.getUpdateManager();
51695 updater.update(url, params, this._setLoaded.createDelegate(this));
51699 _setLoaded : function(){
51700 this.loaded = true;
51704 * Returns this panel's id
51707 getId : function(){
51712 * Returns this panel's element - used by regiosn to add.
51713 * @return {Roo.Element}
51715 getEl : function(){
51716 return this.wrapEl || this.el;
51719 adjustForComponents : function(width, height)
51721 //Roo.log('adjustForComponents ');
51722 if(this.resizeEl != this.el){
51723 width -= this.el.getFrameWidth('lr');
51724 height -= this.el.getFrameWidth('tb');
51727 var te = this.toolbar.getEl();
51728 height -= te.getHeight();
51729 te.setWidth(width);
51732 var te = this.footer.getEl();
51733 Roo.log("footer:" + te.getHeight());
51735 height -= te.getHeight();
51736 te.setWidth(width);
51740 if(this.adjustments){
51741 width += this.adjustments[0];
51742 height += this.adjustments[1];
51744 return {"width": width, "height": height};
51747 setSize : function(width, height){
51748 if(this.fitToFrame && !this.ignoreResize(width, height)){
51749 if(this.fitContainer && this.resizeEl != this.el){
51750 this.el.setSize(width, height);
51752 var size = this.adjustForComponents(width, height);
51753 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51754 this.fireEvent('resize', this, size.width, size.height);
51759 * Returns this panel's title
51762 getTitle : function(){
51767 * Set this panel's title
51768 * @param {String} title
51770 setTitle : function(title){
51771 this.title = title;
51773 this.region.updatePanelTitle(this, title);
51778 * Returns true is this panel was configured to be closable
51779 * @return {Boolean}
51781 isClosable : function(){
51782 return this.closable;
51785 beforeSlide : function(){
51787 this.resizeEl.clip();
51790 afterSlide : function(){
51792 this.resizeEl.unclip();
51796 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51797 * Will fail silently if the {@link #setUrl} method has not been called.
51798 * This does not activate the panel, just updates its content.
51800 refresh : function(){
51801 if(this.refreshDelegate){
51802 this.loaded = false;
51803 this.refreshDelegate();
51808 * Destroys this panel
51810 destroy : function(){
51811 this.el.removeAllListeners();
51812 var tempEl = document.createElement("span");
51813 tempEl.appendChild(this.el.dom);
51814 tempEl.innerHTML = "";
51820 * form - if the content panel contains a form - this is a reference to it.
51821 * @type {Roo.form.Form}
51825 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51826 * This contains a reference to it.
51832 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51842 * @param {Object} cfg Xtype definition of item to add.
51845 addxtype : function(cfg) {
51847 if (cfg.xtype.match(/^Form$/)) {
51850 //if (this.footer) {
51851 // el = this.footer.container.insertSibling(false, 'before');
51853 el = this.el.createChild();
51856 this.form = new Roo.form.Form(cfg);
51859 if ( this.form.allItems.length) this.form.render(el.dom);
51862 // should only have one of theses..
51863 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51864 // views.. should not be just added - used named prop 'view''
51866 cfg.el = this.el.appendChild(document.createElement("div"));
51869 var ret = new Roo.factory(cfg);
51871 ret.render && ret.render(false, ''); // render blank..
51880 * @class Roo.GridPanel
51881 * @extends Roo.ContentPanel
51883 * Create a new GridPanel.
51884 * @param {Roo.grid.Grid} grid The grid for this panel
51885 * @param {String/Object} config A string to set only the panel's title, or a config object
51887 Roo.GridPanel = function(grid, config){
51890 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51891 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51893 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51895 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51898 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51900 // xtype created footer. - not sure if will work as we normally have to render first..
51901 if (this.footer && !this.footer.el && this.footer.xtype) {
51903 this.footer.container = this.grid.getView().getFooterPanel(true);
51904 this.footer.dataSource = this.grid.dataSource;
51905 this.footer = Roo.factory(this.footer, Roo);
51909 grid.monitorWindowResize = false; // turn off autosizing
51910 grid.autoHeight = false;
51911 grid.autoWidth = false;
51913 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51916 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51917 getId : function(){
51918 return this.grid.id;
51922 * Returns the grid for this panel
51923 * @return {Roo.grid.Grid}
51925 getGrid : function(){
51929 setSize : function(width, height){
51930 if(!this.ignoreResize(width, height)){
51931 var grid = this.grid;
51932 var size = this.adjustForComponents(width, height);
51933 grid.getGridEl().setSize(size.width, size.height);
51938 beforeSlide : function(){
51939 this.grid.getView().scroller.clip();
51942 afterSlide : function(){
51943 this.grid.getView().scroller.unclip();
51946 destroy : function(){
51947 this.grid.destroy();
51949 Roo.GridPanel.superclass.destroy.call(this);
51955 * @class Roo.NestedLayoutPanel
51956 * @extends Roo.ContentPanel
51958 * Create a new NestedLayoutPanel.
51961 * @param {Roo.BorderLayout} layout The layout for this panel
51962 * @param {String/Object} config A string to set only the title or a config object
51964 Roo.NestedLayoutPanel = function(layout, config)
51966 // construct with only one argument..
51967 /* FIXME - implement nicer consturctors
51968 if (layout.layout) {
51970 layout = config.layout;
51971 delete config.layout;
51973 if (layout.xtype && !layout.getEl) {
51974 // then layout needs constructing..
51975 layout = Roo.factory(layout, Roo);
51980 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51982 layout.monitorWindowResize = false; // turn off autosizing
51983 this.layout = layout;
51984 this.layout.getEl().addClass("x-layout-nested-layout");
51991 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51993 setSize : function(width, height){
51994 if(!this.ignoreResize(width, height)){
51995 var size = this.adjustForComponents(width, height);
51996 var el = this.layout.getEl();
51997 el.setSize(size.width, size.height);
51998 var touch = el.dom.offsetWidth;
51999 this.layout.layout();
52000 // ie requires a double layout on the first pass
52001 if(Roo.isIE && !this.initialized){
52002 this.initialized = true;
52003 this.layout.layout();
52008 // activate all subpanels if not currently active..
52010 setActiveState : function(active){
52011 this.active = active;
52013 this.fireEvent("deactivate", this);
52017 this.fireEvent("activate", this);
52018 // not sure if this should happen before or after..
52019 if (!this.layout) {
52020 return; // should not happen..
52023 for (var r in this.layout.regions) {
52024 reg = this.layout.getRegion(r);
52025 if (reg.getActivePanel()) {
52026 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52027 reg.setActivePanel(reg.getActivePanel());
52030 if (!reg.panels.length) {
52033 reg.showPanel(reg.getPanel(0));
52042 * Returns the nested BorderLayout for this panel
52043 * @return {Roo.BorderLayout}
52045 getLayout : function(){
52046 return this.layout;
52050 * Adds a xtype elements to the layout of the nested panel
52054 xtype : 'ContentPanel',
52061 xtype : 'NestedLayoutPanel',
52067 items : [ ... list of content panels or nested layout panels.. ]
52071 * @param {Object} cfg Xtype definition of item to add.
52073 addxtype : function(cfg) {
52074 return this.layout.addxtype(cfg);
52079 Roo.ScrollPanel = function(el, config, content){
52080 config = config || {};
52081 config.fitToFrame = true;
52082 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52084 this.el.dom.style.overflow = "hidden";
52085 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52086 this.el.removeClass("x-layout-inactive-content");
52087 this.el.on("mousewheel", this.onWheel, this);
52089 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52090 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52091 up.unselectable(); down.unselectable();
52092 up.on("click", this.scrollUp, this);
52093 down.on("click", this.scrollDown, this);
52094 up.addClassOnOver("x-scroller-btn-over");
52095 down.addClassOnOver("x-scroller-btn-over");
52096 up.addClassOnClick("x-scroller-btn-click");
52097 down.addClassOnClick("x-scroller-btn-click");
52098 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52100 this.resizeEl = this.el;
52101 this.el = wrap; this.up = up; this.down = down;
52104 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52106 wheelIncrement : 5,
52107 scrollUp : function(){
52108 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52111 scrollDown : function(){
52112 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52115 afterScroll : function(){
52116 var el = this.resizeEl;
52117 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52118 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52119 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52122 setSize : function(){
52123 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52124 this.afterScroll();
52127 onWheel : function(e){
52128 var d = e.getWheelDelta();
52129 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52130 this.afterScroll();
52134 setContent : function(content, loadScripts){
52135 this.resizeEl.update(content, loadScripts);
52149 * @class Roo.TreePanel
52150 * @extends Roo.ContentPanel
52152 * Create a new TreePanel. - defaults to fit/scoll contents.
52153 * @param {String/Object} config A string to set only the panel's title, or a config object
52154 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52156 Roo.TreePanel = function(config){
52157 var el = config.el;
52158 var tree = config.tree;
52159 delete config.tree;
52160 delete config.el; // hopefull!
52162 // wrapper for IE7 strict & safari scroll issue
52164 var treeEl = el.createChild();
52165 config.resizeEl = treeEl;
52169 Roo.TreePanel.superclass.constructor.call(this, el, config);
52172 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52173 //console.log(tree);
52174 this.on('activate', function()
52176 if (this.tree.rendered) {
52179 //console.log('render tree');
52180 this.tree.render();
52182 // this should not be needed.. - it's actually the 'el' that resizes?
52183 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52185 //this.on('resize', function (cp, w, h) {
52186 // this.tree.innerCt.setWidth(w);
52187 // this.tree.innerCt.setHeight(h);
52188 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52195 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52212 * Ext JS Library 1.1.1
52213 * Copyright(c) 2006-2007, Ext JS, LLC.
52215 * Originally Released Under LGPL - original licence link has changed is not relivant.
52218 * <script type="text/javascript">
52223 * @class Roo.ReaderLayout
52224 * @extends Roo.BorderLayout
52225 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52226 * center region containing two nested regions (a top one for a list view and one for item preview below),
52227 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52228 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52229 * expedites the setup of the overall layout and regions for this common application style.
52232 var reader = new Roo.ReaderLayout();
52233 var CP = Roo.ContentPanel; // shortcut for adding
52235 reader.beginUpdate();
52236 reader.add("north", new CP("north", "North"));
52237 reader.add("west", new CP("west", {title: "West"}));
52238 reader.add("east", new CP("east", {title: "East"}));
52240 reader.regions.listView.add(new CP("listView", "List"));
52241 reader.regions.preview.add(new CP("preview", "Preview"));
52242 reader.endUpdate();
52245 * Create a new ReaderLayout
52246 * @param {Object} config Configuration options
52247 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52248 * document.body if omitted)
52250 Roo.ReaderLayout = function(config, renderTo){
52251 var c = config || {size:{}};
52252 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52253 north: c.north !== false ? Roo.apply({
52257 }, c.north) : false,
52258 west: c.west !== false ? Roo.apply({
52266 margins:{left:5,right:0,bottom:5,top:5},
52267 cmargins:{left:5,right:5,bottom:5,top:5}
52268 }, c.west) : false,
52269 east: c.east !== false ? Roo.apply({
52277 margins:{left:0,right:5,bottom:5,top:5},
52278 cmargins:{left:5,right:5,bottom:5,top:5}
52279 }, c.east) : false,
52280 center: Roo.apply({
52281 tabPosition: 'top',
52285 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52289 this.el.addClass('x-reader');
52291 this.beginUpdate();
52293 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52294 south: c.preview !== false ? Roo.apply({
52301 cmargins:{top:5,left:0, right:0, bottom:0}
52302 }, c.preview) : false,
52303 center: Roo.apply({
52309 this.add('center', new Roo.NestedLayoutPanel(inner,
52310 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52314 this.regions.preview = inner.getRegion('south');
52315 this.regions.listView = inner.getRegion('center');
52318 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52320 * Ext JS Library 1.1.1
52321 * Copyright(c) 2006-2007, Ext JS, LLC.
52323 * Originally Released Under LGPL - original licence link has changed is not relivant.
52326 * <script type="text/javascript">
52330 * @class Roo.grid.Grid
52331 * @extends Roo.util.Observable
52332 * This class represents the primary interface of a component based grid control.
52333 * <br><br>Usage:<pre><code>
52334 var grid = new Roo.grid.Grid("my-container-id", {
52337 selModel: mySelectionModel,
52338 autoSizeColumns: true,
52339 monitorWindowResize: false,
52340 trackMouseOver: true
52345 * <b>Common Problems:</b><br/>
52346 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52347 * element will correct this<br/>
52348 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52349 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52350 * are unpredictable.<br/>
52351 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52352 * grid to calculate dimensions/offsets.<br/>
52354 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52355 * The container MUST have some type of size defined for the grid to fill. The container will be
52356 * automatically set to position relative if it isn't already.
52357 * @param {Object} config A config object that sets properties on this grid.
52359 Roo.grid.Grid = function(container, config){
52360 // initialize the container
52361 this.container = Roo.get(container);
52362 this.container.update("");
52363 this.container.setStyle("overflow", "hidden");
52364 this.container.addClass('x-grid-container');
52366 this.id = this.container.id;
52368 Roo.apply(this, config);
52369 // check and correct shorthanded configs
52371 this.dataSource = this.ds;
52375 this.colModel = this.cm;
52379 this.selModel = this.sm;
52383 if (this.selModel) {
52384 this.selModel = Roo.factory(this.selModel, Roo.grid);
52385 this.sm = this.selModel;
52386 this.sm.xmodule = this.xmodule || false;
52388 if (typeof(this.colModel.config) == 'undefined') {
52389 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52390 this.cm = this.colModel;
52391 this.cm.xmodule = this.xmodule || false;
52393 if (this.dataSource) {
52394 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52395 this.ds = this.dataSource;
52396 this.ds.xmodule = this.xmodule || false;
52403 this.container.setWidth(this.width);
52407 this.container.setHeight(this.height);
52414 * The raw click event for the entire grid.
52415 * @param {Roo.EventObject} e
52420 * The raw dblclick event for the entire grid.
52421 * @param {Roo.EventObject} e
52425 * @event contextmenu
52426 * The raw contextmenu event for the entire grid.
52427 * @param {Roo.EventObject} e
52429 "contextmenu" : true,
52432 * The raw mousedown event for the entire grid.
52433 * @param {Roo.EventObject} e
52435 "mousedown" : true,
52438 * The raw mouseup event for the entire grid.
52439 * @param {Roo.EventObject} e
52444 * The raw mouseover event for the entire grid.
52445 * @param {Roo.EventObject} e
52447 "mouseover" : true,
52450 * The raw mouseout event for the entire grid.
52451 * @param {Roo.EventObject} e
52456 * The raw keypress event for the entire grid.
52457 * @param {Roo.EventObject} e
52462 * The raw keydown event for the entire grid.
52463 * @param {Roo.EventObject} e
52471 * Fires when a cell is clicked
52472 * @param {Grid} this
52473 * @param {Number} rowIndex
52474 * @param {Number} columnIndex
52475 * @param {Roo.EventObject} e
52477 "cellclick" : true,
52479 * @event celldblclick
52480 * Fires when a cell is double clicked
52481 * @param {Grid} this
52482 * @param {Number} rowIndex
52483 * @param {Number} columnIndex
52484 * @param {Roo.EventObject} e
52486 "celldblclick" : true,
52489 * Fires when a row is clicked
52490 * @param {Grid} this
52491 * @param {Number} rowIndex
52492 * @param {Roo.EventObject} e
52496 * @event rowdblclick
52497 * Fires when a row is double clicked
52498 * @param {Grid} this
52499 * @param {Number} rowIndex
52500 * @param {Roo.EventObject} e
52502 "rowdblclick" : true,
52504 * @event headerclick
52505 * Fires when a header is clicked
52506 * @param {Grid} this
52507 * @param {Number} columnIndex
52508 * @param {Roo.EventObject} e
52510 "headerclick" : true,
52512 * @event headerdblclick
52513 * Fires when a header cell is double clicked
52514 * @param {Grid} this
52515 * @param {Number} columnIndex
52516 * @param {Roo.EventObject} e
52518 "headerdblclick" : true,
52520 * @event rowcontextmenu
52521 * Fires when a row is right clicked
52522 * @param {Grid} this
52523 * @param {Number} rowIndex
52524 * @param {Roo.EventObject} e
52526 "rowcontextmenu" : true,
52528 * @event cellcontextmenu
52529 * Fires when a cell is right clicked
52530 * @param {Grid} this
52531 * @param {Number} rowIndex
52532 * @param {Number} cellIndex
52533 * @param {Roo.EventObject} e
52535 "cellcontextmenu" : true,
52537 * @event headercontextmenu
52538 * Fires when a header is right clicked
52539 * @param {Grid} this
52540 * @param {Number} columnIndex
52541 * @param {Roo.EventObject} e
52543 "headercontextmenu" : true,
52545 * @event bodyscroll
52546 * Fires when the body element is scrolled
52547 * @param {Number} scrollLeft
52548 * @param {Number} scrollTop
52550 "bodyscroll" : true,
52552 * @event columnresize
52553 * Fires when the user resizes a column
52554 * @param {Number} columnIndex
52555 * @param {Number} newSize
52557 "columnresize" : true,
52559 * @event columnmove
52560 * Fires when the user moves a column
52561 * @param {Number} oldIndex
52562 * @param {Number} newIndex
52564 "columnmove" : true,
52567 * Fires when row(s) start being dragged
52568 * @param {Grid} this
52569 * @param {Roo.GridDD} dd The drag drop object
52570 * @param {event} e The raw browser event
52572 "startdrag" : true,
52575 * Fires when a drag operation is complete
52576 * @param {Grid} this
52577 * @param {Roo.GridDD} dd The drag drop object
52578 * @param {event} e The raw browser event
52583 * Fires when dragged row(s) are dropped on a valid DD target
52584 * @param {Grid} this
52585 * @param {Roo.GridDD} dd The drag drop object
52586 * @param {String} targetId The target drag drop object
52587 * @param {event} e The raw browser event
52592 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52593 * @param {Grid} this
52594 * @param {Roo.GridDD} dd The drag drop object
52595 * @param {String} targetId The target drag drop object
52596 * @param {event} e The raw browser event
52601 * Fires when the dragged row(s) first cross another DD target while being dragged
52602 * @param {Grid} this
52603 * @param {Roo.GridDD} dd The drag drop object
52604 * @param {String} targetId The target drag drop object
52605 * @param {event} e The raw browser event
52607 "dragenter" : true,
52610 * Fires when the dragged row(s) leave another DD target while being dragged
52611 * @param {Grid} this
52612 * @param {Roo.GridDD} dd The drag drop object
52613 * @param {String} targetId The target drag drop object
52614 * @param {event} e The raw browser event
52619 * Fires when a row is rendered, so you can change add a style to it.
52620 * @param {GridView} gridview The grid view
52621 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52627 * Fires when the grid is rendered
52628 * @param {Grid} grid
52633 Roo.grid.Grid.superclass.constructor.call(this);
52635 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52638 * @cfg {String} ddGroup - drag drop group.
52642 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52644 minColumnWidth : 25,
52647 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52648 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52649 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52651 autoSizeColumns : false,
52654 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52656 autoSizeHeaders : true,
52659 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52661 monitorWindowResize : true,
52664 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52665 * rows measured to get a columns size. Default is 0 (all rows).
52667 maxRowsToMeasure : 0,
52670 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52672 trackMouseOver : true,
52675 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52679 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52681 enableDragDrop : false,
52684 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52686 enableColumnMove : true,
52689 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52691 enableColumnHide : true,
52694 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52696 enableRowHeightSync : false,
52699 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52704 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52706 autoHeight : false,
52709 * @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.
52711 autoExpandColumn : false,
52714 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52717 autoExpandMin : 50,
52720 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52722 autoExpandMax : 1000,
52725 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52730 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52734 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52744 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52745 * of a fixed width. Default is false.
52748 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52751 * Called once after all setup has been completed and the grid is ready to be rendered.
52752 * @return {Roo.grid.Grid} this
52754 render : function()
52756 var c = this.container;
52757 // try to detect autoHeight/width mode
52758 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52759 this.autoHeight = true;
52761 var view = this.getView();
52764 c.on("click", this.onClick, this);
52765 c.on("dblclick", this.onDblClick, this);
52766 c.on("contextmenu", this.onContextMenu, this);
52767 c.on("keydown", this.onKeyDown, this);
52769 c.on("touchstart", this.onTouchStart, this);
52772 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52774 this.getSelectionModel().init(this);
52779 this.loadMask = new Roo.LoadMask(this.container,
52780 Roo.apply({store:this.dataSource}, this.loadMask));
52784 if (this.toolbar && this.toolbar.xtype) {
52785 this.toolbar.container = this.getView().getHeaderPanel(true);
52786 this.toolbar = new Roo.Toolbar(this.toolbar);
52788 if (this.footer && this.footer.xtype) {
52789 this.footer.dataSource = this.getDataSource();
52790 this.footer.container = this.getView().getFooterPanel(true);
52791 this.footer = Roo.factory(this.footer, Roo);
52793 if (this.dropTarget && this.dropTarget.xtype) {
52794 delete this.dropTarget.xtype;
52795 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52799 this.rendered = true;
52800 this.fireEvent('render', this);
52805 * Reconfigures the grid to use a different Store and Column Model.
52806 * The View will be bound to the new objects and refreshed.
52807 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52808 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52810 reconfigure : function(dataSource, colModel){
52812 this.loadMask.destroy();
52813 this.loadMask = new Roo.LoadMask(this.container,
52814 Roo.apply({store:dataSource}, this.loadMask));
52816 this.view.bind(dataSource, colModel);
52817 this.dataSource = dataSource;
52818 this.colModel = colModel;
52819 this.view.refresh(true);
52823 onKeyDown : function(e){
52824 this.fireEvent("keydown", e);
52828 * Destroy this grid.
52829 * @param {Boolean} removeEl True to remove the element
52831 destroy : function(removeEl, keepListeners){
52833 this.loadMask.destroy();
52835 var c = this.container;
52836 c.removeAllListeners();
52837 this.view.destroy();
52838 this.colModel.purgeListeners();
52839 if(!keepListeners){
52840 this.purgeListeners();
52843 if(removeEl === true){
52849 processEvent : function(name, e){
52850 // does this fire select???
52851 //Roo.log('grid:processEvent ' + name);
52853 if (name != 'touchstart' ) {
52854 this.fireEvent(name, e);
52857 var t = e.getTarget();
52859 var header = v.findHeaderIndex(t);
52860 if(header !== false){
52861 var ename = name == 'touchstart' ? 'click' : name;
52863 this.fireEvent("header" + ename, this, header, e);
52865 var row = v.findRowIndex(t);
52866 var cell = v.findCellIndex(t);
52867 if (name == 'touchstart') {
52868 // first touch is always a click.
52869 // hopefull this happens after selection is updated.?
52872 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52873 var cs = this.selModel.getSelectedCell();
52874 if (row == cs[0] && cell == cs[1]){
52878 if (typeof(this.selModel.getSelections) != 'undefined') {
52879 var cs = this.selModel.getSelections();
52880 var ds = this.dataSource;
52881 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52892 this.fireEvent("row" + name, this, row, e);
52893 if(cell !== false){
52894 this.fireEvent("cell" + name, this, row, cell, e);
52901 onClick : function(e){
52902 this.processEvent("click", e);
52905 onTouchStart : function(e){
52906 this.processEvent("touchstart", e);
52910 onContextMenu : function(e, t){
52911 this.processEvent("contextmenu", e);
52915 onDblClick : function(e){
52916 this.processEvent("dblclick", e);
52920 walkCells : function(row, col, step, fn, scope){
52921 var cm = this.colModel, clen = cm.getColumnCount();
52922 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52934 if(fn.call(scope || this, row, col, cm) === true){
52952 if(fn.call(scope || this, row, col, cm) === true){
52964 getSelections : function(){
52965 return this.selModel.getSelections();
52969 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52970 * but if manual update is required this method will initiate it.
52972 autoSize : function(){
52974 this.view.layout();
52975 if(this.view.adjustForScroll){
52976 this.view.adjustForScroll();
52982 * Returns the grid's underlying element.
52983 * @return {Element} The element
52985 getGridEl : function(){
52986 return this.container;
52989 // private for compatibility, overridden by editor grid
52990 stopEditing : function(){},
52993 * Returns the grid's SelectionModel.
52994 * @return {SelectionModel}
52996 getSelectionModel : function(){
52997 if(!this.selModel){
52998 this.selModel = new Roo.grid.RowSelectionModel();
53000 return this.selModel;
53004 * Returns the grid's DataSource.
53005 * @return {DataSource}
53007 getDataSource : function(){
53008 return this.dataSource;
53012 * Returns the grid's ColumnModel.
53013 * @return {ColumnModel}
53015 getColumnModel : function(){
53016 return this.colModel;
53020 * Returns the grid's GridView object.
53021 * @return {GridView}
53023 getView : function(){
53025 this.view = new Roo.grid.GridView(this.viewConfig);
53030 * Called to get grid's drag proxy text, by default returns this.ddText.
53033 getDragDropText : function(){
53034 var count = this.selModel.getCount();
53035 return String.format(this.ddText, count, count == 1 ? '' : 's');
53039 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53040 * %0 is replaced with the number of selected rows.
53043 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53045 * Ext JS Library 1.1.1
53046 * Copyright(c) 2006-2007, Ext JS, LLC.
53048 * Originally Released Under LGPL - original licence link has changed is not relivant.
53051 * <script type="text/javascript">
53054 Roo.grid.AbstractGridView = function(){
53058 "beforerowremoved" : true,
53059 "beforerowsinserted" : true,
53060 "beforerefresh" : true,
53061 "rowremoved" : true,
53062 "rowsinserted" : true,
53063 "rowupdated" : true,
53066 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53069 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53070 rowClass : "x-grid-row",
53071 cellClass : "x-grid-cell",
53072 tdClass : "x-grid-td",
53073 hdClass : "x-grid-hd",
53074 splitClass : "x-grid-hd-split",
53076 init: function(grid){
53078 var cid = this.grid.getGridEl().id;
53079 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53080 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53081 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53082 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53085 getColumnRenderers : function(){
53086 var renderers = [];
53087 var cm = this.grid.colModel;
53088 var colCount = cm.getColumnCount();
53089 for(var i = 0; i < colCount; i++){
53090 renderers[i] = cm.getRenderer(i);
53095 getColumnIds : function(){
53097 var cm = this.grid.colModel;
53098 var colCount = cm.getColumnCount();
53099 for(var i = 0; i < colCount; i++){
53100 ids[i] = cm.getColumnId(i);
53105 getDataIndexes : function(){
53106 if(!this.indexMap){
53107 this.indexMap = this.buildIndexMap();
53109 return this.indexMap.colToData;
53112 getColumnIndexByDataIndex : function(dataIndex){
53113 if(!this.indexMap){
53114 this.indexMap = this.buildIndexMap();
53116 return this.indexMap.dataToCol[dataIndex];
53120 * Set a css style for a column dynamically.
53121 * @param {Number} colIndex The index of the column
53122 * @param {String} name The css property name
53123 * @param {String} value The css value
53125 setCSSStyle : function(colIndex, name, value){
53126 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53127 Roo.util.CSS.updateRule(selector, name, value);
53130 generateRules : function(cm){
53131 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53132 Roo.util.CSS.removeStyleSheet(rulesId);
53133 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53134 var cid = cm.getColumnId(i);
53135 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53136 this.tdSelector, cid, " {\n}\n",
53137 this.hdSelector, cid, " {\n}\n",
53138 this.splitSelector, cid, " {\n}\n");
53140 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53144 * Ext JS Library 1.1.1
53145 * Copyright(c) 2006-2007, Ext JS, LLC.
53147 * Originally Released Under LGPL - original licence link has changed is not relivant.
53150 * <script type="text/javascript">
53154 // This is a support class used internally by the Grid components
53155 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53157 this.view = grid.getView();
53158 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53159 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53161 this.setHandleElId(Roo.id(hd));
53162 this.setOuterHandleElId(Roo.id(hd2));
53164 this.scroll = false;
53166 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53168 getDragData : function(e){
53169 var t = Roo.lib.Event.getTarget(e);
53170 var h = this.view.findHeaderCell(t);
53172 return {ddel: h.firstChild, header:h};
53177 onInitDrag : function(e){
53178 this.view.headersDisabled = true;
53179 var clone = this.dragData.ddel.cloneNode(true);
53180 clone.id = Roo.id();
53181 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53182 this.proxy.update(clone);
53186 afterValidDrop : function(){
53188 setTimeout(function(){
53189 v.headersDisabled = false;
53193 afterInvalidDrop : function(){
53195 setTimeout(function(){
53196 v.headersDisabled = false;
53202 * Ext JS Library 1.1.1
53203 * Copyright(c) 2006-2007, Ext JS, LLC.
53205 * Originally Released Under LGPL - original licence link has changed is not relivant.
53208 * <script type="text/javascript">
53211 // This is a support class used internally by the Grid components
53212 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53214 this.view = grid.getView();
53215 // split the proxies so they don't interfere with mouse events
53216 this.proxyTop = Roo.DomHelper.append(document.body, {
53217 cls:"col-move-top", html:" "
53219 this.proxyBottom = Roo.DomHelper.append(document.body, {
53220 cls:"col-move-bottom", html:" "
53222 this.proxyTop.hide = this.proxyBottom.hide = function(){
53223 this.setLeftTop(-100,-100);
53224 this.setStyle("visibility", "hidden");
53226 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53227 // temporarily disabled
53228 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53229 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53231 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53232 proxyOffsets : [-4, -9],
53233 fly: Roo.Element.fly,
53235 getTargetFromEvent : function(e){
53236 var t = Roo.lib.Event.getTarget(e);
53237 var cindex = this.view.findCellIndex(t);
53238 if(cindex !== false){
53239 return this.view.getHeaderCell(cindex);
53244 nextVisible : function(h){
53245 var v = this.view, cm = this.grid.colModel;
53248 if(!cm.isHidden(v.getCellIndex(h))){
53256 prevVisible : function(h){
53257 var v = this.view, cm = this.grid.colModel;
53260 if(!cm.isHidden(v.getCellIndex(h))){
53268 positionIndicator : function(h, n, e){
53269 var x = Roo.lib.Event.getPageX(e);
53270 var r = Roo.lib.Dom.getRegion(n.firstChild);
53271 var px, pt, py = r.top + this.proxyOffsets[1];
53272 if((r.right - x) <= (r.right-r.left)/2){
53273 px = r.right+this.view.borderWidth;
53279 var oldIndex = this.view.getCellIndex(h);
53280 var newIndex = this.view.getCellIndex(n);
53282 if(this.grid.colModel.isFixed(newIndex)){
53286 var locked = this.grid.colModel.isLocked(newIndex);
53291 if(oldIndex < newIndex){
53294 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53297 px += this.proxyOffsets[0];
53298 this.proxyTop.setLeftTop(px, py);
53299 this.proxyTop.show();
53300 if(!this.bottomOffset){
53301 this.bottomOffset = this.view.mainHd.getHeight();
53303 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53304 this.proxyBottom.show();
53308 onNodeEnter : function(n, dd, e, data){
53309 if(data.header != n){
53310 this.positionIndicator(data.header, n, e);
53314 onNodeOver : function(n, dd, e, data){
53315 var result = false;
53316 if(data.header != n){
53317 result = this.positionIndicator(data.header, n, e);
53320 this.proxyTop.hide();
53321 this.proxyBottom.hide();
53323 return result ? this.dropAllowed : this.dropNotAllowed;
53326 onNodeOut : function(n, dd, e, data){
53327 this.proxyTop.hide();
53328 this.proxyBottom.hide();
53331 onNodeDrop : function(n, dd, e, data){
53332 var h = data.header;
53334 var cm = this.grid.colModel;
53335 var x = Roo.lib.Event.getPageX(e);
53336 var r = Roo.lib.Dom.getRegion(n.firstChild);
53337 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53338 var oldIndex = this.view.getCellIndex(h);
53339 var newIndex = this.view.getCellIndex(n);
53340 var locked = cm.isLocked(newIndex);
53344 if(oldIndex < newIndex){
53347 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53350 cm.setLocked(oldIndex, locked, true);
53351 cm.moveColumn(oldIndex, newIndex);
53352 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53360 * Ext JS Library 1.1.1
53361 * Copyright(c) 2006-2007, Ext JS, LLC.
53363 * Originally Released Under LGPL - original licence link has changed is not relivant.
53366 * <script type="text/javascript">
53370 * @class Roo.grid.GridView
53371 * @extends Roo.util.Observable
53374 * @param {Object} config
53376 Roo.grid.GridView = function(config){
53377 Roo.grid.GridView.superclass.constructor.call(this);
53380 Roo.apply(this, config);
53383 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53385 unselectable : 'unselectable="on"',
53386 unselectableCls : 'x-unselectable',
53389 rowClass : "x-grid-row",
53391 cellClass : "x-grid-col",
53393 tdClass : "x-grid-td",
53395 hdClass : "x-grid-hd",
53397 splitClass : "x-grid-split",
53399 sortClasses : ["sort-asc", "sort-desc"],
53401 enableMoveAnim : false,
53405 dh : Roo.DomHelper,
53407 fly : Roo.Element.fly,
53409 css : Roo.util.CSS,
53415 scrollIncrement : 22,
53417 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53419 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53421 bind : function(ds, cm){
53423 this.ds.un("load", this.onLoad, this);
53424 this.ds.un("datachanged", this.onDataChange, this);
53425 this.ds.un("add", this.onAdd, this);
53426 this.ds.un("remove", this.onRemove, this);
53427 this.ds.un("update", this.onUpdate, this);
53428 this.ds.un("clear", this.onClear, this);
53431 ds.on("load", this.onLoad, this);
53432 ds.on("datachanged", this.onDataChange, this);
53433 ds.on("add", this.onAdd, this);
53434 ds.on("remove", this.onRemove, this);
53435 ds.on("update", this.onUpdate, this);
53436 ds.on("clear", this.onClear, this);
53441 this.cm.un("widthchange", this.onColWidthChange, this);
53442 this.cm.un("headerchange", this.onHeaderChange, this);
53443 this.cm.un("hiddenchange", this.onHiddenChange, this);
53444 this.cm.un("columnmoved", this.onColumnMove, this);
53445 this.cm.un("columnlockchange", this.onColumnLock, this);
53448 this.generateRules(cm);
53449 cm.on("widthchange", this.onColWidthChange, this);
53450 cm.on("headerchange", this.onHeaderChange, this);
53451 cm.on("hiddenchange", this.onHiddenChange, this);
53452 cm.on("columnmoved", this.onColumnMove, this);
53453 cm.on("columnlockchange", this.onColumnLock, this);
53458 init: function(grid){
53459 Roo.grid.GridView.superclass.init.call(this, grid);
53461 this.bind(grid.dataSource, grid.colModel);
53463 grid.on("headerclick", this.handleHeaderClick, this);
53465 if(grid.trackMouseOver){
53466 grid.on("mouseover", this.onRowOver, this);
53467 grid.on("mouseout", this.onRowOut, this);
53469 grid.cancelTextSelection = function(){};
53470 this.gridId = grid.id;
53472 var tpls = this.templates || {};
53475 tpls.master = new Roo.Template(
53476 '<div class="x-grid" hidefocus="true">',
53477 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53478 '<div class="x-grid-topbar"></div>',
53479 '<div class="x-grid-scroller"><div></div></div>',
53480 '<div class="x-grid-locked">',
53481 '<div class="x-grid-header">{lockedHeader}</div>',
53482 '<div class="x-grid-body">{lockedBody}</div>',
53484 '<div class="x-grid-viewport">',
53485 '<div class="x-grid-header">{header}</div>',
53486 '<div class="x-grid-body">{body}</div>',
53488 '<div class="x-grid-bottombar"></div>',
53490 '<div class="x-grid-resize-proxy"> </div>',
53493 tpls.master.disableformats = true;
53497 tpls.header = new Roo.Template(
53498 '<table border="0" cellspacing="0" cellpadding="0">',
53499 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53502 tpls.header.disableformats = true;
53504 tpls.header.compile();
53507 tpls.hcell = new Roo.Template(
53508 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53509 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53512 tpls.hcell.disableFormats = true;
53514 tpls.hcell.compile();
53517 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53518 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53519 tpls.hsplit.disableFormats = true;
53521 tpls.hsplit.compile();
53524 tpls.body = new Roo.Template(
53525 '<table border="0" cellspacing="0" cellpadding="0">',
53526 "<tbody>{rows}</tbody>",
53529 tpls.body.disableFormats = true;
53531 tpls.body.compile();
53534 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53535 tpls.row.disableFormats = true;
53537 tpls.row.compile();
53540 tpls.cell = new Roo.Template(
53541 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53542 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53543 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53546 tpls.cell.disableFormats = true;
53548 tpls.cell.compile();
53550 this.templates = tpls;
53553 // remap these for backwards compat
53554 onColWidthChange : function(){
53555 this.updateColumns.apply(this, arguments);
53557 onHeaderChange : function(){
53558 this.updateHeaders.apply(this, arguments);
53560 onHiddenChange : function(){
53561 this.handleHiddenChange.apply(this, arguments);
53563 onColumnMove : function(){
53564 this.handleColumnMove.apply(this, arguments);
53566 onColumnLock : function(){
53567 this.handleLockChange.apply(this, arguments);
53570 onDataChange : function(){
53572 this.updateHeaderSortState();
53575 onClear : function(){
53579 onUpdate : function(ds, record){
53580 this.refreshRow(record);
53583 refreshRow : function(record){
53584 var ds = this.ds, index;
53585 if(typeof record == 'number'){
53587 record = ds.getAt(index);
53589 index = ds.indexOf(record);
53591 this.insertRows(ds, index, index, true);
53592 this.onRemove(ds, record, index+1, true);
53593 this.syncRowHeights(index, index);
53595 this.fireEvent("rowupdated", this, index, record);
53598 onAdd : function(ds, records, index){
53599 this.insertRows(ds, index, index + (records.length-1));
53602 onRemove : function(ds, record, index, isUpdate){
53603 if(isUpdate !== true){
53604 this.fireEvent("beforerowremoved", this, index, record);
53606 var bt = this.getBodyTable(), lt = this.getLockedTable();
53607 if(bt.rows[index]){
53608 bt.firstChild.removeChild(bt.rows[index]);
53610 if(lt.rows[index]){
53611 lt.firstChild.removeChild(lt.rows[index]);
53613 if(isUpdate !== true){
53614 this.stripeRows(index);
53615 this.syncRowHeights(index, index);
53617 this.fireEvent("rowremoved", this, index, record);
53621 onLoad : function(){
53622 this.scrollToTop();
53626 * Scrolls the grid to the top
53628 scrollToTop : function(){
53630 this.scroller.dom.scrollTop = 0;
53636 * Gets a panel in the header of the grid that can be used for toolbars etc.
53637 * After modifying the contents of this panel a call to grid.autoSize() may be
53638 * required to register any changes in size.
53639 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53640 * @return Roo.Element
53642 getHeaderPanel : function(doShow){
53644 this.headerPanel.show();
53646 return this.headerPanel;
53650 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53651 * After modifying the contents of this panel a call to grid.autoSize() may be
53652 * required to register any changes in size.
53653 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53654 * @return Roo.Element
53656 getFooterPanel : function(doShow){
53658 this.footerPanel.show();
53660 return this.footerPanel;
53663 initElements : function(){
53664 var E = Roo.Element;
53665 var el = this.grid.getGridEl().dom.firstChild;
53666 var cs = el.childNodes;
53668 this.el = new E(el);
53670 this.focusEl = new E(el.firstChild);
53671 this.focusEl.swallowEvent("click", true);
53673 this.headerPanel = new E(cs[1]);
53674 this.headerPanel.enableDisplayMode("block");
53676 this.scroller = new E(cs[2]);
53677 this.scrollSizer = new E(this.scroller.dom.firstChild);
53679 this.lockedWrap = new E(cs[3]);
53680 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53681 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53683 this.mainWrap = new E(cs[4]);
53684 this.mainHd = new E(this.mainWrap.dom.firstChild);
53685 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53687 this.footerPanel = new E(cs[5]);
53688 this.footerPanel.enableDisplayMode("block");
53690 this.resizeProxy = new E(cs[6]);
53692 this.headerSelector = String.format(
53693 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53694 this.lockedHd.id, this.mainHd.id
53697 this.splitterSelector = String.format(
53698 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53699 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53702 idToCssName : function(s)
53704 return s.replace(/[^a-z0-9]+/ig, '-');
53707 getHeaderCell : function(index){
53708 return Roo.DomQuery.select(this.headerSelector)[index];
53711 getHeaderCellMeasure : function(index){
53712 return this.getHeaderCell(index).firstChild;
53715 getHeaderCellText : function(index){
53716 return this.getHeaderCell(index).firstChild.firstChild;
53719 getLockedTable : function(){
53720 return this.lockedBody.dom.firstChild;
53723 getBodyTable : function(){
53724 return this.mainBody.dom.firstChild;
53727 getLockedRow : function(index){
53728 return this.getLockedTable().rows[index];
53731 getRow : function(index){
53732 return this.getBodyTable().rows[index];
53735 getRowComposite : function(index){
53737 this.rowEl = new Roo.CompositeElementLite();
53739 var els = [], lrow, mrow;
53740 if(lrow = this.getLockedRow(index)){
53743 if(mrow = this.getRow(index)){
53746 this.rowEl.elements = els;
53750 * Gets the 'td' of the cell
53752 * @param {Integer} rowIndex row to select
53753 * @param {Integer} colIndex column to select
53757 getCell : function(rowIndex, colIndex){
53758 var locked = this.cm.getLockedCount();
53760 if(colIndex < locked){
53761 source = this.lockedBody.dom.firstChild;
53763 source = this.mainBody.dom.firstChild;
53764 colIndex -= locked;
53766 return source.rows[rowIndex].childNodes[colIndex];
53769 getCellText : function(rowIndex, colIndex){
53770 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53773 getCellBox : function(cell){
53774 var b = this.fly(cell).getBox();
53775 if(Roo.isOpera){ // opera fails to report the Y
53776 b.y = cell.offsetTop + this.mainBody.getY();
53781 getCellIndex : function(cell){
53782 var id = String(cell.className).match(this.cellRE);
53784 return parseInt(id[1], 10);
53789 findHeaderIndex : function(n){
53790 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53791 return r ? this.getCellIndex(r) : false;
53794 findHeaderCell : function(n){
53795 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53796 return r ? r : false;
53799 findRowIndex : function(n){
53803 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53804 return r ? r.rowIndex : false;
53807 findCellIndex : function(node){
53808 var stop = this.el.dom;
53809 while(node && node != stop){
53810 if(this.findRE.test(node.className)){
53811 return this.getCellIndex(node);
53813 node = node.parentNode;
53818 getColumnId : function(index){
53819 return this.cm.getColumnId(index);
53822 getSplitters : function()
53824 if(this.splitterSelector){
53825 return Roo.DomQuery.select(this.splitterSelector);
53831 getSplitter : function(index){
53832 return this.getSplitters()[index];
53835 onRowOver : function(e, t){
53837 if((row = this.findRowIndex(t)) !== false){
53838 this.getRowComposite(row).addClass("x-grid-row-over");
53842 onRowOut : function(e, t){
53844 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53845 this.getRowComposite(row).removeClass("x-grid-row-over");
53849 renderHeaders : function(){
53851 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53852 var cb = [], lb = [], sb = [], lsb = [], p = {};
53853 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53854 p.cellId = "x-grid-hd-0-" + i;
53855 p.splitId = "x-grid-csplit-0-" + i;
53856 p.id = cm.getColumnId(i);
53857 p.title = cm.getColumnTooltip(i) || "";
53858 p.value = cm.getColumnHeader(i) || "";
53859 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53860 if(!cm.isLocked(i)){
53861 cb[cb.length] = ct.apply(p);
53862 sb[sb.length] = st.apply(p);
53864 lb[lb.length] = ct.apply(p);
53865 lsb[lsb.length] = st.apply(p);
53868 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53869 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53872 updateHeaders : function(){
53873 var html = this.renderHeaders();
53874 this.lockedHd.update(html[0]);
53875 this.mainHd.update(html[1]);
53879 * Focuses the specified row.
53880 * @param {Number} row The row index
53882 focusRow : function(row)
53884 //Roo.log('GridView.focusRow');
53885 var x = this.scroller.dom.scrollLeft;
53886 this.focusCell(row, 0, false);
53887 this.scroller.dom.scrollLeft = x;
53891 * Focuses the specified cell.
53892 * @param {Number} row The row index
53893 * @param {Number} col The column index
53894 * @param {Boolean} hscroll false to disable horizontal scrolling
53896 focusCell : function(row, col, hscroll)
53898 //Roo.log('GridView.focusCell');
53899 var el = this.ensureVisible(row, col, hscroll);
53900 this.focusEl.alignTo(el, "tl-tl");
53902 this.focusEl.focus();
53904 this.focusEl.focus.defer(1, this.focusEl);
53909 * Scrolls the specified cell into view
53910 * @param {Number} row The row index
53911 * @param {Number} col The column index
53912 * @param {Boolean} hscroll false to disable horizontal scrolling
53914 ensureVisible : function(row, col, hscroll)
53916 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53917 //return null; //disable for testing.
53918 if(typeof row != "number"){
53919 row = row.rowIndex;
53921 if(row < 0 && row >= this.ds.getCount()){
53924 col = (col !== undefined ? col : 0);
53925 var cm = this.grid.colModel;
53926 while(cm.isHidden(col)){
53930 var el = this.getCell(row, col);
53934 var c = this.scroller.dom;
53936 var ctop = parseInt(el.offsetTop, 10);
53937 var cleft = parseInt(el.offsetLeft, 10);
53938 var cbot = ctop + el.offsetHeight;
53939 var cright = cleft + el.offsetWidth;
53941 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53942 var stop = parseInt(c.scrollTop, 10);
53943 var sleft = parseInt(c.scrollLeft, 10);
53944 var sbot = stop + ch;
53945 var sright = sleft + c.clientWidth;
53947 Roo.log('GridView.ensureVisible:' +
53949 ' c.clientHeight:' + c.clientHeight +
53950 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53958 c.scrollTop = ctop;
53959 //Roo.log("set scrolltop to ctop DISABLE?");
53960 }else if(cbot > sbot){
53961 //Roo.log("set scrolltop to cbot-ch");
53962 c.scrollTop = cbot-ch;
53965 if(hscroll !== false){
53967 c.scrollLeft = cleft;
53968 }else if(cright > sright){
53969 c.scrollLeft = cright-c.clientWidth;
53976 updateColumns : function(){
53977 this.grid.stopEditing();
53978 var cm = this.grid.colModel, colIds = this.getColumnIds();
53979 //var totalWidth = cm.getTotalWidth();
53981 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53982 //if(cm.isHidden(i)) continue;
53983 var w = cm.getColumnWidth(i);
53984 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53985 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53987 this.updateSplitters();
53990 generateRules : function(cm){
53991 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53992 Roo.util.CSS.removeStyleSheet(rulesId);
53993 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53994 var cid = cm.getColumnId(i);
53996 if(cm.config[i].align){
53997 align = 'text-align:'+cm.config[i].align+';';
54000 if(cm.isHidden(i)){
54001 hidden = 'display:none;';
54003 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
54005 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
54006 this.hdSelector, cid, " {\n", align, width, "}\n",
54007 this.tdSelector, cid, " {\n",hidden,"\n}\n",
54008 this.splitSelector, cid, " {\n", hidden , "\n}\n");
54010 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54013 updateSplitters : function(){
54014 var cm = this.cm, s = this.getSplitters();
54015 if(s){ // splitters not created yet
54016 var pos = 0, locked = true;
54017 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54018 if(cm.isHidden(i)) continue;
54019 var w = cm.getColumnWidth(i); // make sure it's a number
54020 if(!cm.isLocked(i) && locked){
54025 s[i].style.left = (pos-this.splitOffset) + "px";
54030 handleHiddenChange : function(colModel, colIndex, hidden){
54032 this.hideColumn(colIndex);
54034 this.unhideColumn(colIndex);
54038 hideColumn : function(colIndex){
54039 var cid = this.getColumnId(colIndex);
54040 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54041 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54043 this.updateHeaders();
54045 this.updateSplitters();
54049 unhideColumn : function(colIndex){
54050 var cid = this.getColumnId(colIndex);
54051 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54052 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54055 this.updateHeaders();
54057 this.updateSplitters();
54061 insertRows : function(dm, firstRow, lastRow, isUpdate){
54062 if(firstRow == 0 && lastRow == dm.getCount()-1){
54066 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54068 var s = this.getScrollState();
54069 var markup = this.renderRows(firstRow, lastRow);
54070 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54071 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54072 this.restoreScroll(s);
54074 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54075 this.syncRowHeights(firstRow, lastRow);
54076 this.stripeRows(firstRow);
54082 bufferRows : function(markup, target, index){
54083 var before = null, trows = target.rows, tbody = target.tBodies[0];
54084 if(index < trows.length){
54085 before = trows[index];
54087 var b = document.createElement("div");
54088 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54089 var rows = b.firstChild.rows;
54090 for(var i = 0, len = rows.length; i < len; i++){
54092 tbody.insertBefore(rows[0], before);
54094 tbody.appendChild(rows[0]);
54101 deleteRows : function(dm, firstRow, lastRow){
54102 if(dm.getRowCount()<1){
54103 this.fireEvent("beforerefresh", this);
54104 this.mainBody.update("");
54105 this.lockedBody.update("");
54106 this.fireEvent("refresh", this);
54108 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54109 var bt = this.getBodyTable();
54110 var tbody = bt.firstChild;
54111 var rows = bt.rows;
54112 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54113 tbody.removeChild(rows[firstRow]);
54115 this.stripeRows(firstRow);
54116 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54120 updateRows : function(dataSource, firstRow, lastRow){
54121 var s = this.getScrollState();
54123 this.restoreScroll(s);
54126 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54130 this.updateHeaderSortState();
54133 getScrollState : function(){
54135 var sb = this.scroller.dom;
54136 return {left: sb.scrollLeft, top: sb.scrollTop};
54139 stripeRows : function(startRow){
54140 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54143 startRow = startRow || 0;
54144 var rows = this.getBodyTable().rows;
54145 var lrows = this.getLockedTable().rows;
54146 var cls = ' x-grid-row-alt ';
54147 for(var i = startRow, len = rows.length; i < len; i++){
54148 var row = rows[i], lrow = lrows[i];
54149 var isAlt = ((i+1) % 2 == 0);
54150 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54151 if(isAlt == hasAlt){
54155 row.className += " x-grid-row-alt";
54157 row.className = row.className.replace("x-grid-row-alt", "");
54160 lrow.className = row.className;
54165 restoreScroll : function(state){
54166 //Roo.log('GridView.restoreScroll');
54167 var sb = this.scroller.dom;
54168 sb.scrollLeft = state.left;
54169 sb.scrollTop = state.top;
54173 syncScroll : function(){
54174 //Roo.log('GridView.syncScroll');
54175 var sb = this.scroller.dom;
54176 var sh = this.mainHd.dom;
54177 var bs = this.mainBody.dom;
54178 var lv = this.lockedBody.dom;
54179 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54180 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54183 handleScroll : function(e){
54185 var sb = this.scroller.dom;
54186 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54190 handleWheel : function(e){
54191 var d = e.getWheelDelta();
54192 this.scroller.dom.scrollTop -= d*22;
54193 // set this here to prevent jumpy scrolling on large tables
54194 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54198 renderRows : function(startRow, endRow){
54199 // pull in all the crap needed to render rows
54200 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54201 var colCount = cm.getColumnCount();
54203 if(ds.getCount() < 1){
54207 // build a map for all the columns
54209 for(var i = 0; i < colCount; i++){
54210 var name = cm.getDataIndex(i);
54212 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54213 renderer : cm.getRenderer(i),
54214 id : cm.getColumnId(i),
54215 locked : cm.isLocked(i)
54219 startRow = startRow || 0;
54220 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54222 // records to render
54223 var rs = ds.getRange(startRow, endRow);
54225 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54228 // As much as I hate to duplicate code, this was branched because FireFox really hates
54229 // [].join("") on strings. The performance difference was substantial enough to
54230 // branch this function
54231 doRender : Roo.isGecko ?
54232 function(cs, rs, ds, startRow, colCount, stripe){
54233 var ts = this.templates, ct = ts.cell, rt = ts.row;
54235 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54237 var hasListener = this.grid.hasListener('rowclass');
54239 for(var j = 0, len = rs.length; j < len; j++){
54240 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54241 for(var i = 0; i < colCount; i++){
54243 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54245 p.css = p.attr = "";
54246 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54247 if(p.value == undefined || p.value === "") p.value = " ";
54248 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54249 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54251 var markup = ct.apply(p);
54259 if(stripe && ((rowIndex+1) % 2 == 0)){
54260 alt.push("x-grid-row-alt")
54263 alt.push( " x-grid-dirty-row");
54266 if(this.getRowClass){
54267 alt.push(this.getRowClass(r, rowIndex));
54273 rowIndex : rowIndex,
54276 this.grid.fireEvent('rowclass', this, rowcfg);
54277 alt.push(rowcfg.rowClass);
54279 rp.alt = alt.join(" ");
54280 lbuf+= rt.apply(rp);
54282 buf+= rt.apply(rp);
54284 return [lbuf, buf];
54286 function(cs, rs, ds, startRow, colCount, stripe){
54287 var ts = this.templates, ct = ts.cell, rt = ts.row;
54289 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54290 var hasListener = this.grid.hasListener('rowclass');
54293 for(var j = 0, len = rs.length; j < len; j++){
54294 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54295 for(var i = 0; i < colCount; i++){
54297 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54299 p.css = p.attr = "";
54300 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54301 if(p.value == undefined || p.value === "") p.value = " ";
54302 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54303 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54306 var markup = ct.apply(p);
54308 cb[cb.length] = markup;
54310 lcb[lcb.length] = markup;
54314 if(stripe && ((rowIndex+1) % 2 == 0)){
54315 alt.push( "x-grid-row-alt");
54318 alt.push(" x-grid-dirty-row");
54321 if(this.getRowClass){
54322 alt.push( this.getRowClass(r, rowIndex));
54328 rowIndex : rowIndex,
54331 this.grid.fireEvent('rowclass', this, rowcfg);
54332 alt.push(rowcfg.rowClass);
54334 rp.alt = alt.join(" ");
54335 rp.cells = lcb.join("");
54336 lbuf[lbuf.length] = rt.apply(rp);
54337 rp.cells = cb.join("");
54338 buf[buf.length] = rt.apply(rp);
54340 return [lbuf.join(""), buf.join("")];
54343 renderBody : function(){
54344 var markup = this.renderRows();
54345 var bt = this.templates.body;
54346 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54350 * Refreshes the grid
54351 * @param {Boolean} headersToo
54353 refresh : function(headersToo){
54354 this.fireEvent("beforerefresh", this);
54355 this.grid.stopEditing();
54356 var result = this.renderBody();
54357 this.lockedBody.update(result[0]);
54358 this.mainBody.update(result[1]);
54359 if(headersToo === true){
54360 this.updateHeaders();
54361 this.updateColumns();
54362 this.updateSplitters();
54363 this.updateHeaderSortState();
54365 this.syncRowHeights();
54367 this.fireEvent("refresh", this);
54370 handleColumnMove : function(cm, oldIndex, newIndex){
54371 this.indexMap = null;
54372 var s = this.getScrollState();
54373 this.refresh(true);
54374 this.restoreScroll(s);
54375 this.afterMove(newIndex);
54378 afterMove : function(colIndex){
54379 if(this.enableMoveAnim && Roo.enableFx){
54380 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54382 // if multisort - fix sortOrder, and reload..
54383 if (this.grid.dataSource.multiSort) {
54384 // the we can call sort again..
54385 var dm = this.grid.dataSource;
54386 var cm = this.grid.colModel;
54388 for(var i = 0; i < cm.config.length; i++ ) {
54390 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54391 continue; // dont' bother, it's not in sort list or being set.
54394 so.push(cm.config[i].dataIndex);
54397 dm.load(dm.lastOptions);
54404 updateCell : function(dm, rowIndex, dataIndex){
54405 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54406 if(typeof colIndex == "undefined"){ // not present in grid
54409 var cm = this.grid.colModel;
54410 var cell = this.getCell(rowIndex, colIndex);
54411 var cellText = this.getCellText(rowIndex, colIndex);
54414 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54415 id : cm.getColumnId(colIndex),
54416 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54418 var renderer = cm.getRenderer(colIndex);
54419 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54420 if(typeof val == "undefined" || val === "") val = " ";
54421 cellText.innerHTML = val;
54422 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54423 this.syncRowHeights(rowIndex, rowIndex);
54426 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54428 if(this.grid.autoSizeHeaders){
54429 var h = this.getHeaderCellMeasure(colIndex);
54430 maxWidth = Math.max(maxWidth, h.scrollWidth);
54433 if(this.cm.isLocked(colIndex)){
54434 tb = this.getLockedTable();
54437 tb = this.getBodyTable();
54438 index = colIndex - this.cm.getLockedCount();
54441 var rows = tb.rows;
54442 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54443 for(var i = 0; i < stopIndex; i++){
54444 var cell = rows[i].childNodes[index].firstChild;
54445 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54448 return maxWidth + /*margin for error in IE*/ 5;
54451 * Autofit a column to its content.
54452 * @param {Number} colIndex
54453 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54455 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54456 if(this.cm.isHidden(colIndex)){
54457 return; // can't calc a hidden column
54460 var cid = this.cm.getColumnId(colIndex);
54461 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54462 if(this.grid.autoSizeHeaders){
54463 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54466 var newWidth = this.calcColumnWidth(colIndex);
54467 this.cm.setColumnWidth(colIndex,
54468 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54469 if(!suppressEvent){
54470 this.grid.fireEvent("columnresize", colIndex, newWidth);
54475 * Autofits all columns to their content and then expands to fit any extra space in the grid
54477 autoSizeColumns : function(){
54478 var cm = this.grid.colModel;
54479 var colCount = cm.getColumnCount();
54480 for(var i = 0; i < colCount; i++){
54481 this.autoSizeColumn(i, true, true);
54483 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54486 this.updateColumns();
54492 * Autofits all columns to the grid's width proportionate with their current size
54493 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54495 fitColumns : function(reserveScrollSpace){
54496 var cm = this.grid.colModel;
54497 var colCount = cm.getColumnCount();
54501 for (i = 0; i < colCount; i++){
54502 if(!cm.isHidden(i) && !cm.isFixed(i)){
54503 w = cm.getColumnWidth(i);
54509 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54510 if(reserveScrollSpace){
54513 var frac = (avail - cm.getTotalWidth())/width;
54514 while (cols.length){
54517 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54519 this.updateColumns();
54523 onRowSelect : function(rowIndex){
54524 var row = this.getRowComposite(rowIndex);
54525 row.addClass("x-grid-row-selected");
54528 onRowDeselect : function(rowIndex){
54529 var row = this.getRowComposite(rowIndex);
54530 row.removeClass("x-grid-row-selected");
54533 onCellSelect : function(row, col){
54534 var cell = this.getCell(row, col);
54536 Roo.fly(cell).addClass("x-grid-cell-selected");
54540 onCellDeselect : function(row, col){
54541 var cell = this.getCell(row, col);
54543 Roo.fly(cell).removeClass("x-grid-cell-selected");
54547 updateHeaderSortState : function(){
54549 // sort state can be single { field: xxx, direction : yyy}
54550 // or { xxx=>ASC , yyy : DESC ..... }
54553 if (!this.ds.multiSort) {
54554 var state = this.ds.getSortState();
54558 mstate[state.field] = state.direction;
54559 // FIXME... - this is not used here.. but might be elsewhere..
54560 this.sortState = state;
54563 mstate = this.ds.sortToggle;
54565 //remove existing sort classes..
54567 var sc = this.sortClasses;
54568 var hds = this.el.select(this.headerSelector).removeClass(sc);
54570 for(var f in mstate) {
54572 var sortColumn = this.cm.findColumnIndex(f);
54574 if(sortColumn != -1){
54575 var sortDir = mstate[f];
54576 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54585 handleHeaderClick : function(g, index,e){
54587 Roo.log("header click");
54590 // touch events on header are handled by context
54591 this.handleHdCtx(g,index,e);
54596 if(this.headersDisabled){
54599 var dm = g.dataSource, cm = g.colModel;
54600 if(!cm.isSortable(index)){
54605 if (dm.multiSort) {
54606 // update the sortOrder
54608 for(var i = 0; i < cm.config.length; i++ ) {
54610 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54611 continue; // dont' bother, it's not in sort list or being set.
54614 so.push(cm.config[i].dataIndex);
54620 dm.sort(cm.getDataIndex(index));
54624 destroy : function(){
54626 this.colMenu.removeAll();
54627 Roo.menu.MenuMgr.unregister(this.colMenu);
54628 this.colMenu.getEl().remove();
54629 delete this.colMenu;
54632 this.hmenu.removeAll();
54633 Roo.menu.MenuMgr.unregister(this.hmenu);
54634 this.hmenu.getEl().remove();
54637 if(this.grid.enableColumnMove){
54638 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54640 for(var dd in dds){
54641 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54642 var elid = dds[dd].dragElId;
54644 Roo.get(elid).remove();
54645 } else if(dds[dd].config.isTarget){
54646 dds[dd].proxyTop.remove();
54647 dds[dd].proxyBottom.remove();
54650 if(Roo.dd.DDM.locationCache[dd]){
54651 delete Roo.dd.DDM.locationCache[dd];
54654 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54657 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54658 this.bind(null, null);
54659 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54662 handleLockChange : function(){
54663 this.refresh(true);
54666 onDenyColumnLock : function(){
54670 onDenyColumnHide : function(){
54674 handleHdMenuClick : function(item){
54675 var index = this.hdCtxIndex;
54676 var cm = this.cm, ds = this.ds;
54679 ds.sort(cm.getDataIndex(index), "ASC");
54682 ds.sort(cm.getDataIndex(index), "DESC");
54685 var lc = cm.getLockedCount();
54686 if(cm.getColumnCount(true) <= lc+1){
54687 this.onDenyColumnLock();
54691 cm.setLocked(index, true, true);
54692 cm.moveColumn(index, lc);
54693 this.grid.fireEvent("columnmove", index, lc);
54695 cm.setLocked(index, true);
54699 var lc = cm.getLockedCount();
54700 if((lc-1) != index){
54701 cm.setLocked(index, false, true);
54702 cm.moveColumn(index, lc-1);
54703 this.grid.fireEvent("columnmove", index, lc-1);
54705 cm.setLocked(index, false);
54708 case 'wider': // used to expand cols on touch..
54710 var cw = cm.getColumnWidth(index);
54711 cw += (item.id == 'wider' ? 1 : -1) * 50;
54712 cw = Math.max(0, cw);
54713 cw = Math.min(cw,4000);
54714 cm.setColumnWidth(index, cw);
54718 index = cm.getIndexById(item.id.substr(4));
54720 if(item.checked && cm.getColumnCount(true) <= 1){
54721 this.onDenyColumnHide();
54724 cm.setHidden(index, item.checked);
54730 beforeColMenuShow : function(){
54731 var cm = this.cm, colCount = cm.getColumnCount();
54732 this.colMenu.removeAll();
54733 for(var i = 0; i < colCount; i++){
54734 this.colMenu.add(new Roo.menu.CheckItem({
54735 id: "col-"+cm.getColumnId(i),
54736 text: cm.getColumnHeader(i),
54737 checked: !cm.isHidden(i),
54743 handleHdCtx : function(g, index, e){
54745 var hd = this.getHeaderCell(index);
54746 this.hdCtxIndex = index;
54747 var ms = this.hmenu.items, cm = this.cm;
54748 ms.get("asc").setDisabled(!cm.isSortable(index));
54749 ms.get("desc").setDisabled(!cm.isSortable(index));
54750 if(this.grid.enableColLock !== false){
54751 ms.get("lock").setDisabled(cm.isLocked(index));
54752 ms.get("unlock").setDisabled(!cm.isLocked(index));
54754 this.hmenu.show(hd, "tl-bl");
54757 handleHdOver : function(e){
54758 var hd = this.findHeaderCell(e.getTarget());
54759 if(hd && !this.headersDisabled){
54760 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54761 this.fly(hd).addClass("x-grid-hd-over");
54766 handleHdOut : function(e){
54767 var hd = this.findHeaderCell(e.getTarget());
54769 this.fly(hd).removeClass("x-grid-hd-over");
54773 handleSplitDblClick : function(e, t){
54774 var i = this.getCellIndex(t);
54775 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54776 this.autoSizeColumn(i, true);
54781 render : function(){
54784 var colCount = cm.getColumnCount();
54786 if(this.grid.monitorWindowResize === true){
54787 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54789 var header = this.renderHeaders();
54790 var body = this.templates.body.apply({rows:""});
54791 var html = this.templates.master.apply({
54794 lockedHeader: header[0],
54798 //this.updateColumns();
54800 this.grid.getGridEl().dom.innerHTML = html;
54802 this.initElements();
54804 // a kludge to fix the random scolling effect in webkit
54805 this.el.on("scroll", function() {
54806 this.el.dom.scrollTop=0; // hopefully not recursive..
54809 this.scroller.on("scroll", this.handleScroll, this);
54810 this.lockedBody.on("mousewheel", this.handleWheel, this);
54811 this.mainBody.on("mousewheel", this.handleWheel, this);
54813 this.mainHd.on("mouseover", this.handleHdOver, this);
54814 this.mainHd.on("mouseout", this.handleHdOut, this);
54815 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54816 {delegate: "."+this.splitClass});
54818 this.lockedHd.on("mouseover", this.handleHdOver, this);
54819 this.lockedHd.on("mouseout", this.handleHdOut, this);
54820 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54821 {delegate: "."+this.splitClass});
54823 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54824 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54827 this.updateSplitters();
54829 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54830 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54831 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54834 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54835 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54837 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54838 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54840 if(this.grid.enableColLock !== false){
54841 this.hmenu.add('-',
54842 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54843 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54847 this.hmenu.add('-',
54848 {id:"wider", text: this.columnsWiderText},
54849 {id:"narrow", text: this.columnsNarrowText }
54855 if(this.grid.enableColumnHide !== false){
54857 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54858 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54859 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54861 this.hmenu.add('-',
54862 {id:"columns", text: this.columnsText, menu: this.colMenu}
54865 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54867 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54870 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54871 this.dd = new Roo.grid.GridDragZone(this.grid, {
54872 ddGroup : this.grid.ddGroup || 'GridDD'
54878 for(var i = 0; i < colCount; i++){
54879 if(cm.isHidden(i)){
54880 this.hideColumn(i);
54882 if(cm.config[i].align){
54883 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54884 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54888 this.updateHeaderSortState();
54890 this.beforeInitialResize();
54893 // two part rendering gives faster view to the user
54894 this.renderPhase2.defer(1, this);
54897 renderPhase2 : function(){
54898 // render the rows now
54900 if(this.grid.autoSizeColumns){
54901 this.autoSizeColumns();
54905 beforeInitialResize : function(){
54909 onColumnSplitterMoved : function(i, w){
54910 this.userResized = true;
54911 var cm = this.grid.colModel;
54912 cm.setColumnWidth(i, w, true);
54913 var cid = cm.getColumnId(i);
54914 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54915 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54916 this.updateSplitters();
54918 this.grid.fireEvent("columnresize", i, w);
54921 syncRowHeights : function(startIndex, endIndex){
54922 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54923 startIndex = startIndex || 0;
54924 var mrows = this.getBodyTable().rows;
54925 var lrows = this.getLockedTable().rows;
54926 var len = mrows.length-1;
54927 endIndex = Math.min(endIndex || len, len);
54928 for(var i = startIndex; i <= endIndex; i++){
54929 var m = mrows[i], l = lrows[i];
54930 var h = Math.max(m.offsetHeight, l.offsetHeight);
54931 m.style.height = l.style.height = h + "px";
54936 layout : function(initialRender, is2ndPass){
54938 var auto = g.autoHeight;
54939 var scrollOffset = 16;
54940 var c = g.getGridEl(), cm = this.cm,
54941 expandCol = g.autoExpandColumn,
54943 //c.beginMeasure();
54945 if(!c.dom.offsetWidth){ // display:none?
54947 this.lockedWrap.show();
54948 this.mainWrap.show();
54953 var hasLock = this.cm.isLocked(0);
54955 var tbh = this.headerPanel.getHeight();
54956 var bbh = this.footerPanel.getHeight();
54959 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54960 var newHeight = ch + c.getBorderWidth("tb");
54962 newHeight = Math.min(g.maxHeight, newHeight);
54964 c.setHeight(newHeight);
54968 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54971 var s = this.scroller;
54973 var csize = c.getSize(true);
54975 this.el.setSize(csize.width, csize.height);
54977 this.headerPanel.setWidth(csize.width);
54978 this.footerPanel.setWidth(csize.width);
54980 var hdHeight = this.mainHd.getHeight();
54981 var vw = csize.width;
54982 var vh = csize.height - (tbh + bbh);
54986 var bt = this.getBodyTable();
54987 var ltWidth = hasLock ?
54988 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54990 var scrollHeight = bt.offsetHeight;
54991 var scrollWidth = ltWidth + bt.offsetWidth;
54992 var vscroll = false, hscroll = false;
54994 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54996 var lw = this.lockedWrap, mw = this.mainWrap;
54997 var lb = this.lockedBody, mb = this.mainBody;
54999 setTimeout(function(){
55000 var t = s.dom.offsetTop;
55001 var w = s.dom.clientWidth,
55002 h = s.dom.clientHeight;
55005 lw.setSize(ltWidth, h);
55007 mw.setLeftTop(ltWidth, t);
55008 mw.setSize(w-ltWidth, h);
55010 lb.setHeight(h-hdHeight);
55011 mb.setHeight(h-hdHeight);
55013 if(is2ndPass !== true && !gv.userResized && expandCol){
55014 // high speed resize without full column calculation
55016 var ci = cm.getIndexById(expandCol);
55018 ci = cm.findColumnIndex(expandCol);
55020 ci = Math.max(0, ci); // make sure it's got at least the first col.
55021 var expandId = cm.getColumnId(ci);
55022 var tw = cm.getTotalWidth(false);
55023 var currentWidth = cm.getColumnWidth(ci);
55024 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55025 if(currentWidth != cw){
55026 cm.setColumnWidth(ci, cw, true);
55027 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55028 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55029 gv.updateSplitters();
55030 gv.layout(false, true);
55042 onWindowResize : function(){
55043 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55049 appendFooter : function(parentEl){
55053 sortAscText : "Sort Ascending",
55054 sortDescText : "Sort Descending",
55055 lockText : "Lock Column",
55056 unlockText : "Unlock Column",
55057 columnsText : "Columns",
55059 columnsWiderText : "Wider",
55060 columnsNarrowText : "Thinner"
55064 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55065 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55066 this.proxy.el.addClass('x-grid3-col-dd');
55069 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55070 handleMouseDown : function(e){
55074 callHandleMouseDown : function(e){
55075 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55080 * Ext JS Library 1.1.1
55081 * Copyright(c) 2006-2007, Ext JS, LLC.
55083 * Originally Released Under LGPL - original licence link has changed is not relivant.
55086 * <script type="text/javascript">
55090 // This is a support class used internally by the Grid components
55091 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55093 this.view = grid.getView();
55094 this.proxy = this.view.resizeProxy;
55095 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55096 "gridSplitters" + this.grid.getGridEl().id, {
55097 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55099 this.setHandleElId(Roo.id(hd));
55100 this.setOuterHandleElId(Roo.id(hd2));
55101 this.scroll = false;
55103 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55104 fly: Roo.Element.fly,
55106 b4StartDrag : function(x, y){
55107 this.view.headersDisabled = true;
55108 this.proxy.setHeight(this.view.mainWrap.getHeight());
55109 var w = this.cm.getColumnWidth(this.cellIndex);
55110 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55111 this.resetConstraints();
55112 this.setXConstraint(minw, 1000);
55113 this.setYConstraint(0, 0);
55114 this.minX = x - minw;
55115 this.maxX = x + 1000;
55117 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55121 handleMouseDown : function(e){
55122 ev = Roo.EventObject.setEvent(e);
55123 var t = this.fly(ev.getTarget());
55124 if(t.hasClass("x-grid-split")){
55125 this.cellIndex = this.view.getCellIndex(t.dom);
55126 this.split = t.dom;
55127 this.cm = this.grid.colModel;
55128 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55129 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55134 endDrag : function(e){
55135 this.view.headersDisabled = false;
55136 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55137 var diff = endX - this.startPos;
55138 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55141 autoOffset : function(){
55142 this.setDelta(0,0);
55146 * Ext JS Library 1.1.1
55147 * Copyright(c) 2006-2007, Ext JS, LLC.
55149 * Originally Released Under LGPL - original licence link has changed is not relivant.
55152 * <script type="text/javascript">
55156 // This is a support class used internally by the Grid components
55157 Roo.grid.GridDragZone = function(grid, config){
55158 this.view = grid.getView();
55159 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55160 if(this.view.lockedBody){
55161 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55162 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55164 this.scroll = false;
55166 this.ddel = document.createElement('div');
55167 this.ddel.className = 'x-grid-dd-wrap';
55170 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55171 ddGroup : "GridDD",
55173 getDragData : function(e){
55174 var t = Roo.lib.Event.getTarget(e);
55175 var rowIndex = this.view.findRowIndex(t);
55176 var sm = this.grid.selModel;
55178 //Roo.log(rowIndex);
55180 if (sm.getSelectedCell) {
55181 // cell selection..
55182 if (!sm.getSelectedCell()) {
55185 if (rowIndex != sm.getSelectedCell()[0]) {
55191 if(rowIndex !== false){
55196 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55198 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55201 if (e.hasModifier()){
55202 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55205 Roo.log("getDragData");
55210 rowIndex: rowIndex,
55211 selections:sm.getSelections ? sm.getSelections() : (
55212 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55219 onInitDrag : function(e){
55220 var data = this.dragData;
55221 this.ddel.innerHTML = this.grid.getDragDropText();
55222 this.proxy.update(this.ddel);
55223 // fire start drag?
55226 afterRepair : function(){
55227 this.dragging = false;
55230 getRepairXY : function(e, data){
55234 onEndDrag : function(data, e){
55238 onValidDrop : function(dd, e, id){
55243 beforeInvalidDrop : function(e, id){
55248 * Ext JS Library 1.1.1
55249 * Copyright(c) 2006-2007, Ext JS, LLC.
55251 * Originally Released Under LGPL - original licence link has changed is not relivant.
55254 * <script type="text/javascript">
55259 * @class Roo.grid.ColumnModel
55260 * @extends Roo.util.Observable
55261 * This is the default implementation of a ColumnModel used by the Grid. It defines
55262 * the columns in the grid.
55265 var colModel = new Roo.grid.ColumnModel([
55266 {header: "Ticker", width: 60, sortable: true, locked: true},
55267 {header: "Company Name", width: 150, sortable: true},
55268 {header: "Market Cap.", width: 100, sortable: true},
55269 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55270 {header: "Employees", width: 100, sortable: true, resizable: false}
55275 * The config options listed for this class are options which may appear in each
55276 * individual column definition.
55277 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55279 * @param {Object} config An Array of column config objects. See this class's
55280 * config objects for details.
55282 Roo.grid.ColumnModel = function(config){
55284 * The config passed into the constructor
55286 this.config = config;
55289 // if no id, create one
55290 // if the column does not have a dataIndex mapping,
55291 // map it to the order it is in the config
55292 for(var i = 0, len = config.length; i < len; i++){
55294 if(typeof c.dataIndex == "undefined"){
55297 if(typeof c.renderer == "string"){
55298 c.renderer = Roo.util.Format[c.renderer];
55300 if(typeof c.id == "undefined"){
55303 if(c.editor && c.editor.xtype){
55304 c.editor = Roo.factory(c.editor, Roo.grid);
55306 if(c.editor && c.editor.isFormField){
55307 c.editor = new Roo.grid.GridEditor(c.editor);
55309 this.lookup[c.id] = c;
55313 * The width of columns which have no width specified (defaults to 100)
55316 this.defaultWidth = 100;
55319 * Default sortable of columns which have no sortable specified (defaults to false)
55322 this.defaultSortable = false;
55326 * @event widthchange
55327 * Fires when the width of a column changes.
55328 * @param {ColumnModel} this
55329 * @param {Number} columnIndex The column index
55330 * @param {Number} newWidth The new width
55332 "widthchange": true,
55334 * @event headerchange
55335 * Fires when the text of a header changes.
55336 * @param {ColumnModel} this
55337 * @param {Number} columnIndex The column index
55338 * @param {Number} newText The new header text
55340 "headerchange": true,
55342 * @event hiddenchange
55343 * Fires when a column is hidden or "unhidden".
55344 * @param {ColumnModel} this
55345 * @param {Number} columnIndex The column index
55346 * @param {Boolean} hidden true if hidden, false otherwise
55348 "hiddenchange": true,
55350 * @event columnmoved
55351 * Fires when a column is moved.
55352 * @param {ColumnModel} this
55353 * @param {Number} oldIndex
55354 * @param {Number} newIndex
55356 "columnmoved" : true,
55358 * @event columlockchange
55359 * Fires when a column's locked state is changed
55360 * @param {ColumnModel} this
55361 * @param {Number} colIndex
55362 * @param {Boolean} locked true if locked
55364 "columnlockchange" : true
55366 Roo.grid.ColumnModel.superclass.constructor.call(this);
55368 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55370 * @cfg {String} header The header text to display in the Grid view.
55373 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55374 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55375 * specified, the column's index is used as an index into the Record's data Array.
55378 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55379 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55382 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55383 * Defaults to the value of the {@link #defaultSortable} property.
55384 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55387 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55390 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55393 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55396 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55399 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55400 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55401 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55402 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55405 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55408 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55411 * @cfg {String} cursor (Optional)
55414 * @cfg {String} tooltip (Optional)
55417 * @cfg {Number} xs (Optional)
55420 * @cfg {Number} sm (Optional)
55423 * @cfg {Number} md (Optional)
55426 * @cfg {Number} lg (Optional)
55429 * Returns the id of the column at the specified index.
55430 * @param {Number} index The column index
55431 * @return {String} the id
55433 getColumnId : function(index){
55434 return this.config[index].id;
55438 * Returns the column for a specified id.
55439 * @param {String} id The column id
55440 * @return {Object} the column
55442 getColumnById : function(id){
55443 return this.lookup[id];
55448 * Returns the column for a specified dataIndex.
55449 * @param {String} dataIndex The column dataIndex
55450 * @return {Object|Boolean} the column or false if not found
55452 getColumnByDataIndex: function(dataIndex){
55453 var index = this.findColumnIndex(dataIndex);
55454 return index > -1 ? this.config[index] : false;
55458 * Returns the index for a specified column id.
55459 * @param {String} id The column id
55460 * @return {Number} the index, or -1 if not found
55462 getIndexById : function(id){
55463 for(var i = 0, len = this.config.length; i < len; i++){
55464 if(this.config[i].id == id){
55472 * Returns the index for a specified column dataIndex.
55473 * @param {String} dataIndex The column dataIndex
55474 * @return {Number} the index, or -1 if not found
55477 findColumnIndex : function(dataIndex){
55478 for(var i = 0, len = this.config.length; i < len; i++){
55479 if(this.config[i].dataIndex == dataIndex){
55487 moveColumn : function(oldIndex, newIndex){
55488 var c = this.config[oldIndex];
55489 this.config.splice(oldIndex, 1);
55490 this.config.splice(newIndex, 0, c);
55491 this.dataMap = null;
55492 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55495 isLocked : function(colIndex){
55496 return this.config[colIndex].locked === true;
55499 setLocked : function(colIndex, value, suppressEvent){
55500 if(this.isLocked(colIndex) == value){
55503 this.config[colIndex].locked = value;
55504 if(!suppressEvent){
55505 this.fireEvent("columnlockchange", this, colIndex, value);
55509 getTotalLockedWidth : function(){
55510 var totalWidth = 0;
55511 for(var i = 0; i < this.config.length; i++){
55512 if(this.isLocked(i) && !this.isHidden(i)){
55513 this.totalWidth += this.getColumnWidth(i);
55519 getLockedCount : function(){
55520 for(var i = 0, len = this.config.length; i < len; i++){
55521 if(!this.isLocked(i)){
55528 * Returns the number of columns.
55531 getColumnCount : function(visibleOnly){
55532 if(visibleOnly === true){
55534 for(var i = 0, len = this.config.length; i < len; i++){
55535 if(!this.isHidden(i)){
55541 return this.config.length;
55545 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55546 * @param {Function} fn
55547 * @param {Object} scope (optional)
55548 * @return {Array} result
55550 getColumnsBy : function(fn, scope){
55552 for(var i = 0, len = this.config.length; i < len; i++){
55553 var c = this.config[i];
55554 if(fn.call(scope||this, c, i) === true){
55562 * Returns true if the specified column is sortable.
55563 * @param {Number} col The column index
55564 * @return {Boolean}
55566 isSortable : function(col){
55567 if(typeof this.config[col].sortable == "undefined"){
55568 return this.defaultSortable;
55570 return this.config[col].sortable;
55574 * Returns the rendering (formatting) function defined for the column.
55575 * @param {Number} col The column index.
55576 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55578 getRenderer : function(col){
55579 if(!this.config[col].renderer){
55580 return Roo.grid.ColumnModel.defaultRenderer;
55582 return this.config[col].renderer;
55586 * Sets the rendering (formatting) function for a column.
55587 * @param {Number} col The column index
55588 * @param {Function} fn The function to use to process the cell's raw data
55589 * to return HTML markup for the grid view. The render function is called with
55590 * the following parameters:<ul>
55591 * <li>Data value.</li>
55592 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55593 * <li>css A CSS style string to apply to the table cell.</li>
55594 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55595 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55596 * <li>Row index</li>
55597 * <li>Column index</li>
55598 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55600 setRenderer : function(col, fn){
55601 this.config[col].renderer = fn;
55605 * Returns the width for the specified column.
55606 * @param {Number} col The column index
55609 getColumnWidth : function(col){
55610 return this.config[col].width * 1 || this.defaultWidth;
55614 * Sets the width for a column.
55615 * @param {Number} col The column index
55616 * @param {Number} width The new width
55618 setColumnWidth : function(col, width, suppressEvent){
55619 this.config[col].width = width;
55620 this.totalWidth = null;
55621 if(!suppressEvent){
55622 this.fireEvent("widthchange", this, col, width);
55627 * Returns the total width of all columns.
55628 * @param {Boolean} includeHidden True to include hidden column widths
55631 getTotalWidth : function(includeHidden){
55632 if(!this.totalWidth){
55633 this.totalWidth = 0;
55634 for(var i = 0, len = this.config.length; i < len; i++){
55635 if(includeHidden || !this.isHidden(i)){
55636 this.totalWidth += this.getColumnWidth(i);
55640 return this.totalWidth;
55644 * Returns the header for the specified column.
55645 * @param {Number} col The column index
55648 getColumnHeader : function(col){
55649 return this.config[col].header;
55653 * Sets the header for a column.
55654 * @param {Number} col The column index
55655 * @param {String} header The new header
55657 setColumnHeader : function(col, header){
55658 this.config[col].header = header;
55659 this.fireEvent("headerchange", this, col, header);
55663 * Returns the tooltip for the specified column.
55664 * @param {Number} col The column index
55667 getColumnTooltip : function(col){
55668 return this.config[col].tooltip;
55671 * Sets the tooltip for a column.
55672 * @param {Number} col The column index
55673 * @param {String} tooltip The new tooltip
55675 setColumnTooltip : function(col, tooltip){
55676 this.config[col].tooltip = tooltip;
55680 * Returns the dataIndex for the specified column.
55681 * @param {Number} col The column index
55684 getDataIndex : function(col){
55685 return this.config[col].dataIndex;
55689 * Sets the dataIndex for a column.
55690 * @param {Number} col The column index
55691 * @param {Number} dataIndex The new dataIndex
55693 setDataIndex : function(col, dataIndex){
55694 this.config[col].dataIndex = dataIndex;
55700 * Returns true if the cell is editable.
55701 * @param {Number} colIndex The column index
55702 * @param {Number} rowIndex The row index
55703 * @return {Boolean}
55705 isCellEditable : function(colIndex, rowIndex){
55706 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55710 * Returns the editor defined for the cell/column.
55711 * return false or null to disable editing.
55712 * @param {Number} colIndex The column index
55713 * @param {Number} rowIndex The row index
55716 getCellEditor : function(colIndex, rowIndex){
55717 return this.config[colIndex].editor;
55721 * Sets if a column is editable.
55722 * @param {Number} col The column index
55723 * @param {Boolean} editable True if the column is editable
55725 setEditable : function(col, editable){
55726 this.config[col].editable = editable;
55731 * Returns true if the column is hidden.
55732 * @param {Number} colIndex The column index
55733 * @return {Boolean}
55735 isHidden : function(colIndex){
55736 return this.config[colIndex].hidden;
55741 * Returns true if the column width cannot be changed
55743 isFixed : function(colIndex){
55744 return this.config[colIndex].fixed;
55748 * Returns true if the column can be resized
55749 * @return {Boolean}
55751 isResizable : function(colIndex){
55752 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55755 * Sets if a column is hidden.
55756 * @param {Number} colIndex The column index
55757 * @param {Boolean} hidden True if the column is hidden
55759 setHidden : function(colIndex, hidden){
55760 this.config[colIndex].hidden = hidden;
55761 this.totalWidth = null;
55762 this.fireEvent("hiddenchange", this, colIndex, hidden);
55766 * Sets the editor for a column.
55767 * @param {Number} col The column index
55768 * @param {Object} editor The editor object
55770 setEditor : function(col, editor){
55771 this.config[col].editor = editor;
55775 Roo.grid.ColumnModel.defaultRenderer = function(value){
55776 if(typeof value == "string" && value.length < 1){
55782 // Alias for backwards compatibility
55783 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55786 * Ext JS Library 1.1.1
55787 * Copyright(c) 2006-2007, Ext JS, LLC.
55789 * Originally Released Under LGPL - original licence link has changed is not relivant.
55792 * <script type="text/javascript">
55796 * @class Roo.grid.AbstractSelectionModel
55797 * @extends Roo.util.Observable
55798 * Abstract base class for grid SelectionModels. It provides the interface that should be
55799 * implemented by descendant classes. This class should not be directly instantiated.
55802 Roo.grid.AbstractSelectionModel = function(){
55803 this.locked = false;
55804 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55807 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55808 /** @ignore Called by the grid automatically. Do not call directly. */
55809 init : function(grid){
55815 * Locks the selections.
55818 this.locked = true;
55822 * Unlocks the selections.
55824 unlock : function(){
55825 this.locked = false;
55829 * Returns true if the selections are locked.
55830 * @return {Boolean}
55832 isLocked : function(){
55833 return this.locked;
55837 * Ext JS Library 1.1.1
55838 * Copyright(c) 2006-2007, Ext JS, LLC.
55840 * Originally Released Under LGPL - original licence link has changed is not relivant.
55843 * <script type="text/javascript">
55846 * @extends Roo.grid.AbstractSelectionModel
55847 * @class Roo.grid.RowSelectionModel
55848 * The default SelectionModel used by {@link Roo.grid.Grid}.
55849 * It supports multiple selections and keyboard selection/navigation.
55851 * @param {Object} config
55853 Roo.grid.RowSelectionModel = function(config){
55854 Roo.apply(this, config);
55855 this.selections = new Roo.util.MixedCollection(false, function(o){
55860 this.lastActive = false;
55864 * @event selectionchange
55865 * Fires when the selection changes
55866 * @param {SelectionModel} this
55868 "selectionchange" : true,
55870 * @event afterselectionchange
55871 * Fires after the selection changes (eg. by key press or clicking)
55872 * @param {SelectionModel} this
55874 "afterselectionchange" : true,
55876 * @event beforerowselect
55877 * Fires when a row is selected being selected, return false to cancel.
55878 * @param {SelectionModel} this
55879 * @param {Number} rowIndex The selected index
55880 * @param {Boolean} keepExisting False if other selections will be cleared
55882 "beforerowselect" : true,
55885 * Fires when a row is selected.
55886 * @param {SelectionModel} this
55887 * @param {Number} rowIndex The selected index
55888 * @param {Roo.data.Record} r The record
55890 "rowselect" : true,
55892 * @event rowdeselect
55893 * Fires when a row is deselected.
55894 * @param {SelectionModel} this
55895 * @param {Number} rowIndex The selected index
55897 "rowdeselect" : true
55899 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55900 this.locked = false;
55903 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55905 * @cfg {Boolean} singleSelect
55906 * True to allow selection of only one row at a time (defaults to false)
55908 singleSelect : false,
55911 initEvents : function(){
55913 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55914 this.grid.on("mousedown", this.handleMouseDown, this);
55915 }else{ // allow click to work like normal
55916 this.grid.on("rowclick", this.handleDragableRowClick, this);
55919 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55920 "up" : function(e){
55922 this.selectPrevious(e.shiftKey);
55923 }else if(this.last !== false && this.lastActive !== false){
55924 var last = this.last;
55925 this.selectRange(this.last, this.lastActive-1);
55926 this.grid.getView().focusRow(this.lastActive);
55927 if(last !== false){
55931 this.selectFirstRow();
55933 this.fireEvent("afterselectionchange", this);
55935 "down" : function(e){
55937 this.selectNext(e.shiftKey);
55938 }else if(this.last !== false && this.lastActive !== false){
55939 var last = this.last;
55940 this.selectRange(this.last, this.lastActive+1);
55941 this.grid.getView().focusRow(this.lastActive);
55942 if(last !== false){
55946 this.selectFirstRow();
55948 this.fireEvent("afterselectionchange", this);
55953 var view = this.grid.view;
55954 view.on("refresh", this.onRefresh, this);
55955 view.on("rowupdated", this.onRowUpdated, this);
55956 view.on("rowremoved", this.onRemove, this);
55960 onRefresh : function(){
55961 var ds = this.grid.dataSource, i, v = this.grid.view;
55962 var s = this.selections;
55963 s.each(function(r){
55964 if((i = ds.indexOfId(r.id)) != -1){
55966 s.add(ds.getAt(i)); // updating the selection relate data
55974 onRemove : function(v, index, r){
55975 this.selections.remove(r);
55979 onRowUpdated : function(v, index, r){
55980 if(this.isSelected(r)){
55981 v.onRowSelect(index);
55987 * @param {Array} records The records to select
55988 * @param {Boolean} keepExisting (optional) True to keep existing selections
55990 selectRecords : function(records, keepExisting){
55992 this.clearSelections();
55994 var ds = this.grid.dataSource;
55995 for(var i = 0, len = records.length; i < len; i++){
55996 this.selectRow(ds.indexOf(records[i]), true);
56001 * Gets the number of selected rows.
56004 getCount : function(){
56005 return this.selections.length;
56009 * Selects the first row in the grid.
56011 selectFirstRow : function(){
56016 * Select the last row.
56017 * @param {Boolean} keepExisting (optional) True to keep existing selections
56019 selectLastRow : function(keepExisting){
56020 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56024 * Selects the row immediately following the last selected row.
56025 * @param {Boolean} keepExisting (optional) True to keep existing selections
56027 selectNext : function(keepExisting){
56028 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56029 this.selectRow(this.last+1, keepExisting);
56030 this.grid.getView().focusRow(this.last);
56035 * Selects the row that precedes the last selected row.
56036 * @param {Boolean} keepExisting (optional) True to keep existing selections
56038 selectPrevious : function(keepExisting){
56040 this.selectRow(this.last-1, keepExisting);
56041 this.grid.getView().focusRow(this.last);
56046 * Returns the selected records
56047 * @return {Array} Array of selected records
56049 getSelections : function(){
56050 return [].concat(this.selections.items);
56054 * Returns the first selected record.
56057 getSelected : function(){
56058 return this.selections.itemAt(0);
56063 * Clears all selections.
56065 clearSelections : function(fast){
56066 if(this.locked) return;
56068 var ds = this.grid.dataSource;
56069 var s = this.selections;
56070 s.each(function(r){
56071 this.deselectRow(ds.indexOfId(r.id));
56075 this.selections.clear();
56082 * Selects all rows.
56084 selectAll : function(){
56085 if(this.locked) return;
56086 this.selections.clear();
56087 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56088 this.selectRow(i, true);
56093 * Returns True if there is a selection.
56094 * @return {Boolean}
56096 hasSelection : function(){
56097 return this.selections.length > 0;
56101 * Returns True if the specified row is selected.
56102 * @param {Number/Record} record The record or index of the record to check
56103 * @return {Boolean}
56105 isSelected : function(index){
56106 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56107 return (r && this.selections.key(r.id) ? true : false);
56111 * Returns True if the specified record id is selected.
56112 * @param {String} id The id of record to check
56113 * @return {Boolean}
56115 isIdSelected : function(id){
56116 return (this.selections.key(id) ? true : false);
56120 handleMouseDown : function(e, t){
56121 var view = this.grid.getView(), rowIndex;
56122 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56125 if(e.shiftKey && this.last !== false){
56126 var last = this.last;
56127 this.selectRange(last, rowIndex, e.ctrlKey);
56128 this.last = last; // reset the last
56129 view.focusRow(rowIndex);
56131 var isSelected = this.isSelected(rowIndex);
56132 if(e.button !== 0 && isSelected){
56133 view.focusRow(rowIndex);
56134 }else if(e.ctrlKey && isSelected){
56135 this.deselectRow(rowIndex);
56136 }else if(!isSelected){
56137 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56138 view.focusRow(rowIndex);
56141 this.fireEvent("afterselectionchange", this);
56144 handleDragableRowClick : function(grid, rowIndex, e)
56146 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56147 this.selectRow(rowIndex, false);
56148 grid.view.focusRow(rowIndex);
56149 this.fireEvent("afterselectionchange", this);
56154 * Selects multiple rows.
56155 * @param {Array} rows Array of the indexes of the row to select
56156 * @param {Boolean} keepExisting (optional) True to keep existing selections
56158 selectRows : function(rows, keepExisting){
56160 this.clearSelections();
56162 for(var i = 0, len = rows.length; i < len; i++){
56163 this.selectRow(rows[i], true);
56168 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56169 * @param {Number} startRow The index of the first row in the range
56170 * @param {Number} endRow The index of the last row in the range
56171 * @param {Boolean} keepExisting (optional) True to retain existing selections
56173 selectRange : function(startRow, endRow, keepExisting){
56174 if(this.locked) return;
56176 this.clearSelections();
56178 if(startRow <= endRow){
56179 for(var i = startRow; i <= endRow; i++){
56180 this.selectRow(i, true);
56183 for(var i = startRow; i >= endRow; i--){
56184 this.selectRow(i, true);
56190 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56191 * @param {Number} startRow The index of the first row in the range
56192 * @param {Number} endRow The index of the last row in the range
56194 deselectRange : function(startRow, endRow, preventViewNotify){
56195 if(this.locked) return;
56196 for(var i = startRow; i <= endRow; i++){
56197 this.deselectRow(i, preventViewNotify);
56203 * @param {Number} row The index of the row to select
56204 * @param {Boolean} keepExisting (optional) True to keep existing selections
56206 selectRow : function(index, keepExisting, preventViewNotify){
56207 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56208 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56209 if(!keepExisting || this.singleSelect){
56210 this.clearSelections();
56212 var r = this.grid.dataSource.getAt(index);
56213 this.selections.add(r);
56214 this.last = this.lastActive = index;
56215 if(!preventViewNotify){
56216 this.grid.getView().onRowSelect(index);
56218 this.fireEvent("rowselect", this, index, r);
56219 this.fireEvent("selectionchange", this);
56225 * @param {Number} row The index of the row to deselect
56227 deselectRow : function(index, preventViewNotify){
56228 if(this.locked) return;
56229 if(this.last == index){
56232 if(this.lastActive == index){
56233 this.lastActive = false;
56235 var r = this.grid.dataSource.getAt(index);
56236 this.selections.remove(r);
56237 if(!preventViewNotify){
56238 this.grid.getView().onRowDeselect(index);
56240 this.fireEvent("rowdeselect", this, index);
56241 this.fireEvent("selectionchange", this);
56245 restoreLast : function(){
56247 this.last = this._last;
56252 acceptsNav : function(row, col, cm){
56253 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56257 onEditorKey : function(field, e){
56258 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56263 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56265 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56267 }else if(k == e.ENTER && !e.ctrlKey){
56271 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56273 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56275 }else if(k == e.ESC){
56279 g.startEditing(newCell[0], newCell[1]);
56284 * Ext JS Library 1.1.1
56285 * Copyright(c) 2006-2007, Ext JS, LLC.
56287 * Originally Released Under LGPL - original licence link has changed is not relivant.
56290 * <script type="text/javascript">
56293 * @class Roo.grid.CellSelectionModel
56294 * @extends Roo.grid.AbstractSelectionModel
56295 * This class provides the basic implementation for cell selection in a grid.
56297 * @param {Object} config The object containing the configuration of this model.
56298 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56300 Roo.grid.CellSelectionModel = function(config){
56301 Roo.apply(this, config);
56303 this.selection = null;
56307 * @event beforerowselect
56308 * Fires before a cell is selected.
56309 * @param {SelectionModel} this
56310 * @param {Number} rowIndex The selected row index
56311 * @param {Number} colIndex The selected cell index
56313 "beforecellselect" : true,
56315 * @event cellselect
56316 * Fires when a cell is selected.
56317 * @param {SelectionModel} this
56318 * @param {Number} rowIndex The selected row index
56319 * @param {Number} colIndex The selected cell index
56321 "cellselect" : true,
56323 * @event selectionchange
56324 * Fires when the active selection changes.
56325 * @param {SelectionModel} this
56326 * @param {Object} selection null for no selection or an object (o) with two properties
56328 <li>o.record: the record object for the row the selection is in</li>
56329 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56332 "selectionchange" : true,
56335 * Fires when the tab (or enter) was pressed on the last editable cell
56336 * You can use this to trigger add new row.
56337 * @param {SelectionModel} this
56341 * @event beforeeditnext
56342 * Fires before the next editable sell is made active
56343 * You can use this to skip to another cell or fire the tabend
56344 * if you set cell to false
56345 * @param {Object} eventdata object : { cell : [ row, col ] }
56347 "beforeeditnext" : true
56349 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56352 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56354 enter_is_tab: false,
56357 initEvents : function(){
56358 this.grid.on("mousedown", this.handleMouseDown, this);
56359 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56360 var view = this.grid.view;
56361 view.on("refresh", this.onViewChange, this);
56362 view.on("rowupdated", this.onRowUpdated, this);
56363 view.on("beforerowremoved", this.clearSelections, this);
56364 view.on("beforerowsinserted", this.clearSelections, this);
56365 if(this.grid.isEditor){
56366 this.grid.on("beforeedit", this.beforeEdit, this);
56371 beforeEdit : function(e){
56372 this.select(e.row, e.column, false, true, e.record);
56376 onRowUpdated : function(v, index, r){
56377 if(this.selection && this.selection.record == r){
56378 v.onCellSelect(index, this.selection.cell[1]);
56383 onViewChange : function(){
56384 this.clearSelections(true);
56388 * Returns the currently selected cell,.
56389 * @return {Array} The selected cell (row, column) or null if none selected.
56391 getSelectedCell : function(){
56392 return this.selection ? this.selection.cell : null;
56396 * Clears all selections.
56397 * @param {Boolean} true to prevent the gridview from being notified about the change.
56399 clearSelections : function(preventNotify){
56400 var s = this.selection;
56402 if(preventNotify !== true){
56403 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56405 this.selection = null;
56406 this.fireEvent("selectionchange", this, null);
56411 * Returns true if there is a selection.
56412 * @return {Boolean}
56414 hasSelection : function(){
56415 return this.selection ? true : false;
56419 handleMouseDown : function(e, t){
56420 var v = this.grid.getView();
56421 if(this.isLocked()){
56424 var row = v.findRowIndex(t);
56425 var cell = v.findCellIndex(t);
56426 if(row !== false && cell !== false){
56427 this.select(row, cell);
56433 * @param {Number} rowIndex
56434 * @param {Number} collIndex
56436 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56437 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56438 this.clearSelections();
56439 r = r || this.grid.dataSource.getAt(rowIndex);
56442 cell : [rowIndex, colIndex]
56444 if(!preventViewNotify){
56445 var v = this.grid.getView();
56446 v.onCellSelect(rowIndex, colIndex);
56447 if(preventFocus !== true){
56448 v.focusCell(rowIndex, colIndex);
56451 this.fireEvent("cellselect", this, rowIndex, colIndex);
56452 this.fireEvent("selectionchange", this, this.selection);
56457 isSelectable : function(rowIndex, colIndex, cm){
56458 return !cm.isHidden(colIndex);
56462 handleKeyDown : function(e){
56463 //Roo.log('Cell Sel Model handleKeyDown');
56464 if(!e.isNavKeyPress()){
56467 var g = this.grid, s = this.selection;
56470 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56472 this.select(cell[0], cell[1]);
56477 var walk = function(row, col, step){
56478 return g.walkCells(row, col, step, sm.isSelectable, sm);
56480 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56487 // handled by onEditorKey
56488 if (g.isEditor && g.editing) {
56492 newCell = walk(r, c-1, -1);
56494 newCell = walk(r, c+1, 1);
56499 newCell = walk(r+1, c, 1);
56503 newCell = walk(r-1, c, -1);
56507 newCell = walk(r, c+1, 1);
56511 newCell = walk(r, c-1, -1);
56516 if(g.isEditor && !g.editing){
56517 g.startEditing(r, c);
56526 this.select(newCell[0], newCell[1]);
56532 acceptsNav : function(row, col, cm){
56533 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56537 * @param {Number} field (not used) - as it's normally used as a listener
56538 * @param {Number} e - event - fake it by using
56540 * var e = Roo.EventObjectImpl.prototype;
56541 * e.keyCode = e.TAB
56545 onEditorKey : function(field, e){
56547 var k = e.getKey(),
56550 ed = g.activeEditor,
56552 ///Roo.log('onEditorKey' + k);
56555 if (this.enter_is_tab && k == e.ENTER) {
56561 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56563 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56569 } else if(k == e.ENTER && !e.ctrlKey){
56572 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56574 } else if(k == e.ESC){
56579 var ecall = { cell : newCell, forward : forward };
56580 this.fireEvent('beforeeditnext', ecall );
56581 newCell = ecall.cell;
56582 forward = ecall.forward;
56586 //Roo.log('next cell after edit');
56587 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56588 } else if (forward) {
56589 // tabbed past last
56590 this.fireEvent.defer(100, this, ['tabend',this]);
56595 * Ext JS Library 1.1.1
56596 * Copyright(c) 2006-2007, Ext JS, LLC.
56598 * Originally Released Under LGPL - original licence link has changed is not relivant.
56601 * <script type="text/javascript">
56605 * @class Roo.grid.EditorGrid
56606 * @extends Roo.grid.Grid
56607 * Class for creating and editable grid.
56608 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56609 * The container MUST have some type of size defined for the grid to fill. The container will be
56610 * automatically set to position relative if it isn't already.
56611 * @param {Object} dataSource The data model to bind to
56612 * @param {Object} colModel The column model with info about this grid's columns
56614 Roo.grid.EditorGrid = function(container, config){
56615 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56616 this.getGridEl().addClass("xedit-grid");
56618 if(!this.selModel){
56619 this.selModel = new Roo.grid.CellSelectionModel();
56622 this.activeEditor = null;
56626 * @event beforeedit
56627 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56628 * <ul style="padding:5px;padding-left:16px;">
56629 * <li>grid - This grid</li>
56630 * <li>record - The record being edited</li>
56631 * <li>field - The field name being edited</li>
56632 * <li>value - The value for the field being edited.</li>
56633 * <li>row - The grid row index</li>
56634 * <li>column - The grid column index</li>
56635 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56637 * @param {Object} e An edit event (see above for description)
56639 "beforeedit" : true,
56642 * Fires after a cell is edited. <br />
56643 * <ul style="padding:5px;padding-left:16px;">
56644 * <li>grid - This grid</li>
56645 * <li>record - The record being edited</li>
56646 * <li>field - The field name being edited</li>
56647 * <li>value - The value being set</li>
56648 * <li>originalValue - The original value for the field, before the edit.</li>
56649 * <li>row - The grid row index</li>
56650 * <li>column - The grid column index</li>
56652 * @param {Object} e An edit event (see above for description)
56654 "afteredit" : true,
56656 * @event validateedit
56657 * Fires after a cell is edited, but before the value is set in the record.
56658 * You can use this to modify the value being set in the field, Return false
56659 * to cancel the change. The edit event object has the following properties <br />
56660 * <ul style="padding:5px;padding-left:16px;">
56661 * <li>editor - This editor</li>
56662 * <li>grid - This grid</li>
56663 * <li>record - The record being edited</li>
56664 * <li>field - The field name being edited</li>
56665 * <li>value - The value being set</li>
56666 * <li>originalValue - The original value for the field, before the edit.</li>
56667 * <li>row - The grid row index</li>
56668 * <li>column - The grid column index</li>
56669 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56671 * @param {Object} e An edit event (see above for description)
56673 "validateedit" : true
56675 this.on("bodyscroll", this.stopEditing, this);
56676 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56679 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56681 * @cfg {Number} clicksToEdit
56682 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56689 trackMouseOver: false, // causes very odd FF errors
56691 onCellDblClick : function(g, row, col){
56692 this.startEditing(row, col);
56695 onEditComplete : function(ed, value, startValue){
56696 this.editing = false;
56697 this.activeEditor = null;
56698 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56700 var field = this.colModel.getDataIndex(ed.col);
56705 originalValue: startValue,
56712 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56715 if(String(value) !== String(startValue)){
56717 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56718 r.set(field, e.value);
56719 // if we are dealing with a combo box..
56720 // then we also set the 'name' colum to be the displayField
56721 if (ed.field.displayField && ed.field.name) {
56722 r.set(ed.field.name, ed.field.el.dom.value);
56725 delete e.cancel; //?? why!!!
56726 this.fireEvent("afteredit", e);
56729 this.fireEvent("afteredit", e); // always fire it!
56731 this.view.focusCell(ed.row, ed.col);
56735 * Starts editing the specified for the specified row/column
56736 * @param {Number} rowIndex
56737 * @param {Number} colIndex
56739 startEditing : function(row, col){
56740 this.stopEditing();
56741 if(this.colModel.isCellEditable(col, row)){
56742 this.view.ensureVisible(row, col, true);
56744 var r = this.dataSource.getAt(row);
56745 var field = this.colModel.getDataIndex(col);
56746 var cell = Roo.get(this.view.getCell(row,col));
56751 value: r.data[field],
56756 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56757 this.editing = true;
56758 var ed = this.colModel.getCellEditor(col, row);
56764 ed.render(ed.parentEl || document.body);
56770 (function(){ // complex but required for focus issues in safari, ie and opera
56774 ed.on("complete", this.onEditComplete, this, {single: true});
56775 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56776 this.activeEditor = ed;
56777 var v = r.data[field];
56778 ed.startEdit(this.view.getCell(row, col), v);
56779 // combo's with 'displayField and name set
56780 if (ed.field.displayField && ed.field.name) {
56781 ed.field.el.dom.value = r.data[ed.field.name];
56785 }).defer(50, this);
56791 * Stops any active editing
56793 stopEditing : function(){
56794 if(this.activeEditor){
56795 this.activeEditor.completeEdit();
56797 this.activeEditor = null;
56801 * Called to get grid's drag proxy text, by default returns this.ddText.
56804 getDragDropText : function(){
56805 var count = this.selModel.getSelectedCell() ? 1 : 0;
56806 return String.format(this.ddText, count, count == 1 ? '' : 's');
56811 * Ext JS Library 1.1.1
56812 * Copyright(c) 2006-2007, Ext JS, LLC.
56814 * Originally Released Under LGPL - original licence link has changed is not relivant.
56817 * <script type="text/javascript">
56820 // private - not really -- you end up using it !
56821 // This is a support class used internally by the Grid components
56824 * @class Roo.grid.GridEditor
56825 * @extends Roo.Editor
56826 * Class for creating and editable grid elements.
56827 * @param {Object} config any settings (must include field)
56829 Roo.grid.GridEditor = function(field, config){
56830 if (!config && field.field) {
56832 field = Roo.factory(config.field, Roo.form);
56834 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56835 field.monitorTab = false;
56838 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56841 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56844 alignment: "tl-tl",
56847 cls: "x-small-editor x-grid-editor",
56852 * Ext JS Library 1.1.1
56853 * Copyright(c) 2006-2007, Ext JS, LLC.
56855 * Originally Released Under LGPL - original licence link has changed is not relivant.
56858 * <script type="text/javascript">
56863 Roo.grid.PropertyRecord = Roo.data.Record.create([
56864 {name:'name',type:'string'}, 'value'
56868 Roo.grid.PropertyStore = function(grid, source){
56870 this.store = new Roo.data.Store({
56871 recordType : Roo.grid.PropertyRecord
56873 this.store.on('update', this.onUpdate, this);
56875 this.setSource(source);
56877 Roo.grid.PropertyStore.superclass.constructor.call(this);
56882 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56883 setSource : function(o){
56885 this.store.removeAll();
56888 if(this.isEditableValue(o[k])){
56889 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56892 this.store.loadRecords({records: data}, {}, true);
56895 onUpdate : function(ds, record, type){
56896 if(type == Roo.data.Record.EDIT){
56897 var v = record.data['value'];
56898 var oldValue = record.modified['value'];
56899 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56900 this.source[record.id] = v;
56902 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56909 getProperty : function(row){
56910 return this.store.getAt(row);
56913 isEditableValue: function(val){
56914 if(val && val instanceof Date){
56916 }else if(typeof val == 'object' || typeof val == 'function'){
56922 setValue : function(prop, value){
56923 this.source[prop] = value;
56924 this.store.getById(prop).set('value', value);
56927 getSource : function(){
56928 return this.source;
56932 Roo.grid.PropertyColumnModel = function(grid, store){
56935 g.PropertyColumnModel.superclass.constructor.call(this, [
56936 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56937 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56939 this.store = store;
56940 this.bselect = Roo.DomHelper.append(document.body, {
56941 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56942 {tag: 'option', value: 'true', html: 'true'},
56943 {tag: 'option', value: 'false', html: 'false'}
56946 Roo.id(this.bselect);
56949 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56950 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56951 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56952 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56953 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56955 this.renderCellDelegate = this.renderCell.createDelegate(this);
56956 this.renderPropDelegate = this.renderProp.createDelegate(this);
56959 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56963 valueText : 'Value',
56965 dateFormat : 'm/j/Y',
56968 renderDate : function(dateVal){
56969 return dateVal.dateFormat(this.dateFormat);
56972 renderBool : function(bVal){
56973 return bVal ? 'true' : 'false';
56976 isCellEditable : function(colIndex, rowIndex){
56977 return colIndex == 1;
56980 getRenderer : function(col){
56982 this.renderCellDelegate : this.renderPropDelegate;
56985 renderProp : function(v){
56986 return this.getPropertyName(v);
56989 renderCell : function(val){
56991 if(val instanceof Date){
56992 rv = this.renderDate(val);
56993 }else if(typeof val == 'boolean'){
56994 rv = this.renderBool(val);
56996 return Roo.util.Format.htmlEncode(rv);
56999 getPropertyName : function(name){
57000 var pn = this.grid.propertyNames;
57001 return pn && pn[name] ? pn[name] : name;
57004 getCellEditor : function(colIndex, rowIndex){
57005 var p = this.store.getProperty(rowIndex);
57006 var n = p.data['name'], val = p.data['value'];
57008 if(typeof(this.grid.customEditors[n]) == 'string'){
57009 return this.editors[this.grid.customEditors[n]];
57011 if(typeof(this.grid.customEditors[n]) != 'undefined'){
57012 return this.grid.customEditors[n];
57014 if(val instanceof Date){
57015 return this.editors['date'];
57016 }else if(typeof val == 'number'){
57017 return this.editors['number'];
57018 }else if(typeof val == 'boolean'){
57019 return this.editors['boolean'];
57021 return this.editors['string'];
57027 * @class Roo.grid.PropertyGrid
57028 * @extends Roo.grid.EditorGrid
57029 * This class represents the interface of a component based property grid control.
57030 * <br><br>Usage:<pre><code>
57031 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57039 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57040 * The container MUST have some type of size defined for the grid to fill. The container will be
57041 * automatically set to position relative if it isn't already.
57042 * @param {Object} config A config object that sets properties on this grid.
57044 Roo.grid.PropertyGrid = function(container, config){
57045 config = config || {};
57046 var store = new Roo.grid.PropertyStore(this);
57047 this.store = store;
57048 var cm = new Roo.grid.PropertyColumnModel(this, store);
57049 store.store.sort('name', 'ASC');
57050 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57053 enableColLock:false,
57054 enableColumnMove:false,
57056 trackMouseOver: false,
57059 this.getGridEl().addClass('x-props-grid');
57060 this.lastEditRow = null;
57061 this.on('columnresize', this.onColumnResize, this);
57064 * @event beforepropertychange
57065 * Fires before a property changes (return false to stop?)
57066 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57067 * @param {String} id Record Id
57068 * @param {String} newval New Value
57069 * @param {String} oldval Old Value
57071 "beforepropertychange": true,
57073 * @event propertychange
57074 * Fires after a property changes
57075 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57076 * @param {String} id Record Id
57077 * @param {String} newval New Value
57078 * @param {String} oldval Old Value
57080 "propertychange": true
57082 this.customEditors = this.customEditors || {};
57084 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57087 * @cfg {Object} customEditors map of colnames=> custom editors.
57088 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57089 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57090 * false disables editing of the field.
57094 * @cfg {Object} propertyNames map of property Names to their displayed value
57097 render : function(){
57098 Roo.grid.PropertyGrid.superclass.render.call(this);
57099 this.autoSize.defer(100, this);
57102 autoSize : function(){
57103 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57105 this.view.fitColumns();
57109 onColumnResize : function(){
57110 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57114 * Sets the data for the Grid
57115 * accepts a Key => Value object of all the elements avaiable.
57116 * @param {Object} data to appear in grid.
57118 setSource : function(source){
57119 this.store.setSource(source);
57123 * Gets all the data from the grid.
57124 * @return {Object} data data stored in grid
57126 getSource : function(){
57127 return this.store.getSource();
57136 * @class Roo.grid.Calendar
57137 * @extends Roo.util.Grid
57138 * This class extends the Grid to provide a calendar widget
57139 * <br><br>Usage:<pre><code>
57140 var grid = new Roo.grid.Calendar("my-container-id", {
57143 selModel: mySelectionModel,
57144 autoSizeColumns: true,
57145 monitorWindowResize: false,
57146 trackMouseOver: true
57147 eventstore : real data store..
57153 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57154 * The container MUST have some type of size defined for the grid to fill. The container will be
57155 * automatically set to position relative if it isn't already.
57156 * @param {Object} config A config object that sets properties on this grid.
57158 Roo.grid.Calendar = function(container, config){
57159 // initialize the container
57160 this.container = Roo.get(container);
57161 this.container.update("");
57162 this.container.setStyle("overflow", "hidden");
57163 this.container.addClass('x-grid-container');
57165 this.id = this.container.id;
57167 Roo.apply(this, config);
57168 // check and correct shorthanded configs
57172 for (var r = 0;r < 6;r++) {
57175 for (var c =0;c < 7;c++) {
57179 if (this.eventStore) {
57180 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57181 this.eventStore.on('load',this.onLoad, this);
57182 this.eventStore.on('beforeload',this.clearEvents, this);
57186 this.dataSource = new Roo.data.Store({
57187 proxy: new Roo.data.MemoryProxy(rows),
57188 reader: new Roo.data.ArrayReader({}, [
57189 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57192 this.dataSource.load();
57193 this.ds = this.dataSource;
57194 this.ds.xmodule = this.xmodule || false;
57197 var cellRender = function(v,x,r)
57199 return String.format(
57200 '<div class="fc-day fc-widget-content"><div>' +
57201 '<div class="fc-event-container"></div>' +
57202 '<div class="fc-day-number">{0}</div>'+
57204 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57205 '</div></div>', v);
57210 this.colModel = new Roo.grid.ColumnModel( [
57212 xtype: 'ColumnModel',
57214 dataIndex : 'weekday0',
57216 renderer : cellRender
57219 xtype: 'ColumnModel',
57221 dataIndex : 'weekday1',
57223 renderer : cellRender
57226 xtype: 'ColumnModel',
57228 dataIndex : 'weekday2',
57229 header : 'Tuesday',
57230 renderer : cellRender
57233 xtype: 'ColumnModel',
57235 dataIndex : 'weekday3',
57236 header : 'Wednesday',
57237 renderer : cellRender
57240 xtype: 'ColumnModel',
57242 dataIndex : 'weekday4',
57243 header : 'Thursday',
57244 renderer : cellRender
57247 xtype: 'ColumnModel',
57249 dataIndex : 'weekday5',
57251 renderer : cellRender
57254 xtype: 'ColumnModel',
57256 dataIndex : 'weekday6',
57257 header : 'Saturday',
57258 renderer : cellRender
57261 this.cm = this.colModel;
57262 this.cm.xmodule = this.xmodule || false;
57266 //this.selModel = new Roo.grid.CellSelectionModel();
57267 //this.sm = this.selModel;
57268 //this.selModel.init(this);
57272 this.container.setWidth(this.width);
57276 this.container.setHeight(this.height);
57283 * The raw click event for the entire grid.
57284 * @param {Roo.EventObject} e
57289 * The raw dblclick event for the entire grid.
57290 * @param {Roo.EventObject} e
57294 * @event contextmenu
57295 * The raw contextmenu event for the entire grid.
57296 * @param {Roo.EventObject} e
57298 "contextmenu" : true,
57301 * The raw mousedown event for the entire grid.
57302 * @param {Roo.EventObject} e
57304 "mousedown" : true,
57307 * The raw mouseup event for the entire grid.
57308 * @param {Roo.EventObject} e
57313 * The raw mouseover event for the entire grid.
57314 * @param {Roo.EventObject} e
57316 "mouseover" : true,
57319 * The raw mouseout event for the entire grid.
57320 * @param {Roo.EventObject} e
57325 * The raw keypress event for the entire grid.
57326 * @param {Roo.EventObject} e
57331 * The raw keydown event for the entire grid.
57332 * @param {Roo.EventObject} e
57340 * Fires when a cell is clicked
57341 * @param {Grid} this
57342 * @param {Number} rowIndex
57343 * @param {Number} columnIndex
57344 * @param {Roo.EventObject} e
57346 "cellclick" : true,
57348 * @event celldblclick
57349 * Fires when a cell is double clicked
57350 * @param {Grid} this
57351 * @param {Number} rowIndex
57352 * @param {Number} columnIndex
57353 * @param {Roo.EventObject} e
57355 "celldblclick" : true,
57358 * Fires when a row is clicked
57359 * @param {Grid} this
57360 * @param {Number} rowIndex
57361 * @param {Roo.EventObject} e
57365 * @event rowdblclick
57366 * Fires when a row is double clicked
57367 * @param {Grid} this
57368 * @param {Number} rowIndex
57369 * @param {Roo.EventObject} e
57371 "rowdblclick" : true,
57373 * @event headerclick
57374 * Fires when a header is clicked
57375 * @param {Grid} this
57376 * @param {Number} columnIndex
57377 * @param {Roo.EventObject} e
57379 "headerclick" : true,
57381 * @event headerdblclick
57382 * Fires when a header cell is double clicked
57383 * @param {Grid} this
57384 * @param {Number} columnIndex
57385 * @param {Roo.EventObject} e
57387 "headerdblclick" : true,
57389 * @event rowcontextmenu
57390 * Fires when a row is right clicked
57391 * @param {Grid} this
57392 * @param {Number} rowIndex
57393 * @param {Roo.EventObject} e
57395 "rowcontextmenu" : true,
57397 * @event cellcontextmenu
57398 * Fires when a cell is right clicked
57399 * @param {Grid} this
57400 * @param {Number} rowIndex
57401 * @param {Number} cellIndex
57402 * @param {Roo.EventObject} e
57404 "cellcontextmenu" : true,
57406 * @event headercontextmenu
57407 * Fires when a header is right clicked
57408 * @param {Grid} this
57409 * @param {Number} columnIndex
57410 * @param {Roo.EventObject} e
57412 "headercontextmenu" : true,
57414 * @event bodyscroll
57415 * Fires when the body element is scrolled
57416 * @param {Number} scrollLeft
57417 * @param {Number} scrollTop
57419 "bodyscroll" : true,
57421 * @event columnresize
57422 * Fires when the user resizes a column
57423 * @param {Number} columnIndex
57424 * @param {Number} newSize
57426 "columnresize" : true,
57428 * @event columnmove
57429 * Fires when the user moves a column
57430 * @param {Number} oldIndex
57431 * @param {Number} newIndex
57433 "columnmove" : true,
57436 * Fires when row(s) start being dragged
57437 * @param {Grid} this
57438 * @param {Roo.GridDD} dd The drag drop object
57439 * @param {event} e The raw browser event
57441 "startdrag" : true,
57444 * Fires when a drag operation is complete
57445 * @param {Grid} this
57446 * @param {Roo.GridDD} dd The drag drop object
57447 * @param {event} e The raw browser event
57452 * Fires when dragged row(s) are dropped on a valid DD target
57453 * @param {Grid} this
57454 * @param {Roo.GridDD} dd The drag drop object
57455 * @param {String} targetId The target drag drop object
57456 * @param {event} e The raw browser event
57461 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57462 * @param {Grid} this
57463 * @param {Roo.GridDD} dd The drag drop object
57464 * @param {String} targetId The target drag drop object
57465 * @param {event} e The raw browser event
57470 * Fires when the dragged row(s) first cross another DD target while being dragged
57471 * @param {Grid} this
57472 * @param {Roo.GridDD} dd The drag drop object
57473 * @param {String} targetId The target drag drop object
57474 * @param {event} e The raw browser event
57476 "dragenter" : true,
57479 * Fires when the dragged row(s) leave another DD target while being dragged
57480 * @param {Grid} this
57481 * @param {Roo.GridDD} dd The drag drop object
57482 * @param {String} targetId The target drag drop object
57483 * @param {event} e The raw browser event
57488 * Fires when a row is rendered, so you can change add a style to it.
57489 * @param {GridView} gridview The grid view
57490 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57496 * Fires when the grid is rendered
57497 * @param {Grid} grid
57502 * Fires when a date is selected
57503 * @param {DatePicker} this
57504 * @param {Date} date The selected date
57508 * @event monthchange
57509 * Fires when the displayed month changes
57510 * @param {DatePicker} this
57511 * @param {Date} date The selected month
57513 'monthchange': true,
57515 * @event evententer
57516 * Fires when mouse over an event
57517 * @param {Calendar} this
57518 * @param {event} Event
57520 'evententer': true,
57522 * @event eventleave
57523 * Fires when the mouse leaves an
57524 * @param {Calendar} this
57527 'eventleave': true,
57529 * @event eventclick
57530 * Fires when the mouse click an
57531 * @param {Calendar} this
57534 'eventclick': true,
57536 * @event eventrender
57537 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57538 * @param {Calendar} this
57539 * @param {data} data to be modified
57541 'eventrender': true
57545 Roo.grid.Grid.superclass.constructor.call(this);
57546 this.on('render', function() {
57547 this.view.el.addClass('x-grid-cal');
57549 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57553 if (!Roo.grid.Calendar.style) {
57554 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57557 '.x-grid-cal .x-grid-col' : {
57558 height: 'auto !important',
57559 'vertical-align': 'top'
57561 '.x-grid-cal .fc-event-hori' : {
57572 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57574 * @cfg {Store} eventStore The store that loads events.
57579 activeDate : false,
57582 monitorWindowResize : false,
57585 resizeColumns : function() {
57586 var col = (this.view.el.getWidth() / 7) - 3;
57587 // loop through cols, and setWidth
57588 for(var i =0 ; i < 7 ; i++){
57589 this.cm.setColumnWidth(i, col);
57592 setDate :function(date) {
57594 Roo.log('setDate?');
57596 this.resizeColumns();
57597 var vd = this.activeDate;
57598 this.activeDate = date;
57599 // if(vd && this.el){
57600 // var t = date.getTime();
57601 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57602 // Roo.log('using add remove');
57604 // this.fireEvent('monthchange', this, date);
57606 // this.cells.removeClass("fc-state-highlight");
57607 // this.cells.each(function(c){
57608 // if(c.dateValue == t){
57609 // c.addClass("fc-state-highlight");
57610 // setTimeout(function(){
57611 // try{c.dom.firstChild.focus();}catch(e){}
57621 var days = date.getDaysInMonth();
57623 var firstOfMonth = date.getFirstDateOfMonth();
57624 var startingPos = firstOfMonth.getDay()-this.startDay;
57626 if(startingPos < this.startDay){
57630 var pm = date.add(Date.MONTH, -1);
57631 var prevStart = pm.getDaysInMonth()-startingPos;
57635 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57637 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57638 //this.cells.addClassOnOver('fc-state-hover');
57640 var cells = this.cells.elements;
57641 var textEls = this.textNodes;
57643 //Roo.each(cells, function(cell){
57644 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57647 days += startingPos;
57649 // convert everything to numbers so it's fast
57650 var day = 86400000;
57651 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57654 //Roo.log(prevStart);
57656 var today = new Date().clearTime().getTime();
57657 var sel = date.clearTime().getTime();
57658 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57659 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57660 var ddMatch = this.disabledDatesRE;
57661 var ddText = this.disabledDatesText;
57662 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57663 var ddaysText = this.disabledDaysText;
57664 var format = this.format;
57666 var setCellClass = function(cal, cell){
57668 //Roo.log('set Cell Class');
57670 var t = d.getTime();
57675 cell.dateValue = t;
57677 cell.className += " fc-today";
57678 cell.className += " fc-state-highlight";
57679 cell.title = cal.todayText;
57682 // disable highlight in other month..
57683 cell.className += " fc-state-highlight";
57688 //cell.className = " fc-state-disabled";
57689 cell.title = cal.minText;
57693 //cell.className = " fc-state-disabled";
57694 cell.title = cal.maxText;
57698 if(ddays.indexOf(d.getDay()) != -1){
57699 // cell.title = ddaysText;
57700 // cell.className = " fc-state-disabled";
57703 if(ddMatch && format){
57704 var fvalue = d.dateFormat(format);
57705 if(ddMatch.test(fvalue)){
57706 cell.title = ddText.replace("%0", fvalue);
57707 cell.className = " fc-state-disabled";
57711 if (!cell.initialClassName) {
57712 cell.initialClassName = cell.dom.className;
57715 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57720 for(; i < startingPos; i++) {
57721 cells[i].dayName = (++prevStart);
57722 Roo.log(textEls[i]);
57723 d.setDate(d.getDate()+1);
57725 //cells[i].className = "fc-past fc-other-month";
57726 setCellClass(this, cells[i]);
57731 for(; i < days; i++){
57732 intDay = i - startingPos + 1;
57733 cells[i].dayName = (intDay);
57734 d.setDate(d.getDate()+1);
57736 cells[i].className = ''; // "x-date-active";
57737 setCellClass(this, cells[i]);
57741 for(; i < 42; i++) {
57742 //textEls[i].innerHTML = (++extraDays);
57744 d.setDate(d.getDate()+1);
57745 cells[i].dayName = (++extraDays);
57746 cells[i].className = "fc-future fc-other-month";
57747 setCellClass(this, cells[i]);
57750 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57752 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57754 // this will cause all the cells to mis
57757 for (var r = 0;r < 6;r++) {
57758 for (var c =0;c < 7;c++) {
57759 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57763 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57764 for(i=0;i<cells.length;i++) {
57766 this.cells.elements[i].dayName = cells[i].dayName ;
57767 this.cells.elements[i].className = cells[i].className;
57768 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57769 this.cells.elements[i].title = cells[i].title ;
57770 this.cells.elements[i].dateValue = cells[i].dateValue ;
57776 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57777 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57779 ////if(totalRows != 6){
57780 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57781 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57784 this.fireEvent('monthchange', this, date);
57789 * Returns the grid's SelectionModel.
57790 * @return {SelectionModel}
57792 getSelectionModel : function(){
57793 if(!this.selModel){
57794 this.selModel = new Roo.grid.CellSelectionModel();
57796 return this.selModel;
57800 this.eventStore.load()
57806 findCell : function(dt) {
57807 dt = dt.clearTime().getTime();
57809 this.cells.each(function(c){
57810 //Roo.log("check " +c.dateValue + '?=' + dt);
57811 if(c.dateValue == dt){
57821 findCells : function(rec) {
57822 var s = rec.data.start_dt.clone().clearTime().getTime();
57824 var e= rec.data.end_dt.clone().clearTime().getTime();
57827 this.cells.each(function(c){
57828 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57830 if(c.dateValue > e){
57833 if(c.dateValue < s){
57842 findBestRow: function(cells)
57846 for (var i =0 ; i < cells.length;i++) {
57847 ret = Math.max(cells[i].rows || 0,ret);
57854 addItem : function(rec)
57856 // look for vertical location slot in
57857 var cells = this.findCells(rec);
57859 rec.row = this.findBestRow(cells);
57861 // work out the location.
57865 for(var i =0; i < cells.length; i++) {
57873 if (crow.start.getY() == cells[i].getY()) {
57875 crow.end = cells[i];
57891 for (var i = 0; i < cells.length;i++) {
57892 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57899 clearEvents: function() {
57901 if (!this.eventStore.getCount()) {
57904 // reset number of rows in cells.
57905 Roo.each(this.cells.elements, function(c){
57909 this.eventStore.each(function(e) {
57910 this.clearEvent(e);
57915 clearEvent : function(ev)
57918 Roo.each(ev.els, function(el) {
57919 el.un('mouseenter' ,this.onEventEnter, this);
57920 el.un('mouseleave' ,this.onEventLeave, this);
57928 renderEvent : function(ev,ctr) {
57930 ctr = this.view.el.select('.fc-event-container',true).first();
57934 this.clearEvent(ev);
57940 var cells = ev.cells;
57941 var rows = ev.rows;
57942 this.fireEvent('eventrender', this, ev);
57944 for(var i =0; i < rows.length; i++) {
57948 cls += ' fc-event-start';
57950 if ((i+1) == rows.length) {
57951 cls += ' fc-event-end';
57954 //Roo.log(ev.data);
57955 // how many rows should it span..
57956 var cg = this.eventTmpl.append(ctr,Roo.apply({
57959 }, ev.data) , true);
57962 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57963 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57964 cg.on('click', this.onEventClick, this, ev);
57968 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57969 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57972 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57973 cg.setWidth(ebox.right - sbox.x -2);
57977 renderEvents: function()
57979 // first make sure there is enough space..
57981 if (!this.eventTmpl) {
57982 this.eventTmpl = new Roo.Template(
57983 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57984 '<div class="fc-event-inner">' +
57985 '<span class="fc-event-time">{time}</span>' +
57986 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57988 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57996 this.cells.each(function(c) {
57997 //Roo.log(c.select('.fc-day-content div',true).first());
57998 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
58001 var ctr = this.view.el.select('.fc-event-container',true).first();
58004 this.eventStore.each(function(ev){
58006 this.renderEvent(ev);
58010 this.view.layout();
58014 onEventEnter: function (e, el,event,d) {
58015 this.fireEvent('evententer', this, el, event);
58018 onEventLeave: function (e, el,event,d) {
58019 this.fireEvent('eventleave', this, el, event);
58022 onEventClick: function (e, el,event,d) {
58023 this.fireEvent('eventclick', this, el, event);
58026 onMonthChange: function () {
58030 onLoad: function () {
58032 //Roo.log('calendar onload');
58034 if(this.eventStore.getCount() > 0){
58038 this.eventStore.each(function(d){
58043 if (typeof(add.end_dt) == 'undefined') {
58044 Roo.log("Missing End time in calendar data: ");
58048 if (typeof(add.start_dt) == 'undefined') {
58049 Roo.log("Missing Start time in calendar data: ");
58053 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58054 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58055 add.id = add.id || d.id;
58056 add.title = add.title || '??';
58064 this.renderEvents();
58074 render : function ()
58078 if (!this.view.el.hasClass('course-timesheet')) {
58079 this.view.el.addClass('course-timesheet');
58081 if (this.tsStyle) {
58086 Roo.log(_this.grid.view.el.getWidth());
58089 this.tsStyle = Roo.util.CSS.createStyleSheet({
58090 '.course-timesheet .x-grid-row' : {
58093 '.x-grid-row td' : {
58094 'vertical-align' : 0
58096 '.course-edit-link' : {
58098 'text-overflow' : 'ellipsis',
58099 'overflow' : 'hidden',
58100 'white-space' : 'nowrap',
58101 'cursor' : 'pointer'
58106 '.de-act-sup-link' : {
58107 'color' : 'purple',
58108 'text-decoration' : 'line-through'
58112 'text-decoration' : 'line-through'
58114 '.course-timesheet .course-highlight' : {
58115 'border-top-style': 'dashed !important',
58116 'border-bottom-bottom': 'dashed !important'
58118 '.course-timesheet .course-item' : {
58119 'font-family' : 'tahoma, arial, helvetica',
58120 'font-size' : '11px',
58121 'overflow' : 'hidden',
58122 'padding-left' : '10px',
58123 'padding-right' : '10px',
58124 'padding-top' : '10px'
58132 monitorWindowResize : false,
58133 cellrenderer : function(v,x,r)
58138 xtype: 'CellSelectionModel',
58145 beforeload : function (_self, options)
58147 options.params = options.params || {};
58148 options.params._month = _this.monthField.getValue();
58149 options.params.limit = 9999;
58150 options.params['sort'] = 'when_dt';
58151 options.params['dir'] = 'ASC';
58152 this.proxy.loadResponse = this.loadResponse;
58154 //this.addColumns();
58156 load : function (_self, records, options)
58158 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58159 // if you click on the translation.. you can edit it...
58160 var el = Roo.get(this);
58161 var id = el.dom.getAttribute('data-id');
58162 var d = el.dom.getAttribute('data-date');
58163 var t = el.dom.getAttribute('data-time');
58164 //var id = this.child('span').dom.textContent;
58167 Pman.Dialog.CourseCalendar.show({
58171 productitem_active : id ? 1 : 0
58173 _this.grid.ds.load({});
58178 _this.panel.fireEvent('resize', [ '', '' ]);
58181 loadResponse : function(o, success, response){
58182 // this is overridden on before load..
58184 Roo.log("our code?");
58185 //Roo.log(success);
58186 //Roo.log(response)
58187 delete this.activeRequest;
58189 this.fireEvent("loadexception", this, o, response);
58190 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58195 result = o.reader.read(response);
58197 Roo.log("load exception?");
58198 this.fireEvent("loadexception", this, o, response, e);
58199 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58202 Roo.log("ready...");
58203 // loop through result.records;
58204 // and set this.tdate[date] = [] << array of records..
58206 Roo.each(result.records, function(r){
58208 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58209 _this.tdata[r.data.when_dt.format('j')] = [];
58211 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58214 //Roo.log(_this.tdata);
58216 result.records = [];
58217 result.totalRecords = 6;
58219 // let's generate some duumy records for the rows.
58220 //var st = _this.dateField.getValue();
58222 // work out monday..
58223 //st = st.add(Date.DAY, -1 * st.format('w'));
58225 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58227 var firstOfMonth = date.getFirstDayOfMonth();
58228 var days = date.getDaysInMonth();
58230 var firstAdded = false;
58231 for (var i = 0; i < result.totalRecords ; i++) {
58232 //var d= st.add(Date.DAY, i);
58235 for(var w = 0 ; w < 7 ; w++){
58236 if(!firstAdded && firstOfMonth != w){
58243 var dd = (d > 0 && d < 10) ? "0"+d : d;
58244 row['weekday'+w] = String.format(
58245 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58246 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58248 date.format('Y-m-')+dd
58251 if(typeof(_this.tdata[d]) != 'undefined'){
58252 Roo.each(_this.tdata[d], function(r){
58256 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58257 if(r.parent_id*1>0){
58258 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58261 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58262 deactive = 'de-act-link';
58265 row['weekday'+w] += String.format(
58266 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58268 r.product_id_name, //1
58269 r.when_dt.format('h:ia'), //2
58279 // only do this if something added..
58281 result.records.push(_this.grid.dataSource.reader.newRow(row));
58285 // push it twice. (second one with an hour..
58289 this.fireEvent("load", this, o, o.request.arg);
58290 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58292 sortInfo : {field: 'when_dt', direction : 'ASC' },
58294 xtype: 'HttpProxy',
58297 url : baseURL + '/Roo/Shop_course.php'
58300 xtype: 'JsonReader',
58317 'name': 'parent_id',
58321 'name': 'product_id',
58325 'name': 'productitem_id',
58343 click : function (_self, e)
58345 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58346 sd.setMonth(sd.getMonth()-1);
58347 _this.monthField.setValue(sd.format('Y-m-d'));
58348 _this.grid.ds.load({});
58354 xtype: 'Separator',
58358 xtype: 'MonthField',
58361 render : function (_self)
58363 _this.monthField = _self;
58364 // _this.monthField.set today
58366 select : function (combo, date)
58368 _this.grid.ds.load({});
58371 value : (function() { return new Date(); })()
58374 xtype: 'Separator',
58380 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58390 click : function (_self, e)
58392 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58393 sd.setMonth(sd.getMonth()+1);
58394 _this.monthField.setValue(sd.format('Y-m-d'));
58395 _this.grid.ds.load({});
58408 * Ext JS Library 1.1.1
58409 * Copyright(c) 2006-2007, Ext JS, LLC.
58411 * Originally Released Under LGPL - original licence link has changed is not relivant.
58414 * <script type="text/javascript">
58418 * @class Roo.LoadMask
58419 * A simple utility class for generically masking elements while loading data. If the element being masked has
58420 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58421 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58422 * element's UpdateManager load indicator and will be destroyed after the initial load.
58424 * Create a new LoadMask
58425 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58426 * @param {Object} config The config object
58428 Roo.LoadMask = function(el, config){
58429 this.el = Roo.get(el);
58430 Roo.apply(this, config);
58432 this.store.on('beforeload', this.onBeforeLoad, this);
58433 this.store.on('load', this.onLoad, this);
58434 this.store.on('loadexception', this.onLoadException, this);
58435 this.removeMask = false;
58437 var um = this.el.getUpdateManager();
58438 um.showLoadIndicator = false; // disable the default indicator
58439 um.on('beforeupdate', this.onBeforeLoad, this);
58440 um.on('update', this.onLoad, this);
58441 um.on('failure', this.onLoad, this);
58442 this.removeMask = true;
58446 Roo.LoadMask.prototype = {
58448 * @cfg {Boolean} removeMask
58449 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58450 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58453 * @cfg {String} msg
58454 * The text to display in a centered loading message box (defaults to 'Loading...')
58456 msg : 'Loading...',
58458 * @cfg {String} msgCls
58459 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58461 msgCls : 'x-mask-loading',
58464 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58470 * Disables the mask to prevent it from being displayed
58472 disable : function(){
58473 this.disabled = true;
58477 * Enables the mask so that it can be displayed
58479 enable : function(){
58480 this.disabled = false;
58483 onLoadException : function()
58485 Roo.log(arguments);
58487 if (typeof(arguments[3]) != 'undefined') {
58488 Roo.MessageBox.alert("Error loading",arguments[3]);
58492 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58493 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58502 this.el.unmask(this.removeMask);
58505 onLoad : function()
58507 this.el.unmask(this.removeMask);
58511 onBeforeLoad : function(){
58512 if(!this.disabled){
58513 this.el.mask(this.msg, this.msgCls);
58518 destroy : function(){
58520 this.store.un('beforeload', this.onBeforeLoad, this);
58521 this.store.un('load', this.onLoad, this);
58522 this.store.un('loadexception', this.onLoadException, this);
58524 var um = this.el.getUpdateManager();
58525 um.un('beforeupdate', this.onBeforeLoad, this);
58526 um.un('update', this.onLoad, this);
58527 um.un('failure', this.onLoad, this);
58532 * Ext JS Library 1.1.1
58533 * Copyright(c) 2006-2007, Ext JS, LLC.
58535 * Originally Released Under LGPL - original licence link has changed is not relivant.
58538 * <script type="text/javascript">
58543 * @class Roo.XTemplate
58544 * @extends Roo.Template
58545 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58547 var t = new Roo.XTemplate(
58548 '<select name="{name}">',
58549 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58553 // then append, applying the master template values
58556 * Supported features:
58561 {a_variable} - output encoded.
58562 {a_variable.format:("Y-m-d")} - call a method on the variable
58563 {a_variable:raw} - unencoded output
58564 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58565 {a_variable:this.method_on_template(...)} - call a method on the template object.
58570 <tpl for="a_variable or condition.."></tpl>
58571 <tpl if="a_variable or condition"></tpl>
58572 <tpl exec="some javascript"></tpl>
58573 <tpl name="named_template"></tpl> (experimental)
58575 <tpl for="."></tpl> - just iterate the property..
58576 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58580 Roo.XTemplate = function()
58582 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58589 Roo.extend(Roo.XTemplate, Roo.Template, {
58592 * The various sub templates
58597 * basic tag replacing syntax
58600 * // you can fake an object call by doing this
58604 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58607 * compile the template
58609 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58612 compile: function()
58616 s = ['<tpl>', s, '</tpl>'].join('');
58618 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58619 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58620 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58621 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58622 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58627 while(true == !!(m = s.match(re))){
58628 var forMatch = m[0].match(nameRe),
58629 ifMatch = m[0].match(ifRe),
58630 execMatch = m[0].match(execRe),
58631 namedMatch = m[0].match(namedRe),
58636 name = forMatch && forMatch[1] ? forMatch[1] : '';
58639 // if - puts fn into test..
58640 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58642 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58647 // exec - calls a function... returns empty if true is returned.
58648 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58650 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58658 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58659 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58660 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58663 var uid = namedMatch ? namedMatch[1] : id;
58667 id: namedMatch ? namedMatch[1] : id,
58674 s = s.replace(m[0], '');
58676 s = s.replace(m[0], '{xtpl'+ id + '}');
58681 for(var i = tpls.length-1; i >= 0; --i){
58682 this.compileTpl(tpls[i]);
58683 this.tpls[tpls[i].id] = tpls[i];
58685 this.master = tpls[tpls.length-1];
58689 * same as applyTemplate, except it's done to one of the subTemplates
58690 * when using named templates, you can do:
58692 * var str = pl.applySubTemplate('your-name', values);
58695 * @param {Number} id of the template
58696 * @param {Object} values to apply to template
58697 * @param {Object} parent (normaly the instance of this object)
58699 applySubTemplate : function(id, values, parent)
58703 var t = this.tpls[id];
58707 if(t.test && !t.test.call(this, values, parent)){
58711 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58712 Roo.log(e.toString());
58718 if(t.exec && t.exec.call(this, values, parent)){
58722 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58723 Roo.log(e.toString());
58728 var vs = t.target ? t.target.call(this, values, parent) : values;
58729 parent = t.target ? values : parent;
58730 if(t.target && vs instanceof Array){
58732 for(var i = 0, len = vs.length; i < len; i++){
58733 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58735 return buf.join('');
58737 return t.compiled.call(this, vs, parent);
58739 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58740 Roo.log(e.toString());
58741 Roo.log(t.compiled);
58746 compileTpl : function(tpl)
58748 var fm = Roo.util.Format;
58749 var useF = this.disableFormats !== true;
58750 var sep = Roo.isGecko ? "+" : ",";
58751 var undef = function(str) {
58752 Roo.log("Property not found :" + str);
58756 var fn = function(m, name, format, args)
58758 //Roo.log(arguments);
58759 args = args ? args.replace(/\\'/g,"'") : args;
58760 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58761 if (typeof(format) == 'undefined') {
58762 format= 'htmlEncode';
58764 if (format == 'raw' ) {
58768 if(name.substr(0, 4) == 'xtpl'){
58769 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58772 // build an array of options to determine if value is undefined..
58774 // basically get 'xxxx.yyyy' then do
58775 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58776 // (function () { Roo.log("Property not found"); return ''; })() :
58781 Roo.each(name.split('.'), function(st) {
58782 lookfor += (lookfor.length ? '.': '') + st;
58783 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58786 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58789 if(format && useF){
58791 args = args ? ',' + args : "";
58793 if(format.substr(0, 5) != "this."){
58794 format = "fm." + format + '(';
58796 format = 'this.call("'+ format.substr(5) + '", ';
58800 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58804 // called with xxyx.yuu:(test,test)
58806 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58808 // raw.. - :raw modifier..
58809 return "'"+ sep + udef_st + name + ")"+sep+"'";
58813 // branched to use + in gecko and [].join() in others
58815 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58816 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58819 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58820 body.push(tpl.body.replace(/(\r\n|\n)/g,
58821 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58822 body.push("'].join('');};};");
58823 body = body.join('');
58826 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58828 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58834 applyTemplate : function(values){
58835 return this.master.compiled.call(this, values, {});
58836 //var s = this.subs;
58839 apply : function(){
58840 return this.applyTemplate.apply(this, arguments);
58845 Roo.XTemplate.from = function(el){
58846 el = Roo.getDom(el);
58847 return new Roo.XTemplate(el.value || el.innerHTML);