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 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35701 ul.on("mouseover", this.onMouseOver, this);
35702 ul.on("mouseout", this.onMouseOut, this);
35703 this.items.each(function(item){
35708 var li = document.createElement("li");
35709 li.className = "x-menu-list-item";
35710 ul.dom.appendChild(li);
35711 item.render(li, this);
35718 autoWidth : function(){
35719 var el = this.el, ul = this.ul;
35723 var w = this.width;
35726 }else if(Roo.isIE){
35727 el.setWidth(this.minWidth);
35728 var t = el.dom.offsetWidth; // force recalc
35729 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35734 delayAutoWidth : function(){
35737 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35739 this.awTask.delay(20);
35744 findTargetItem : function(e){
35745 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35746 if(t && t.menuItemId){
35747 return this.items.get(t.menuItemId);
35752 onClick : function(e){
35753 Roo.log("menu.onClick");
35754 var t = this.findTargetItem(e);
35759 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35760 if(t == this.activeItem && t.shouldDeactivate(e)){
35761 this.activeItem.deactivate();
35762 delete this.activeItem;
35766 this.setActiveItem(t, true);
35774 this.fireEvent("click", this, t, e);
35778 setActiveItem : function(item, autoExpand){
35779 if(item != this.activeItem){
35780 if(this.activeItem){
35781 this.activeItem.deactivate();
35783 this.activeItem = item;
35784 item.activate(autoExpand);
35785 }else if(autoExpand){
35791 tryActivate : function(start, step){
35792 var items = this.items;
35793 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35794 var item = items.get(i);
35795 if(!item.disabled && item.canActivate){
35796 this.setActiveItem(item, false);
35804 onMouseOver : function(e){
35806 if(t = this.findTargetItem(e)){
35807 if(t.canActivate && !t.disabled){
35808 this.setActiveItem(t, true);
35811 this.fireEvent("mouseover", this, e, t);
35815 onMouseOut : function(e){
35817 if(t = this.findTargetItem(e)){
35818 if(t == this.activeItem && t.shouldDeactivate(e)){
35819 this.activeItem.deactivate();
35820 delete this.activeItem;
35823 this.fireEvent("mouseout", this, e, t);
35827 * Read-only. Returns true if the menu is currently displayed, else false.
35830 isVisible : function(){
35831 return this.el && !this.hidden;
35835 * Displays this menu relative to another element
35836 * @param {String/HTMLElement/Roo.Element} element The element to align to
35837 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35838 * the element (defaults to this.defaultAlign)
35839 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35841 show : function(el, pos, parentMenu){
35842 this.parentMenu = parentMenu;
35846 this.fireEvent("beforeshow", this);
35847 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35851 * Displays this menu at a specific xy position
35852 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35853 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35855 showAt : function(xy, parentMenu, /* private: */_e){
35856 this.parentMenu = parentMenu;
35861 this.fireEvent("beforeshow", this);
35862 xy = this.el.adjustForConstraints(xy);
35866 this.hidden = false;
35868 this.fireEvent("show", this);
35871 focus : function(){
35873 this.doFocus.defer(50, this);
35877 doFocus : function(){
35879 this.focusEl.focus();
35884 * Hides this menu and optionally all parent menus
35885 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35887 hide : function(deep){
35888 if(this.el && this.isVisible()){
35889 this.fireEvent("beforehide", this);
35890 if(this.activeItem){
35891 this.activeItem.deactivate();
35892 this.activeItem = null;
35895 this.hidden = true;
35896 this.fireEvent("hide", this);
35898 if(deep === true && this.parentMenu){
35899 this.parentMenu.hide(true);
35904 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35905 * Any of the following are valid:
35907 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35908 * <li>An HTMLElement object which will be converted to a menu item</li>
35909 * <li>A menu item config object that will be created as a new menu item</li>
35910 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35911 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35916 var menu = new Roo.menu.Menu();
35918 // Create a menu item to add by reference
35919 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35921 // Add a bunch of items at once using different methods.
35922 // Only the last item added will be returned.
35923 var item = menu.add(
35924 menuItem, // add existing item by ref
35925 'Dynamic Item', // new TextItem
35926 '-', // new separator
35927 { text: 'Config Item' } // new item by config
35930 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35931 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35934 var a = arguments, l = a.length, item;
35935 for(var i = 0; i < l; i++){
35937 if ((typeof(el) == "object") && el.xtype && el.xns) {
35938 el = Roo.factory(el, Roo.menu);
35941 if(el.render){ // some kind of Item
35942 item = this.addItem(el);
35943 }else if(typeof el == "string"){ // string
35944 if(el == "separator" || el == "-"){
35945 item = this.addSeparator();
35947 item = this.addText(el);
35949 }else if(el.tagName || el.el){ // element
35950 item = this.addElement(el);
35951 }else if(typeof el == "object"){ // must be menu item config?
35952 item = this.addMenuItem(el);
35959 * Returns this menu's underlying {@link Roo.Element} object
35960 * @return {Roo.Element} The element
35962 getEl : function(){
35970 * Adds a separator bar to the menu
35971 * @return {Roo.menu.Item} The menu item that was added
35973 addSeparator : function(){
35974 return this.addItem(new Roo.menu.Separator());
35978 * Adds an {@link Roo.Element} object to the menu
35979 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35980 * @return {Roo.menu.Item} The menu item that was added
35982 addElement : function(el){
35983 return this.addItem(new Roo.menu.BaseItem(el));
35987 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35988 * @param {Roo.menu.Item} item The menu item to add
35989 * @return {Roo.menu.Item} The menu item that was added
35991 addItem : function(item){
35992 this.items.add(item);
35994 var li = document.createElement("li");
35995 li.className = "x-menu-list-item";
35996 this.ul.dom.appendChild(li);
35997 item.render(li, this);
35998 this.delayAutoWidth();
36004 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
36005 * @param {Object} config A MenuItem config object
36006 * @return {Roo.menu.Item} The menu item that was added
36008 addMenuItem : function(config){
36009 if(!(config instanceof Roo.menu.Item)){
36010 if(typeof config.checked == "boolean"){ // must be check menu item config?
36011 config = new Roo.menu.CheckItem(config);
36013 config = new Roo.menu.Item(config);
36016 return this.addItem(config);
36020 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36021 * @param {String} text The text to display in the menu item
36022 * @return {Roo.menu.Item} The menu item that was added
36024 addText : function(text){
36025 return this.addItem(new Roo.menu.TextItem({ text : text }));
36029 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36030 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36031 * @param {Roo.menu.Item} item The menu item to add
36032 * @return {Roo.menu.Item} The menu item that was added
36034 insert : function(index, item){
36035 this.items.insert(index, item);
36037 var li = document.createElement("li");
36038 li.className = "x-menu-list-item";
36039 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36040 item.render(li, this);
36041 this.delayAutoWidth();
36047 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36048 * @param {Roo.menu.Item} item The menu item to remove
36050 remove : function(item){
36051 this.items.removeKey(item.id);
36056 * Removes and destroys all items in the menu
36058 removeAll : function(){
36060 while(f = this.items.first()){
36066 // MenuNav is a private utility class used internally by the Menu
36067 Roo.menu.MenuNav = function(menu){
36068 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36069 this.scope = this.menu = menu;
36072 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36073 doRelay : function(e, h){
36074 var k = e.getKey();
36075 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36076 this.menu.tryActivate(0, 1);
36079 return h.call(this.scope || this, e, this.menu);
36082 up : function(e, m){
36083 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36084 m.tryActivate(m.items.length-1, -1);
36088 down : function(e, m){
36089 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36090 m.tryActivate(0, 1);
36094 right : function(e, m){
36096 m.activeItem.expandMenu(true);
36100 left : function(e, m){
36102 if(m.parentMenu && m.parentMenu.activeItem){
36103 m.parentMenu.activeItem.activate();
36107 enter : function(e, m){
36109 e.stopPropagation();
36110 m.activeItem.onClick(e);
36111 m.fireEvent("click", this, m.activeItem);
36117 * Ext JS Library 1.1.1
36118 * Copyright(c) 2006-2007, Ext JS, LLC.
36120 * Originally Released Under LGPL - original licence link has changed is not relivant.
36123 * <script type="text/javascript">
36127 * @class Roo.menu.MenuMgr
36128 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36131 Roo.menu.MenuMgr = function(){
36132 var menus, active, groups = {}, attached = false, lastShow = new Date();
36134 // private - called when first menu is created
36137 active = new Roo.util.MixedCollection();
36138 Roo.get(document).addKeyListener(27, function(){
36139 if(active.length > 0){
36146 function hideAll(){
36147 if(active && active.length > 0){
36148 var c = active.clone();
36149 c.each(function(m){
36156 function onHide(m){
36158 if(active.length < 1){
36159 Roo.get(document).un("mousedown", onMouseDown);
36165 function onShow(m){
36166 var last = active.last();
36167 lastShow = new Date();
36170 Roo.get(document).on("mousedown", onMouseDown);
36174 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36175 m.parentMenu.activeChild = m;
36176 }else if(last && last.isVisible()){
36177 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36182 function onBeforeHide(m){
36184 m.activeChild.hide();
36186 if(m.autoHideTimer){
36187 clearTimeout(m.autoHideTimer);
36188 delete m.autoHideTimer;
36193 function onBeforeShow(m){
36194 var pm = m.parentMenu;
36195 if(!pm && !m.allowOtherMenus){
36197 }else if(pm && pm.activeChild && active != m){
36198 pm.activeChild.hide();
36203 function onMouseDown(e){
36204 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36210 function onBeforeCheck(mi, state){
36212 var g = groups[mi.group];
36213 for(var i = 0, l = g.length; i < l; i++){
36215 g[i].setChecked(false);
36224 * Hides all menus that are currently visible
36226 hideAll : function(){
36231 register : function(menu){
36235 menus[menu.id] = menu;
36236 menu.on("beforehide", onBeforeHide);
36237 menu.on("hide", onHide);
36238 menu.on("beforeshow", onBeforeShow);
36239 menu.on("show", onShow);
36240 var g = menu.group;
36241 if(g && menu.events["checkchange"]){
36245 groups[g].push(menu);
36246 menu.on("checkchange", onCheck);
36251 * Returns a {@link Roo.menu.Menu} object
36252 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36253 * be used to generate and return a new Menu instance.
36255 get : function(menu){
36256 if(typeof menu == "string"){ // menu id
36257 return menus[menu];
36258 }else if(menu.events){ // menu instance
36260 }else if(typeof menu.length == 'number'){ // array of menu items?
36261 return new Roo.menu.Menu({items:menu});
36262 }else{ // otherwise, must be a config
36263 return new Roo.menu.Menu(menu);
36268 unregister : function(menu){
36269 delete menus[menu.id];
36270 menu.un("beforehide", onBeforeHide);
36271 menu.un("hide", onHide);
36272 menu.un("beforeshow", onBeforeShow);
36273 menu.un("show", onShow);
36274 var g = menu.group;
36275 if(g && menu.events["checkchange"]){
36276 groups[g].remove(menu);
36277 menu.un("checkchange", onCheck);
36282 registerCheckable : function(menuItem){
36283 var g = menuItem.group;
36288 groups[g].push(menuItem);
36289 menuItem.on("beforecheckchange", onBeforeCheck);
36294 unregisterCheckable : function(menuItem){
36295 var g = menuItem.group;
36297 groups[g].remove(menuItem);
36298 menuItem.un("beforecheckchange", onBeforeCheck);
36304 * Ext JS Library 1.1.1
36305 * Copyright(c) 2006-2007, Ext JS, LLC.
36307 * Originally Released Under LGPL - original licence link has changed is not relivant.
36310 * <script type="text/javascript">
36315 * @class Roo.menu.BaseItem
36316 * @extends Roo.Component
36317 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36318 * management and base configuration options shared by all menu components.
36320 * Creates a new BaseItem
36321 * @param {Object} config Configuration options
36323 Roo.menu.BaseItem = function(config){
36324 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36329 * Fires when this item is clicked
36330 * @param {Roo.menu.BaseItem} this
36331 * @param {Roo.EventObject} e
36336 * Fires when this item is activated
36337 * @param {Roo.menu.BaseItem} this
36341 * @event deactivate
36342 * Fires when this item is deactivated
36343 * @param {Roo.menu.BaseItem} this
36349 this.on("click", this.handler, this.scope, true);
36353 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36355 * @cfg {Function} handler
36356 * A function that will handle the click event of this menu item (defaults to undefined)
36359 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36361 canActivate : false,
36364 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36369 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36371 activeClass : "x-menu-item-active",
36373 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36375 hideOnClick : true,
36377 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36382 ctype: "Roo.menu.BaseItem",
36385 actionMode : "container",
36388 render : function(container, parentMenu){
36389 this.parentMenu = parentMenu;
36390 Roo.menu.BaseItem.superclass.render.call(this, container);
36391 this.container.menuItemId = this.id;
36395 onRender : function(container, position){
36396 this.el = Roo.get(this.el);
36397 container.dom.appendChild(this.el.dom);
36401 onClick : function(e){
36402 if(!this.disabled && this.fireEvent("click", this, e) !== false
36403 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36404 this.handleClick(e);
36411 activate : function(){
36415 var li = this.container;
36416 li.addClass(this.activeClass);
36417 this.region = li.getRegion().adjust(2, 2, -2, -2);
36418 this.fireEvent("activate", this);
36423 deactivate : function(){
36424 this.container.removeClass(this.activeClass);
36425 this.fireEvent("deactivate", this);
36429 shouldDeactivate : function(e){
36430 return !this.region || !this.region.contains(e.getPoint());
36434 handleClick : function(e){
36435 if(this.hideOnClick){
36436 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36441 expandMenu : function(autoActivate){
36446 hideMenu : function(){
36451 * Ext JS Library 1.1.1
36452 * Copyright(c) 2006-2007, Ext JS, LLC.
36454 * Originally Released Under LGPL - original licence link has changed is not relivant.
36457 * <script type="text/javascript">
36461 * @class Roo.menu.Adapter
36462 * @extends Roo.menu.BaseItem
36463 * 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.
36464 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36466 * Creates a new Adapter
36467 * @param {Object} config Configuration options
36469 Roo.menu.Adapter = function(component, config){
36470 Roo.menu.Adapter.superclass.constructor.call(this, config);
36471 this.component = component;
36473 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36475 canActivate : true,
36478 onRender : function(container, position){
36479 this.component.render(container);
36480 this.el = this.component.getEl();
36484 activate : function(){
36488 this.component.focus();
36489 this.fireEvent("activate", this);
36494 deactivate : function(){
36495 this.fireEvent("deactivate", this);
36499 disable : function(){
36500 this.component.disable();
36501 Roo.menu.Adapter.superclass.disable.call(this);
36505 enable : function(){
36506 this.component.enable();
36507 Roo.menu.Adapter.superclass.enable.call(this);
36511 * Ext JS Library 1.1.1
36512 * Copyright(c) 2006-2007, Ext JS, LLC.
36514 * Originally Released Under LGPL - original licence link has changed is not relivant.
36517 * <script type="text/javascript">
36521 * @class Roo.menu.TextItem
36522 * @extends Roo.menu.BaseItem
36523 * Adds a static text string to a menu, usually used as either a heading or group separator.
36524 * Note: old style constructor with text is still supported.
36527 * Creates a new TextItem
36528 * @param {Object} cfg Configuration
36530 Roo.menu.TextItem = function(cfg){
36531 if (typeof(cfg) == 'string') {
36534 Roo.apply(this,cfg);
36537 Roo.menu.TextItem.superclass.constructor.call(this);
36540 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36542 * @cfg {Boolean} text Text to show on item.
36547 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36549 hideOnClick : false,
36551 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36553 itemCls : "x-menu-text",
36556 onRender : function(){
36557 var s = document.createElement("span");
36558 s.className = this.itemCls;
36559 s.innerHTML = this.text;
36561 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36565 * Ext JS Library 1.1.1
36566 * Copyright(c) 2006-2007, Ext JS, LLC.
36568 * Originally Released Under LGPL - original licence link has changed is not relivant.
36571 * <script type="text/javascript">
36575 * @class Roo.menu.Separator
36576 * @extends Roo.menu.BaseItem
36577 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36578 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36580 * @param {Object} config Configuration options
36582 Roo.menu.Separator = function(config){
36583 Roo.menu.Separator.superclass.constructor.call(this, config);
36586 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36588 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36590 itemCls : "x-menu-sep",
36592 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36594 hideOnClick : false,
36597 onRender : function(li){
36598 var s = document.createElement("span");
36599 s.className = this.itemCls;
36600 s.innerHTML = " ";
36602 li.addClass("x-menu-sep-li");
36603 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36607 * Ext JS Library 1.1.1
36608 * Copyright(c) 2006-2007, Ext JS, LLC.
36610 * Originally Released Under LGPL - original licence link has changed is not relivant.
36613 * <script type="text/javascript">
36616 * @class Roo.menu.Item
36617 * @extends Roo.menu.BaseItem
36618 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36619 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36620 * activation and click handling.
36622 * Creates a new Item
36623 * @param {Object} config Configuration options
36625 Roo.menu.Item = function(config){
36626 Roo.menu.Item.superclass.constructor.call(this, config);
36628 this.menu = Roo.menu.MenuMgr.get(this.menu);
36631 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36634 * @cfg {String} text
36635 * The text to show on the menu item.
36639 * @cfg {String} HTML to render in menu
36640 * The text to show on the menu item (HTML version).
36644 * @cfg {String} icon
36645 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36649 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36651 itemCls : "x-menu-item",
36653 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36655 canActivate : true,
36657 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36660 // doc'd in BaseItem
36664 ctype: "Roo.menu.Item",
36667 onRender : function(container, position){
36668 var el = document.createElement("a");
36669 el.hideFocus = true;
36670 el.unselectable = "on";
36671 el.href = this.href || "#";
36672 if(this.hrefTarget){
36673 el.target = this.hrefTarget;
36675 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36677 var html = this.html.length ? this.html : String.format('{0}',this.text);
36679 el.innerHTML = String.format(
36680 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36681 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36683 Roo.menu.Item.superclass.onRender.call(this, container, position);
36687 * Sets the text to display in this menu item
36688 * @param {String} text The text to display
36689 * @param {Boolean} isHTML true to indicate text is pure html.
36691 setText : function(text, isHTML){
36699 var html = this.html.length ? this.html : String.format('{0}',this.text);
36701 this.el.update(String.format(
36702 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36703 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36704 this.parentMenu.autoWidth();
36709 handleClick : function(e){
36710 if(!this.href){ // if no link defined, stop the event automatically
36713 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36717 activate : function(autoExpand){
36718 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36728 shouldDeactivate : function(e){
36729 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36730 if(this.menu && this.menu.isVisible()){
36731 return !this.menu.getEl().getRegion().contains(e.getPoint());
36739 deactivate : function(){
36740 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36745 expandMenu : function(autoActivate){
36746 if(!this.disabled && this.menu){
36747 clearTimeout(this.hideTimer);
36748 delete this.hideTimer;
36749 if(!this.menu.isVisible() && !this.showTimer){
36750 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36751 }else if (this.menu.isVisible() && autoActivate){
36752 this.menu.tryActivate(0, 1);
36758 deferExpand : function(autoActivate){
36759 delete this.showTimer;
36760 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36762 this.menu.tryActivate(0, 1);
36767 hideMenu : function(){
36768 clearTimeout(this.showTimer);
36769 delete this.showTimer;
36770 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36771 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36776 deferHide : function(){
36777 delete this.hideTimer;
36782 * Ext JS Library 1.1.1
36783 * Copyright(c) 2006-2007, Ext JS, LLC.
36785 * Originally Released Under LGPL - original licence link has changed is not relivant.
36788 * <script type="text/javascript">
36792 * @class Roo.menu.CheckItem
36793 * @extends Roo.menu.Item
36794 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36796 * Creates a new CheckItem
36797 * @param {Object} config Configuration options
36799 Roo.menu.CheckItem = function(config){
36800 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36803 * @event beforecheckchange
36804 * Fires before the checked value is set, providing an opportunity to cancel if needed
36805 * @param {Roo.menu.CheckItem} this
36806 * @param {Boolean} checked The new checked value that will be set
36808 "beforecheckchange" : true,
36810 * @event checkchange
36811 * Fires after the checked value has been set
36812 * @param {Roo.menu.CheckItem} this
36813 * @param {Boolean} checked The checked value that was set
36815 "checkchange" : true
36817 if(this.checkHandler){
36818 this.on('checkchange', this.checkHandler, this.scope);
36821 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36823 * @cfg {String} group
36824 * All check items with the same group name will automatically be grouped into a single-select
36825 * radio button group (defaults to '')
36828 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36830 itemCls : "x-menu-item x-menu-check-item",
36832 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36834 groupClass : "x-menu-group-item",
36837 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36838 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36839 * initialized with checked = true will be rendered as checked.
36844 ctype: "Roo.menu.CheckItem",
36847 onRender : function(c){
36848 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36850 this.el.addClass(this.groupClass);
36852 Roo.menu.MenuMgr.registerCheckable(this);
36854 this.checked = false;
36855 this.setChecked(true, true);
36860 destroy : function(){
36862 Roo.menu.MenuMgr.unregisterCheckable(this);
36864 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36868 * Set the checked state of this item
36869 * @param {Boolean} checked The new checked value
36870 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36872 setChecked : function(state, suppressEvent){
36873 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36874 if(this.container){
36875 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36877 this.checked = state;
36878 if(suppressEvent !== true){
36879 this.fireEvent("checkchange", this, state);
36885 handleClick : function(e){
36886 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36887 this.setChecked(!this.checked);
36889 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36893 * Ext JS Library 1.1.1
36894 * Copyright(c) 2006-2007, Ext JS, LLC.
36896 * Originally Released Under LGPL - original licence link has changed is not relivant.
36899 * <script type="text/javascript">
36903 * @class Roo.menu.DateItem
36904 * @extends Roo.menu.Adapter
36905 * A menu item that wraps the {@link Roo.DatPicker} component.
36907 * Creates a new DateItem
36908 * @param {Object} config Configuration options
36910 Roo.menu.DateItem = function(config){
36911 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36912 /** The Roo.DatePicker object @type Roo.DatePicker */
36913 this.picker = this.component;
36914 this.addEvents({select: true});
36916 this.picker.on("render", function(picker){
36917 picker.getEl().swallowEvent("click");
36918 picker.container.addClass("x-menu-date-item");
36921 this.picker.on("select", this.onSelect, this);
36924 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36926 onSelect : function(picker, date){
36927 this.fireEvent("select", this, date, picker);
36928 Roo.menu.DateItem.superclass.handleClick.call(this);
36932 * Ext JS Library 1.1.1
36933 * Copyright(c) 2006-2007, Ext JS, LLC.
36935 * Originally Released Under LGPL - original licence link has changed is not relivant.
36938 * <script type="text/javascript">
36942 * @class Roo.menu.ColorItem
36943 * @extends Roo.menu.Adapter
36944 * A menu item that wraps the {@link Roo.ColorPalette} component.
36946 * Creates a new ColorItem
36947 * @param {Object} config Configuration options
36949 Roo.menu.ColorItem = function(config){
36950 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36951 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36952 this.palette = this.component;
36953 this.relayEvents(this.palette, ["select"]);
36954 if(this.selectHandler){
36955 this.on('select', this.selectHandler, this.scope);
36958 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36960 * Ext JS Library 1.1.1
36961 * Copyright(c) 2006-2007, Ext JS, LLC.
36963 * Originally Released Under LGPL - original licence link has changed is not relivant.
36966 * <script type="text/javascript">
36971 * @class Roo.menu.DateMenu
36972 * @extends Roo.menu.Menu
36973 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36975 * Creates a new DateMenu
36976 * @param {Object} config Configuration options
36978 Roo.menu.DateMenu = function(config){
36979 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36981 var di = new Roo.menu.DateItem(config);
36984 * The {@link Roo.DatePicker} instance for this DateMenu
36987 this.picker = di.picker;
36990 * @param {DatePicker} picker
36991 * @param {Date} date
36993 this.relayEvents(di, ["select"]);
36994 this.on('beforeshow', function(){
36996 this.picker.hideMonthPicker(false);
37000 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
37004 * Ext JS Library 1.1.1
37005 * Copyright(c) 2006-2007, Ext JS, LLC.
37007 * Originally Released Under LGPL - original licence link has changed is not relivant.
37010 * <script type="text/javascript">
37015 * @class Roo.menu.ColorMenu
37016 * @extends Roo.menu.Menu
37017 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37019 * Creates a new ColorMenu
37020 * @param {Object} config Configuration options
37022 Roo.menu.ColorMenu = function(config){
37023 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37025 var ci = new Roo.menu.ColorItem(config);
37028 * The {@link Roo.ColorPalette} instance for this ColorMenu
37029 * @type ColorPalette
37031 this.palette = ci.palette;
37034 * @param {ColorPalette} palette
37035 * @param {String} color
37037 this.relayEvents(ci, ["select"]);
37039 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37041 * Ext JS Library 1.1.1
37042 * Copyright(c) 2006-2007, Ext JS, LLC.
37044 * Originally Released Under LGPL - original licence link has changed is not relivant.
37047 * <script type="text/javascript">
37051 * @class Roo.form.Field
37052 * @extends Roo.BoxComponent
37053 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37055 * Creates a new Field
37056 * @param {Object} config Configuration options
37058 Roo.form.Field = function(config){
37059 Roo.form.Field.superclass.constructor.call(this, config);
37062 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37064 * @cfg {String} fieldLabel Label to use when rendering a form.
37067 * @cfg {String} qtip Mouse over tip
37071 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37073 invalidClass : "x-form-invalid",
37075 * @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")
37077 invalidText : "The value in this field is invalid",
37079 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37081 focusClass : "x-form-focus",
37083 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37084 automatic validation (defaults to "keyup").
37086 validationEvent : "keyup",
37088 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37090 validateOnBlur : true,
37092 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37094 validationDelay : 250,
37096 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37097 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37099 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37101 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37103 fieldClass : "x-form-field",
37105 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37108 ----------- ----------------------------------------------------------------------
37109 qtip Display a quick tip when the user hovers over the field
37110 title Display a default browser title attribute popup
37111 under Add a block div beneath the field containing the error text
37112 side Add an error icon to the right of the field with a popup on hover
37113 [element id] Add the error text directly to the innerHTML of the specified element
37116 msgTarget : 'qtip',
37118 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37123 * @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.
37128 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37133 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37135 inputType : undefined,
37138 * @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).
37140 tabIndex : undefined,
37143 isFormField : true,
37148 * @property {Roo.Element} fieldEl
37149 * Element Containing the rendered Field (with label etc.)
37152 * @cfg {Mixed} value A value to initialize this field with.
37157 * @cfg {String} name The field's HTML name attribute.
37160 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37164 initComponent : function(){
37165 Roo.form.Field.superclass.initComponent.call(this);
37169 * Fires when this field receives input focus.
37170 * @param {Roo.form.Field} this
37175 * Fires when this field loses input focus.
37176 * @param {Roo.form.Field} this
37180 * @event specialkey
37181 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37182 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37183 * @param {Roo.form.Field} this
37184 * @param {Roo.EventObject} e The event object
37189 * Fires just before the field blurs if the field value has changed.
37190 * @param {Roo.form.Field} this
37191 * @param {Mixed} newValue The new value
37192 * @param {Mixed} oldValue The original value
37197 * Fires after the field has been marked as invalid.
37198 * @param {Roo.form.Field} this
37199 * @param {String} msg The validation message
37204 * Fires after the field has been validated with no errors.
37205 * @param {Roo.form.Field} this
37210 * Fires after the key up
37211 * @param {Roo.form.Field} this
37212 * @param {Roo.EventObject} e The event Object
37219 * Returns the name attribute of the field if available
37220 * @return {String} name The field name
37222 getName: function(){
37223 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37227 onRender : function(ct, position){
37228 Roo.form.Field.superclass.onRender.call(this, ct, position);
37230 var cfg = this.getAutoCreate();
37232 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37234 if (!cfg.name.length) {
37237 if(this.inputType){
37238 cfg.type = this.inputType;
37240 this.el = ct.createChild(cfg, position);
37242 var type = this.el.dom.type;
37244 if(type == 'password'){
37247 this.el.addClass('x-form-'+type);
37250 this.el.dom.readOnly = true;
37252 if(this.tabIndex !== undefined){
37253 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37256 this.el.addClass([this.fieldClass, this.cls]);
37261 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37262 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37263 * @return {Roo.form.Field} this
37265 applyTo : function(target){
37266 this.allowDomMove = false;
37267 this.el = Roo.get(target);
37268 this.render(this.el.dom.parentNode);
37273 initValue : function(){
37274 if(this.value !== undefined){
37275 this.setValue(this.value);
37276 }else if(this.el.dom.value.length > 0){
37277 this.setValue(this.el.dom.value);
37282 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37284 isDirty : function() {
37285 if(this.disabled) {
37288 return String(this.getValue()) !== String(this.originalValue);
37292 afterRender : function(){
37293 Roo.form.Field.superclass.afterRender.call(this);
37298 fireKey : function(e){
37299 //Roo.log('field ' + e.getKey());
37300 if(e.isNavKeyPress()){
37301 this.fireEvent("specialkey", this, e);
37306 * Resets the current field value to the originally loaded value and clears any validation messages
37308 reset : function(){
37309 this.setValue(this.resetValue);
37310 this.clearInvalid();
37314 initEvents : function(){
37315 // safari killled keypress - so keydown is now used..
37316 this.el.on("keydown" , this.fireKey, this);
37317 this.el.on("focus", this.onFocus, this);
37318 this.el.on("blur", this.onBlur, this);
37319 this.el.relayEvent('keyup', this);
37321 // reference to original value for reset
37322 this.originalValue = this.getValue();
37323 this.resetValue = this.getValue();
37327 onFocus : function(){
37328 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37329 this.el.addClass(this.focusClass);
37331 if(!this.hasFocus){
37332 this.hasFocus = true;
37333 this.startValue = this.getValue();
37334 this.fireEvent("focus", this);
37338 beforeBlur : Roo.emptyFn,
37341 onBlur : function(){
37343 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37344 this.el.removeClass(this.focusClass);
37346 this.hasFocus = false;
37347 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37350 var v = this.getValue();
37351 if(String(v) !== String(this.startValue)){
37352 this.fireEvent('change', this, v, this.startValue);
37354 this.fireEvent("blur", this);
37358 * Returns whether or not the field value is currently valid
37359 * @param {Boolean} preventMark True to disable marking the field invalid
37360 * @return {Boolean} True if the value is valid, else false
37362 isValid : function(preventMark){
37366 var restore = this.preventMark;
37367 this.preventMark = preventMark === true;
37368 var v = this.validateValue(this.processValue(this.getRawValue()));
37369 this.preventMark = restore;
37374 * Validates the field value
37375 * @return {Boolean} True if the value is valid, else false
37377 validate : function(){
37378 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37379 this.clearInvalid();
37385 processValue : function(value){
37390 // Subclasses should provide the validation implementation by overriding this
37391 validateValue : function(value){
37396 * Mark this field as invalid
37397 * @param {String} msg The validation message
37399 markInvalid : function(msg){
37400 if(!this.rendered || this.preventMark){ // not rendered
37404 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37406 obj.el.addClass(this.invalidClass);
37407 msg = msg || this.invalidText;
37408 switch(this.msgTarget){
37410 obj.el.dom.qtip = msg;
37411 obj.el.dom.qclass = 'x-form-invalid-tip';
37412 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37413 Roo.QuickTips.enable();
37417 this.el.dom.title = msg;
37421 var elp = this.el.findParent('.x-form-element', 5, true);
37422 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37423 this.errorEl.setWidth(elp.getWidth(true)-20);
37425 this.errorEl.update(msg);
37426 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37429 if(!this.errorIcon){
37430 var elp = this.el.findParent('.x-form-element', 5, true);
37431 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37433 this.alignErrorIcon();
37434 this.errorIcon.dom.qtip = msg;
37435 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37436 this.errorIcon.show();
37437 this.on('resize', this.alignErrorIcon, this);
37440 var t = Roo.getDom(this.msgTarget);
37442 t.style.display = this.msgDisplay;
37445 this.fireEvent('invalid', this, msg);
37449 alignErrorIcon : function(){
37450 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37454 * Clear any invalid styles/messages for this field
37456 clearInvalid : function(){
37457 if(!this.rendered || this.preventMark){ // not rendered
37460 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37462 obj.el.removeClass(this.invalidClass);
37463 switch(this.msgTarget){
37465 obj.el.dom.qtip = '';
37468 this.el.dom.title = '';
37472 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37476 if(this.errorIcon){
37477 this.errorIcon.dom.qtip = '';
37478 this.errorIcon.hide();
37479 this.un('resize', this.alignErrorIcon, this);
37483 var t = Roo.getDom(this.msgTarget);
37485 t.style.display = 'none';
37488 this.fireEvent('valid', this);
37492 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37493 * @return {Mixed} value The field value
37495 getRawValue : function(){
37496 var v = this.el.getValue();
37502 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37503 * @return {Mixed} value The field value
37505 getValue : function(){
37506 var v = this.el.getValue();
37512 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37513 * @param {Mixed} value The value to set
37515 setRawValue : function(v){
37516 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37520 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37521 * @param {Mixed} value The value to set
37523 setValue : function(v){
37526 this.el.dom.value = (v === null || v === undefined ? '' : v);
37531 adjustSize : function(w, h){
37532 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37533 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37537 adjustWidth : function(tag, w){
37538 tag = tag.toLowerCase();
37539 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37540 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37541 if(tag == 'input'){
37544 if(tag == 'textarea'){
37547 }else if(Roo.isOpera){
37548 if(tag == 'input'){
37551 if(tag == 'textarea'){
37561 // anything other than normal should be considered experimental
37562 Roo.form.Field.msgFx = {
37564 show: function(msgEl, f){
37565 msgEl.setDisplayed('block');
37568 hide : function(msgEl, f){
37569 msgEl.setDisplayed(false).update('');
37574 show: function(msgEl, f){
37575 msgEl.slideIn('t', {stopFx:true});
37578 hide : function(msgEl, f){
37579 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37584 show: function(msgEl, f){
37585 msgEl.fixDisplay();
37586 msgEl.alignTo(f.el, 'tl-tr');
37587 msgEl.slideIn('l', {stopFx:true});
37590 hide : function(msgEl, f){
37591 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37596 * Ext JS Library 1.1.1
37597 * Copyright(c) 2006-2007, Ext JS, LLC.
37599 * Originally Released Under LGPL - original licence link has changed is not relivant.
37602 * <script type="text/javascript">
37607 * @class Roo.form.TextField
37608 * @extends Roo.form.Field
37609 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37610 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37612 * Creates a new TextField
37613 * @param {Object} config Configuration options
37615 Roo.form.TextField = function(config){
37616 Roo.form.TextField.superclass.constructor.call(this, config);
37620 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37621 * according to the default logic, but this event provides a hook for the developer to apply additional
37622 * logic at runtime to resize the field if needed.
37623 * @param {Roo.form.Field} this This text field
37624 * @param {Number} width The new field width
37630 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37632 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37636 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37640 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37644 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37648 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37652 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37654 disableKeyFilter : false,
37656 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37660 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37664 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37666 maxLength : Number.MAX_VALUE,
37668 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37670 minLengthText : "The minimum length for this field is {0}",
37672 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37674 maxLengthText : "The maximum length for this field is {0}",
37676 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37678 selectOnFocus : false,
37680 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37682 blankText : "This field is required",
37684 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37685 * If available, this function will be called only after the basic validators all return true, and will be passed the
37686 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37690 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37691 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37692 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37696 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37700 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37706 initEvents : function()
37708 if (this.emptyText) {
37709 this.el.attr('placeholder', this.emptyText);
37712 Roo.form.TextField.superclass.initEvents.call(this);
37713 if(this.validationEvent == 'keyup'){
37714 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37715 this.el.on('keyup', this.filterValidation, this);
37717 else if(this.validationEvent !== false){
37718 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37721 if(this.selectOnFocus){
37722 this.on("focus", this.preFocus, this);
37725 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37726 this.el.on("keypress", this.filterKeys, this);
37729 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37730 this.el.on("click", this.autoSize, this);
37732 if(this.el.is('input[type=password]') && Roo.isSafari){
37733 this.el.on('keydown', this.SafariOnKeyDown, this);
37737 processValue : function(value){
37738 if(this.stripCharsRe){
37739 var newValue = value.replace(this.stripCharsRe, '');
37740 if(newValue !== value){
37741 this.setRawValue(newValue);
37748 filterValidation : function(e){
37749 if(!e.isNavKeyPress()){
37750 this.validationTask.delay(this.validationDelay);
37755 onKeyUp : function(e){
37756 if(!e.isNavKeyPress()){
37762 * Resets the current field value to the originally-loaded value and clears any validation messages.
37765 reset : function(){
37766 Roo.form.TextField.superclass.reset.call(this);
37772 preFocus : function(){
37774 if(this.selectOnFocus){
37775 this.el.dom.select();
37781 filterKeys : function(e){
37782 var k = e.getKey();
37783 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37786 var c = e.getCharCode(), cc = String.fromCharCode(c);
37787 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37790 if(!this.maskRe.test(cc)){
37795 setValue : function(v){
37797 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37803 * Validates a value according to the field's validation rules and marks the field as invalid
37804 * if the validation fails
37805 * @param {Mixed} value The value to validate
37806 * @return {Boolean} True if the value is valid, else false
37808 validateValue : function(value){
37809 if(value.length < 1) { // if it's blank
37810 if(this.allowBlank){
37811 this.clearInvalid();
37814 this.markInvalid(this.blankText);
37818 if(value.length < this.minLength){
37819 this.markInvalid(String.format(this.minLengthText, this.minLength));
37822 if(value.length > this.maxLength){
37823 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37827 var vt = Roo.form.VTypes;
37828 if(!vt[this.vtype](value, this)){
37829 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37833 if(typeof this.validator == "function"){
37834 var msg = this.validator(value);
37836 this.markInvalid(msg);
37840 if(this.regex && !this.regex.test(value)){
37841 this.markInvalid(this.regexText);
37848 * Selects text in this field
37849 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37850 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37852 selectText : function(start, end){
37853 var v = this.getRawValue();
37855 start = start === undefined ? 0 : start;
37856 end = end === undefined ? v.length : end;
37857 var d = this.el.dom;
37858 if(d.setSelectionRange){
37859 d.setSelectionRange(start, end);
37860 }else if(d.createTextRange){
37861 var range = d.createTextRange();
37862 range.moveStart("character", start);
37863 range.moveEnd("character", v.length-end);
37870 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37871 * This only takes effect if grow = true, and fires the autosize event.
37873 autoSize : function(){
37874 if(!this.grow || !this.rendered){
37878 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37881 var v = el.dom.value;
37882 var d = document.createElement('div');
37883 d.appendChild(document.createTextNode(v));
37887 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37888 this.el.setWidth(w);
37889 this.fireEvent("autosize", this, w);
37893 SafariOnKeyDown : function(event)
37895 // this is a workaround for a password hang bug on chrome/ webkit.
37897 var isSelectAll = false;
37899 if(this.el.dom.selectionEnd > 0){
37900 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37902 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37903 event.preventDefault();
37908 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37910 event.preventDefault();
37911 // this is very hacky as keydown always get's upper case.
37913 var cc = String.fromCharCode(event.getCharCode());
37916 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37924 * Ext JS Library 1.1.1
37925 * Copyright(c) 2006-2007, Ext JS, LLC.
37927 * Originally Released Under LGPL - original licence link has changed is not relivant.
37930 * <script type="text/javascript">
37934 * @class Roo.form.Hidden
37935 * @extends Roo.form.TextField
37936 * Simple Hidden element used on forms
37938 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37941 * Creates a new Hidden form element.
37942 * @param {Object} config Configuration options
37947 // easy hidden field...
37948 Roo.form.Hidden = function(config){
37949 Roo.form.Hidden.superclass.constructor.call(this, config);
37952 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37954 inputType: 'hidden',
37957 labelSeparator: '',
37959 itemCls : 'x-form-item-display-none'
37967 * Ext JS Library 1.1.1
37968 * Copyright(c) 2006-2007, Ext JS, LLC.
37970 * Originally Released Under LGPL - original licence link has changed is not relivant.
37973 * <script type="text/javascript">
37977 * @class Roo.form.TriggerField
37978 * @extends Roo.form.TextField
37979 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37980 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37981 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37982 * for which you can provide a custom implementation. For example:
37984 var trigger = new Roo.form.TriggerField();
37985 trigger.onTriggerClick = myTriggerFn;
37986 trigger.applyTo('my-field');
37989 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37990 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37991 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37992 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37994 * Create a new TriggerField.
37995 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37996 * to the base TextField)
37998 Roo.form.TriggerField = function(config){
37999 this.mimicing = false;
38000 Roo.form.TriggerField.superclass.constructor.call(this, config);
38003 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
38005 * @cfg {String} triggerClass A CSS class to apply to the trigger
38008 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38009 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38011 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38013 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38017 /** @cfg {Boolean} grow @hide */
38018 /** @cfg {Number} growMin @hide */
38019 /** @cfg {Number} growMax @hide */
38025 autoSize: Roo.emptyFn,
38029 deferHeight : true,
38032 actionMode : 'wrap',
38034 onResize : function(w, h){
38035 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38036 if(typeof w == 'number'){
38037 var x = w - this.trigger.getWidth();
38038 this.el.setWidth(this.adjustWidth('input', x));
38039 this.trigger.setStyle('left', x+'px');
38044 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38047 getResizeEl : function(){
38052 getPositionEl : function(){
38057 alignErrorIcon : function(){
38058 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38062 onRender : function(ct, position){
38063 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38064 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38065 this.trigger = this.wrap.createChild(this.triggerConfig ||
38066 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38067 if(this.hideTrigger){
38068 this.trigger.setDisplayed(false);
38070 this.initTrigger();
38072 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38077 initTrigger : function(){
38078 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38079 this.trigger.addClassOnOver('x-form-trigger-over');
38080 this.trigger.addClassOnClick('x-form-trigger-click');
38084 onDestroy : function(){
38086 this.trigger.removeAllListeners();
38087 this.trigger.remove();
38090 this.wrap.remove();
38092 Roo.form.TriggerField.superclass.onDestroy.call(this);
38096 onFocus : function(){
38097 Roo.form.TriggerField.superclass.onFocus.call(this);
38098 if(!this.mimicing){
38099 this.wrap.addClass('x-trigger-wrap-focus');
38100 this.mimicing = true;
38101 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38102 if(this.monitorTab){
38103 this.el.on("keydown", this.checkTab, this);
38109 checkTab : function(e){
38110 if(e.getKey() == e.TAB){
38111 this.triggerBlur();
38116 onBlur : function(){
38121 mimicBlur : function(e, t){
38122 if(!this.wrap.contains(t) && this.validateBlur()){
38123 this.triggerBlur();
38128 triggerBlur : function(){
38129 this.mimicing = false;
38130 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38131 if(this.monitorTab){
38132 this.el.un("keydown", this.checkTab, this);
38134 this.wrap.removeClass('x-trigger-wrap-focus');
38135 Roo.form.TriggerField.superclass.onBlur.call(this);
38139 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38140 validateBlur : function(e, t){
38145 onDisable : function(){
38146 Roo.form.TriggerField.superclass.onDisable.call(this);
38148 this.wrap.addClass('x-item-disabled');
38153 onEnable : function(){
38154 Roo.form.TriggerField.superclass.onEnable.call(this);
38156 this.wrap.removeClass('x-item-disabled');
38161 onShow : function(){
38162 var ae = this.getActionEl();
38165 ae.dom.style.display = '';
38166 ae.dom.style.visibility = 'visible';
38172 onHide : function(){
38173 var ae = this.getActionEl();
38174 ae.dom.style.display = 'none';
38178 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38179 * by an implementing function.
38181 * @param {EventObject} e
38183 onTriggerClick : Roo.emptyFn
38186 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38187 // to be extended by an implementing class. For an example of implementing this class, see the custom
38188 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38189 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38190 initComponent : function(){
38191 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38193 this.triggerConfig = {
38194 tag:'span', cls:'x-form-twin-triggers', cn:[
38195 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38196 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38200 getTrigger : function(index){
38201 return this.triggers[index];
38204 initTrigger : function(){
38205 var ts = this.trigger.select('.x-form-trigger', true);
38206 this.wrap.setStyle('overflow', 'hidden');
38207 var triggerField = this;
38208 ts.each(function(t, all, index){
38209 t.hide = function(){
38210 var w = triggerField.wrap.getWidth();
38211 this.dom.style.display = 'none';
38212 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38214 t.show = function(){
38215 var w = triggerField.wrap.getWidth();
38216 this.dom.style.display = '';
38217 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38219 var triggerIndex = 'Trigger'+(index+1);
38221 if(this['hide'+triggerIndex]){
38222 t.dom.style.display = 'none';
38224 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38225 t.addClassOnOver('x-form-trigger-over');
38226 t.addClassOnClick('x-form-trigger-click');
38228 this.triggers = ts.elements;
38231 onTrigger1Click : Roo.emptyFn,
38232 onTrigger2Click : Roo.emptyFn
38235 * Ext JS Library 1.1.1
38236 * Copyright(c) 2006-2007, Ext JS, LLC.
38238 * Originally Released Under LGPL - original licence link has changed is not relivant.
38241 * <script type="text/javascript">
38245 * @class Roo.form.TextArea
38246 * @extends Roo.form.TextField
38247 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38248 * support for auto-sizing.
38250 * Creates a new TextArea
38251 * @param {Object} config Configuration options
38253 Roo.form.TextArea = function(config){
38254 Roo.form.TextArea.superclass.constructor.call(this, config);
38255 // these are provided exchanges for backwards compat
38256 // minHeight/maxHeight were replaced by growMin/growMax to be
38257 // compatible with TextField growing config values
38258 if(this.minHeight !== undefined){
38259 this.growMin = this.minHeight;
38261 if(this.maxHeight !== undefined){
38262 this.growMax = this.maxHeight;
38266 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38268 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38272 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38276 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38277 * in the field (equivalent to setting overflow: hidden, defaults to false)
38279 preventScrollbars: false,
38281 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38282 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38286 onRender : function(ct, position){
38288 this.defaultAutoCreate = {
38290 style:"width:300px;height:60px;",
38291 autocomplete: "new-password"
38294 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38296 this.textSizeEl = Roo.DomHelper.append(document.body, {
38297 tag: "pre", cls: "x-form-grow-sizer"
38299 if(this.preventScrollbars){
38300 this.el.setStyle("overflow", "hidden");
38302 this.el.setHeight(this.growMin);
38306 onDestroy : function(){
38307 if(this.textSizeEl){
38308 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38310 Roo.form.TextArea.superclass.onDestroy.call(this);
38314 onKeyUp : function(e){
38315 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38321 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38322 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38324 autoSize : function(){
38325 if(!this.grow || !this.textSizeEl){
38329 var v = el.dom.value;
38330 var ts = this.textSizeEl;
38333 ts.appendChild(document.createTextNode(v));
38336 Roo.fly(ts).setWidth(this.el.getWidth());
38338 v = "  ";
38341 v = v.replace(/\n/g, '<p> </p>');
38343 v += " \n ";
38346 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38347 if(h != this.lastHeight){
38348 this.lastHeight = h;
38349 this.el.setHeight(h);
38350 this.fireEvent("autosize", this, h);
38355 * Ext JS Library 1.1.1
38356 * Copyright(c) 2006-2007, Ext JS, LLC.
38358 * Originally Released Under LGPL - original licence link has changed is not relivant.
38361 * <script type="text/javascript">
38366 * @class Roo.form.NumberField
38367 * @extends Roo.form.TextField
38368 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38370 * Creates a new NumberField
38371 * @param {Object} config Configuration options
38373 Roo.form.NumberField = function(config){
38374 Roo.form.NumberField.superclass.constructor.call(this, config);
38377 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38379 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38381 fieldClass: "x-form-field x-form-num-field",
38383 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38385 allowDecimals : true,
38387 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38389 decimalSeparator : ".",
38391 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38393 decimalPrecision : 2,
38395 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38397 allowNegative : true,
38399 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38401 minValue : Number.NEGATIVE_INFINITY,
38403 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38405 maxValue : Number.MAX_VALUE,
38407 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38409 minText : "The minimum value for this field is {0}",
38411 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38413 maxText : "The maximum value for this field is {0}",
38415 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38416 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38418 nanText : "{0} is not a valid number",
38421 initEvents : function(){
38422 Roo.form.NumberField.superclass.initEvents.call(this);
38423 var allowed = "0123456789";
38424 if(this.allowDecimals){
38425 allowed += this.decimalSeparator;
38427 if(this.allowNegative){
38430 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38431 var keyPress = function(e){
38432 var k = e.getKey();
38433 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38436 var c = e.getCharCode();
38437 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38441 this.el.on("keypress", keyPress, this);
38445 validateValue : function(value){
38446 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38449 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38452 var num = this.parseValue(value);
38454 this.markInvalid(String.format(this.nanText, value));
38457 if(num < this.minValue){
38458 this.markInvalid(String.format(this.minText, this.minValue));
38461 if(num > this.maxValue){
38462 this.markInvalid(String.format(this.maxText, this.maxValue));
38468 getValue : function(){
38469 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38473 parseValue : function(value){
38474 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38475 return isNaN(value) ? '' : value;
38479 fixPrecision : function(value){
38480 var nan = isNaN(value);
38481 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38482 return nan ? '' : value;
38484 return parseFloat(value).toFixed(this.decimalPrecision);
38487 setValue : function(v){
38488 v = this.fixPrecision(v);
38489 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38493 decimalPrecisionFcn : function(v){
38494 return Math.floor(v);
38497 beforeBlur : function(){
38498 var v = this.parseValue(this.getRawValue());
38505 * Ext JS Library 1.1.1
38506 * Copyright(c) 2006-2007, Ext JS, LLC.
38508 * Originally Released Under LGPL - original licence link has changed is not relivant.
38511 * <script type="text/javascript">
38515 * @class Roo.form.DateField
38516 * @extends Roo.form.TriggerField
38517 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38519 * Create a new DateField
38520 * @param {Object} config
38522 Roo.form.DateField = function(config){
38523 Roo.form.DateField.superclass.constructor.call(this, config);
38529 * Fires when a date is selected
38530 * @param {Roo.form.DateField} combo This combo box
38531 * @param {Date} date The date selected
38538 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38539 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38540 this.ddMatch = null;
38541 if(this.disabledDates){
38542 var dd = this.disabledDates;
38544 for(var i = 0; i < dd.length; i++){
38546 if(i != dd.length-1) re += "|";
38548 this.ddMatch = new RegExp(re + ")");
38552 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38554 * @cfg {String} format
38555 * The default date format string which can be overriden for localization support. The format must be
38556 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38560 * @cfg {String} altFormats
38561 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38562 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38564 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38566 * @cfg {Array} disabledDays
38567 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38569 disabledDays : null,
38571 * @cfg {String} disabledDaysText
38572 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38574 disabledDaysText : "Disabled",
38576 * @cfg {Array} disabledDates
38577 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38578 * expression so they are very powerful. Some examples:
38580 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38581 * <li>["03/08", "09/16"] would disable those days for every year</li>
38582 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38583 * <li>["03/../2006"] would disable every day in March 2006</li>
38584 * <li>["^03"] would disable every day in every March</li>
38586 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38587 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38589 disabledDates : null,
38591 * @cfg {String} disabledDatesText
38592 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38594 disabledDatesText : "Disabled",
38596 * @cfg {Date/String} minValue
38597 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38598 * valid format (defaults to null).
38602 * @cfg {Date/String} maxValue
38603 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38604 * valid format (defaults to null).
38608 * @cfg {String} minText
38609 * The error text to display when the date in the cell is before minValue (defaults to
38610 * 'The date in this field must be after {minValue}').
38612 minText : "The date in this field must be equal to or after {0}",
38614 * @cfg {String} maxText
38615 * The error text to display when the date in the cell is after maxValue (defaults to
38616 * 'The date in this field must be before {maxValue}').
38618 maxText : "The date in this field must be equal to or before {0}",
38620 * @cfg {String} invalidText
38621 * The error text to display when the date in the field is invalid (defaults to
38622 * '{value} is not a valid date - it must be in the format {format}').
38624 invalidText : "{0} is not a valid date - it must be in the format {1}",
38626 * @cfg {String} triggerClass
38627 * An additional CSS class used to style the trigger button. The trigger will always get the
38628 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38629 * which displays a calendar icon).
38631 triggerClass : 'x-form-date-trigger',
38635 * @cfg {Boolean} useIso
38636 * if enabled, then the date field will use a hidden field to store the
38637 * real value as iso formated date. default (false)
38641 * @cfg {String/Object} autoCreate
38642 * A DomHelper element spec, or true for a default element spec (defaults to
38643 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38646 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38649 hiddenField: false,
38651 onRender : function(ct, position)
38653 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38655 //this.el.dom.removeAttribute('name');
38656 Roo.log("Changing name?");
38657 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38658 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38660 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38661 // prevent input submission
38662 this.hiddenName = this.name;
38669 validateValue : function(value)
38671 value = this.formatDate(value);
38672 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38673 Roo.log('super failed');
38676 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38679 var svalue = value;
38680 value = this.parseDate(value);
38682 Roo.log('parse date failed' + svalue);
38683 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38686 var time = value.getTime();
38687 if(this.minValue && time < this.minValue.getTime()){
38688 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38691 if(this.maxValue && time > this.maxValue.getTime()){
38692 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38695 if(this.disabledDays){
38696 var day = value.getDay();
38697 for(var i = 0; i < this.disabledDays.length; i++) {
38698 if(day === this.disabledDays[i]){
38699 this.markInvalid(this.disabledDaysText);
38704 var fvalue = this.formatDate(value);
38705 if(this.ddMatch && this.ddMatch.test(fvalue)){
38706 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38713 // Provides logic to override the default TriggerField.validateBlur which just returns true
38714 validateBlur : function(){
38715 return !this.menu || !this.menu.isVisible();
38718 getName: function()
38720 // returns hidden if it's set..
38721 if (!this.rendered) {return ''};
38722 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38727 * Returns the current date value of the date field.
38728 * @return {Date} The date value
38730 getValue : function(){
38732 return this.hiddenField ?
38733 this.hiddenField.value :
38734 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38738 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38739 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38740 * (the default format used is "m/d/y").
38743 //All of these calls set the same date value (May 4, 2006)
38745 //Pass a date object:
38746 var dt = new Date('5/4/06');
38747 dateField.setValue(dt);
38749 //Pass a date string (default format):
38750 dateField.setValue('5/4/06');
38752 //Pass a date string (custom format):
38753 dateField.format = 'Y-m-d';
38754 dateField.setValue('2006-5-4');
38756 * @param {String/Date} date The date or valid date string
38758 setValue : function(date){
38759 if (this.hiddenField) {
38760 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38762 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38763 // make sure the value field is always stored as a date..
38764 this.value = this.parseDate(date);
38770 parseDate : function(value){
38771 if(!value || value instanceof Date){
38774 var v = Date.parseDate(value, this.format);
38775 if (!v && this.useIso) {
38776 v = Date.parseDate(value, 'Y-m-d');
38778 if(!v && this.altFormats){
38779 if(!this.altFormatsArray){
38780 this.altFormatsArray = this.altFormats.split("|");
38782 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38783 v = Date.parseDate(value, this.altFormatsArray[i]);
38790 formatDate : function(date, fmt){
38791 return (!date || !(date instanceof Date)) ?
38792 date : date.dateFormat(fmt || this.format);
38797 select: function(m, d){
38800 this.fireEvent('select', this, d);
38802 show : function(){ // retain focus styling
38806 this.focus.defer(10, this);
38807 var ml = this.menuListeners;
38808 this.menu.un("select", ml.select, this);
38809 this.menu.un("show", ml.show, this);
38810 this.menu.un("hide", ml.hide, this);
38815 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38816 onTriggerClick : function(){
38820 if(this.menu == null){
38821 this.menu = new Roo.menu.DateMenu();
38823 Roo.apply(this.menu.picker, {
38824 showClear: this.allowBlank,
38825 minDate : this.minValue,
38826 maxDate : this.maxValue,
38827 disabledDatesRE : this.ddMatch,
38828 disabledDatesText : this.disabledDatesText,
38829 disabledDays : this.disabledDays,
38830 disabledDaysText : this.disabledDaysText,
38831 format : this.useIso ? 'Y-m-d' : this.format,
38832 minText : String.format(this.minText, this.formatDate(this.minValue)),
38833 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38835 this.menu.on(Roo.apply({}, this.menuListeners, {
38838 this.menu.picker.setValue(this.getValue() || new Date());
38839 this.menu.show(this.el, "tl-bl?");
38842 beforeBlur : function(){
38843 var v = this.parseDate(this.getRawValue());
38853 isDirty : function() {
38854 if(this.disabled) {
38858 if(typeof(this.startValue) === 'undefined'){
38862 return String(this.getValue()) !== String(this.startValue);
38867 * Ext JS Library 1.1.1
38868 * Copyright(c) 2006-2007, Ext JS, LLC.
38870 * Originally Released Under LGPL - original licence link has changed is not relivant.
38873 * <script type="text/javascript">
38877 * @class Roo.form.MonthField
38878 * @extends Roo.form.TriggerField
38879 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38881 * Create a new MonthField
38882 * @param {Object} config
38884 Roo.form.MonthField = function(config){
38886 Roo.form.MonthField.superclass.constructor.call(this, config);
38892 * Fires when a date is selected
38893 * @param {Roo.form.MonthFieeld} combo This combo box
38894 * @param {Date} date The date selected
38901 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38902 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38903 this.ddMatch = null;
38904 if(this.disabledDates){
38905 var dd = this.disabledDates;
38907 for(var i = 0; i < dd.length; i++){
38909 if(i != dd.length-1) re += "|";
38911 this.ddMatch = new RegExp(re + ")");
38915 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38917 * @cfg {String} format
38918 * The default date format string which can be overriden for localization support. The format must be
38919 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38923 * @cfg {String} altFormats
38924 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38925 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38927 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38929 * @cfg {Array} disabledDays
38930 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38932 disabledDays : [0,1,2,3,4,5,6],
38934 * @cfg {String} disabledDaysText
38935 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38937 disabledDaysText : "Disabled",
38939 * @cfg {Array} disabledDates
38940 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38941 * expression so they are very powerful. Some examples:
38943 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38944 * <li>["03/08", "09/16"] would disable those days for every year</li>
38945 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38946 * <li>["03/../2006"] would disable every day in March 2006</li>
38947 * <li>["^03"] would disable every day in every March</li>
38949 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38950 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38952 disabledDates : null,
38954 * @cfg {String} disabledDatesText
38955 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38957 disabledDatesText : "Disabled",
38959 * @cfg {Date/String} minValue
38960 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38961 * valid format (defaults to null).
38965 * @cfg {Date/String} maxValue
38966 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38967 * valid format (defaults to null).
38971 * @cfg {String} minText
38972 * The error text to display when the date in the cell is before minValue (defaults to
38973 * 'The date in this field must be after {minValue}').
38975 minText : "The date in this field must be equal to or after {0}",
38977 * @cfg {String} maxTextf
38978 * The error text to display when the date in the cell is after maxValue (defaults to
38979 * 'The date in this field must be before {maxValue}').
38981 maxText : "The date in this field must be equal to or before {0}",
38983 * @cfg {String} invalidText
38984 * The error text to display when the date in the field is invalid (defaults to
38985 * '{value} is not a valid date - it must be in the format {format}').
38987 invalidText : "{0} is not a valid date - it must be in the format {1}",
38989 * @cfg {String} triggerClass
38990 * An additional CSS class used to style the trigger button. The trigger will always get the
38991 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38992 * which displays a calendar icon).
38994 triggerClass : 'x-form-date-trigger',
38998 * @cfg {Boolean} useIso
38999 * if enabled, then the date field will use a hidden field to store the
39000 * real value as iso formated date. default (true)
39004 * @cfg {String/Object} autoCreate
39005 * A DomHelper element spec, or true for a default element spec (defaults to
39006 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39009 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39012 hiddenField: false,
39014 hideMonthPicker : false,
39016 onRender : function(ct, position)
39018 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39020 this.el.dom.removeAttribute('name');
39021 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39023 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39024 // prevent input submission
39025 this.hiddenName = this.name;
39032 validateValue : function(value)
39034 value = this.formatDate(value);
39035 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39038 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39041 var svalue = value;
39042 value = this.parseDate(value);
39044 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39047 var time = value.getTime();
39048 if(this.minValue && time < this.minValue.getTime()){
39049 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39052 if(this.maxValue && time > this.maxValue.getTime()){
39053 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39056 /*if(this.disabledDays){
39057 var day = value.getDay();
39058 for(var i = 0; i < this.disabledDays.length; i++) {
39059 if(day === this.disabledDays[i]){
39060 this.markInvalid(this.disabledDaysText);
39066 var fvalue = this.formatDate(value);
39067 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39068 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39076 // Provides logic to override the default TriggerField.validateBlur which just returns true
39077 validateBlur : function(){
39078 return !this.menu || !this.menu.isVisible();
39082 * Returns the current date value of the date field.
39083 * @return {Date} The date value
39085 getValue : function(){
39089 return this.hiddenField ?
39090 this.hiddenField.value :
39091 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39095 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39096 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39097 * (the default format used is "m/d/y").
39100 //All of these calls set the same date value (May 4, 2006)
39102 //Pass a date object:
39103 var dt = new Date('5/4/06');
39104 monthField.setValue(dt);
39106 //Pass a date string (default format):
39107 monthField.setValue('5/4/06');
39109 //Pass a date string (custom format):
39110 monthField.format = 'Y-m-d';
39111 monthField.setValue('2006-5-4');
39113 * @param {String/Date} date The date or valid date string
39115 setValue : function(date){
39116 Roo.log('month setValue' + date);
39117 // can only be first of month..
39119 var val = this.parseDate(date);
39121 if (this.hiddenField) {
39122 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39124 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39125 this.value = this.parseDate(date);
39129 parseDate : function(value){
39130 if(!value || value instanceof Date){
39131 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39134 var v = Date.parseDate(value, this.format);
39135 if (!v && this.useIso) {
39136 v = Date.parseDate(value, 'Y-m-d');
39140 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39144 if(!v && this.altFormats){
39145 if(!this.altFormatsArray){
39146 this.altFormatsArray = this.altFormats.split("|");
39148 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39149 v = Date.parseDate(value, this.altFormatsArray[i]);
39156 formatDate : function(date, fmt){
39157 return (!date || !(date instanceof Date)) ?
39158 date : date.dateFormat(fmt || this.format);
39163 select: function(m, d){
39165 this.fireEvent('select', this, d);
39167 show : function(){ // retain focus styling
39171 this.focus.defer(10, this);
39172 var ml = this.menuListeners;
39173 this.menu.un("select", ml.select, this);
39174 this.menu.un("show", ml.show, this);
39175 this.menu.un("hide", ml.hide, this);
39179 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39180 onTriggerClick : function(){
39184 if(this.menu == null){
39185 this.menu = new Roo.menu.DateMenu();
39189 Roo.apply(this.menu.picker, {
39191 showClear: this.allowBlank,
39192 minDate : this.minValue,
39193 maxDate : this.maxValue,
39194 disabledDatesRE : this.ddMatch,
39195 disabledDatesText : this.disabledDatesText,
39197 format : this.useIso ? 'Y-m-d' : this.format,
39198 minText : String.format(this.minText, this.formatDate(this.minValue)),
39199 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39202 this.menu.on(Roo.apply({}, this.menuListeners, {
39210 // hide month picker get's called when we called by 'before hide';
39212 var ignorehide = true;
39213 p.hideMonthPicker = function(disableAnim){
39217 if(this.monthPicker){
39218 Roo.log("hideMonthPicker called");
39219 if(disableAnim === true){
39220 this.monthPicker.hide();
39222 this.monthPicker.slideOut('t', {duration:.2});
39223 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39224 p.fireEvent("select", this, this.value);
39230 Roo.log('picker set value');
39231 Roo.log(this.getValue());
39232 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39233 m.show(this.el, 'tl-bl?');
39234 ignorehide = false;
39235 // this will trigger hideMonthPicker..
39238 // hidden the day picker
39239 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39245 p.showMonthPicker.defer(100, p);
39251 beforeBlur : function(){
39252 var v = this.parseDate(this.getRawValue());
39258 /** @cfg {Boolean} grow @hide */
39259 /** @cfg {Number} growMin @hide */
39260 /** @cfg {Number} growMax @hide */
39267 * Ext JS Library 1.1.1
39268 * Copyright(c) 2006-2007, Ext JS, LLC.
39270 * Originally Released Under LGPL - original licence link has changed is not relivant.
39273 * <script type="text/javascript">
39278 * @class Roo.form.ComboBox
39279 * @extends Roo.form.TriggerField
39280 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39282 * Create a new ComboBox.
39283 * @param {Object} config Configuration options
39285 Roo.form.ComboBox = function(config){
39286 Roo.form.ComboBox.superclass.constructor.call(this, config);
39290 * Fires when the dropdown list is expanded
39291 * @param {Roo.form.ComboBox} combo This combo box
39296 * Fires when the dropdown list is collapsed
39297 * @param {Roo.form.ComboBox} combo This combo box
39301 * @event beforeselect
39302 * Fires before a list item is selected. Return false to cancel the selection.
39303 * @param {Roo.form.ComboBox} combo This combo box
39304 * @param {Roo.data.Record} record The data record returned from the underlying store
39305 * @param {Number} index The index of the selected item in the dropdown list
39307 'beforeselect' : true,
39310 * Fires when a list item is selected
39311 * @param {Roo.form.ComboBox} combo This combo box
39312 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39313 * @param {Number} index The index of the selected item in the dropdown list
39317 * @event beforequery
39318 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39319 * The event object passed has these properties:
39320 * @param {Roo.form.ComboBox} combo This combo box
39321 * @param {String} query The query
39322 * @param {Boolean} forceAll true to force "all" query
39323 * @param {Boolean} cancel true to cancel the query
39324 * @param {Object} e The query event object
39326 'beforequery': true,
39329 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39330 * @param {Roo.form.ComboBox} combo This combo box
39335 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39336 * @param {Roo.form.ComboBox} combo This combo box
39337 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39343 if(this.transform){
39344 this.allowDomMove = false;
39345 var s = Roo.getDom(this.transform);
39346 if(!this.hiddenName){
39347 this.hiddenName = s.name;
39350 this.mode = 'local';
39351 var d = [], opts = s.options;
39352 for(var i = 0, len = opts.length;i < len; i++){
39354 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39356 this.value = value;
39358 d.push([value, o.text]);
39360 this.store = new Roo.data.SimpleStore({
39362 fields: ['value', 'text'],
39365 this.valueField = 'value';
39366 this.displayField = 'text';
39368 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39369 if(!this.lazyRender){
39370 this.target = true;
39371 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39372 s.parentNode.removeChild(s); // remove it
39373 this.render(this.el.parentNode);
39375 s.parentNode.removeChild(s); // remove it
39380 this.store = Roo.factory(this.store, Roo.data);
39383 this.selectedIndex = -1;
39384 if(this.mode == 'local'){
39385 if(config.queryDelay === undefined){
39386 this.queryDelay = 10;
39388 if(config.minChars === undefined){
39394 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39396 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39399 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39400 * rendering into an Roo.Editor, defaults to false)
39403 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39404 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39407 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39410 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39411 * the dropdown list (defaults to undefined, with no header element)
39415 * @cfg {String/Roo.Template} tpl The template to use to render the output
39419 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39421 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39423 listWidth: undefined,
39425 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39426 * mode = 'remote' or 'text' if mode = 'local')
39428 displayField: undefined,
39430 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39431 * mode = 'remote' or 'value' if mode = 'local').
39432 * Note: use of a valueField requires the user make a selection
39433 * in order for a value to be mapped.
39435 valueField: undefined,
39439 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39440 * field's data value (defaults to the underlying DOM element's name)
39442 hiddenName: undefined,
39444 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39448 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39450 selectedClass: 'x-combo-selected',
39452 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39453 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39454 * which displays a downward arrow icon).
39456 triggerClass : 'x-form-arrow-trigger',
39458 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39462 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39463 * anchor positions (defaults to 'tl-bl')
39465 listAlign: 'tl-bl?',
39467 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39471 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39472 * query specified by the allQuery config option (defaults to 'query')
39474 triggerAction: 'query',
39476 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39477 * (defaults to 4, does not apply if editable = false)
39481 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39482 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39486 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39487 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39491 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39492 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39496 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39497 * when editable = true (defaults to false)
39499 selectOnFocus:false,
39501 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39503 queryParam: 'query',
39505 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39506 * when mode = 'remote' (defaults to 'Loading...')
39508 loadingText: 'Loading...',
39510 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39514 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39518 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39519 * traditional select (defaults to true)
39523 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39527 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39531 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39532 * listWidth has a higher value)
39536 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39537 * allow the user to set arbitrary text into the field (defaults to false)
39539 forceSelection:false,
39541 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39542 * if typeAhead = true (defaults to 250)
39544 typeAheadDelay : 250,
39546 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39547 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39549 valueNotFoundText : undefined,
39551 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39553 blockFocus : false,
39556 * @cfg {Boolean} disableClear Disable showing of clear button.
39558 disableClear : false,
39560 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39562 alwaysQuery : false,
39568 // element that contains real text value.. (when hidden is used..)
39571 onRender : function(ct, position){
39572 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39573 if(this.hiddenName){
39574 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39576 this.hiddenField.value =
39577 this.hiddenValue !== undefined ? this.hiddenValue :
39578 this.value !== undefined ? this.value : '';
39580 // prevent input submission
39581 this.el.dom.removeAttribute('name');
39586 this.el.dom.setAttribute('autocomplete', 'off');
39589 var cls = 'x-combo-list';
39591 this.list = new Roo.Layer({
39592 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39595 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39596 this.list.setWidth(lw);
39597 this.list.swallowEvent('mousewheel');
39598 this.assetHeight = 0;
39601 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39602 this.assetHeight += this.header.getHeight();
39605 this.innerList = this.list.createChild({cls:cls+'-inner'});
39606 this.innerList.on('mouseover', this.onViewOver, this);
39607 this.innerList.on('mousemove', this.onViewMove, this);
39608 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39610 if(this.allowBlank && !this.pageSize && !this.disableClear){
39611 this.footer = this.list.createChild({cls:cls+'-ft'});
39612 this.pageTb = new Roo.Toolbar(this.footer);
39616 this.footer = this.list.createChild({cls:cls+'-ft'});
39617 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39618 {pageSize: this.pageSize});
39622 if (this.pageTb && this.allowBlank && !this.disableClear) {
39624 this.pageTb.add(new Roo.Toolbar.Fill(), {
39625 cls: 'x-btn-icon x-btn-clear',
39627 handler: function()
39630 _this.clearValue();
39631 _this.onSelect(false, -1);
39636 this.assetHeight += this.footer.getHeight();
39641 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39644 this.view = new Roo.View(this.innerList, this.tpl, {
39645 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39648 this.view.on('click', this.onViewClick, this);
39650 this.store.on('beforeload', this.onBeforeLoad, this);
39651 this.store.on('load', this.onLoad, this);
39652 this.store.on('loadexception', this.onLoadException, this);
39654 if(this.resizable){
39655 this.resizer = new Roo.Resizable(this.list, {
39656 pinned:true, handles:'se'
39658 this.resizer.on('resize', function(r, w, h){
39659 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39660 this.listWidth = w;
39661 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39662 this.restrictHeight();
39664 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39666 if(!this.editable){
39667 this.editable = true;
39668 this.setEditable(false);
39672 if (typeof(this.events.add.listeners) != 'undefined') {
39674 this.addicon = this.wrap.createChild(
39675 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39677 this.addicon.on('click', function(e) {
39678 this.fireEvent('add', this);
39681 if (typeof(this.events.edit.listeners) != 'undefined') {
39683 this.editicon = this.wrap.createChild(
39684 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39685 if (this.addicon) {
39686 this.editicon.setStyle('margin-left', '40px');
39688 this.editicon.on('click', function(e) {
39690 // we fire even if inothing is selected..
39691 this.fireEvent('edit', this, this.lastData );
39701 initEvents : function(){
39702 Roo.form.ComboBox.superclass.initEvents.call(this);
39704 this.keyNav = new Roo.KeyNav(this.el, {
39705 "up" : function(e){
39706 this.inKeyMode = true;
39710 "down" : function(e){
39711 if(!this.isExpanded()){
39712 this.onTriggerClick();
39714 this.inKeyMode = true;
39719 "enter" : function(e){
39720 this.onViewClick();
39724 "esc" : function(e){
39728 "tab" : function(e){
39729 this.onViewClick(false);
39730 this.fireEvent("specialkey", this, e);
39736 doRelay : function(foo, bar, hname){
39737 if(hname == 'down' || this.scope.isExpanded()){
39738 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39745 this.queryDelay = Math.max(this.queryDelay || 10,
39746 this.mode == 'local' ? 10 : 250);
39747 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39748 if(this.typeAhead){
39749 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39751 if(this.editable !== false){
39752 this.el.on("keyup", this.onKeyUp, this);
39754 if(this.forceSelection){
39755 this.on('blur', this.doForce, this);
39759 onDestroy : function(){
39761 this.view.setStore(null);
39762 this.view.el.removeAllListeners();
39763 this.view.el.remove();
39764 this.view.purgeListeners();
39767 this.list.destroy();
39770 this.store.un('beforeload', this.onBeforeLoad, this);
39771 this.store.un('load', this.onLoad, this);
39772 this.store.un('loadexception', this.onLoadException, this);
39774 Roo.form.ComboBox.superclass.onDestroy.call(this);
39778 fireKey : function(e){
39779 if(e.isNavKeyPress() && !this.list.isVisible()){
39780 this.fireEvent("specialkey", this, e);
39785 onResize: function(w, h){
39786 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39788 if(typeof w != 'number'){
39789 // we do not handle it!?!?
39792 var tw = this.trigger.getWidth();
39793 tw += this.addicon ? this.addicon.getWidth() : 0;
39794 tw += this.editicon ? this.editicon.getWidth() : 0;
39796 this.el.setWidth( this.adjustWidth('input', x));
39798 this.trigger.setStyle('left', x+'px');
39800 if(this.list && this.listWidth === undefined){
39801 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39802 this.list.setWidth(lw);
39803 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39811 * Allow or prevent the user from directly editing the field text. If false is passed,
39812 * the user will only be able to select from the items defined in the dropdown list. This method
39813 * is the runtime equivalent of setting the 'editable' config option at config time.
39814 * @param {Boolean} value True to allow the user to directly edit the field text
39816 setEditable : function(value){
39817 if(value == this.editable){
39820 this.editable = value;
39822 this.el.dom.setAttribute('readOnly', true);
39823 this.el.on('mousedown', this.onTriggerClick, this);
39824 this.el.addClass('x-combo-noedit');
39826 this.el.dom.setAttribute('readOnly', false);
39827 this.el.un('mousedown', this.onTriggerClick, this);
39828 this.el.removeClass('x-combo-noedit');
39833 onBeforeLoad : function(){
39834 if(!this.hasFocus){
39837 this.innerList.update(this.loadingText ?
39838 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39839 this.restrictHeight();
39840 this.selectedIndex = -1;
39844 onLoad : function(){
39845 if(!this.hasFocus){
39848 if(this.store.getCount() > 0){
39850 this.restrictHeight();
39851 if(this.lastQuery == this.allQuery){
39853 this.el.dom.select();
39855 if(!this.selectByValue(this.value, true)){
39856 this.select(0, true);
39860 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39861 this.taTask.delay(this.typeAheadDelay);
39865 this.onEmptyResults();
39870 onLoadException : function()
39873 Roo.log(this.store.reader.jsonData);
39874 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39875 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39881 onTypeAhead : function(){
39882 if(this.store.getCount() > 0){
39883 var r = this.store.getAt(0);
39884 var newValue = r.data[this.displayField];
39885 var len = newValue.length;
39886 var selStart = this.getRawValue().length;
39887 if(selStart != len){
39888 this.setRawValue(newValue);
39889 this.selectText(selStart, newValue.length);
39895 onSelect : function(record, index){
39896 if(this.fireEvent('beforeselect', this, record, index) !== false){
39897 this.setFromData(index > -1 ? record.data : false);
39899 this.fireEvent('select', this, record, index);
39904 * Returns the currently selected field value or empty string if no value is set.
39905 * @return {String} value The selected value
39907 getValue : function(){
39908 if(this.valueField){
39909 return typeof this.value != 'undefined' ? this.value : '';
39911 return Roo.form.ComboBox.superclass.getValue.call(this);
39915 * Clears any text/value currently set in the field
39917 clearValue : function(){
39918 if(this.hiddenField){
39919 this.hiddenField.value = '';
39922 this.setRawValue('');
39923 this.lastSelectionText = '';
39928 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39929 * will be displayed in the field. If the value does not match the data value of an existing item,
39930 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39931 * Otherwise the field will be blank (although the value will still be set).
39932 * @param {String} value The value to match
39934 setValue : function(v){
39936 if(this.valueField){
39937 var r = this.findRecord(this.valueField, v);
39939 text = r.data[this.displayField];
39940 }else if(this.valueNotFoundText !== undefined){
39941 text = this.valueNotFoundText;
39944 this.lastSelectionText = text;
39945 if(this.hiddenField){
39946 this.hiddenField.value = v;
39948 Roo.form.ComboBox.superclass.setValue.call(this, text);
39952 * @property {Object} the last set data for the element
39957 * Sets the value of the field based on a object which is related to the record format for the store.
39958 * @param {Object} value the value to set as. or false on reset?
39960 setFromData : function(o){
39961 var dv = ''; // display value
39962 var vv = ''; // value value..
39964 if (this.displayField) {
39965 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39967 // this is an error condition!!!
39968 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39971 if(this.valueField){
39972 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39974 if(this.hiddenField){
39975 this.hiddenField.value = vv;
39977 this.lastSelectionText = dv;
39978 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39982 // no hidden field.. - we store the value in 'value', but still display
39983 // display field!!!!
39984 this.lastSelectionText = dv;
39985 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39991 reset : function(){
39992 // overridden so that last data is reset..
39993 this.setValue(this.resetValue);
39994 this.clearInvalid();
39995 this.lastData = false;
39997 this.view.clearSelections();
40001 findRecord : function(prop, value){
40003 if(this.store.getCount() > 0){
40004 this.store.each(function(r){
40005 if(r.data[prop] == value){
40015 getName: function()
40017 // returns hidden if it's set..
40018 if (!this.rendered) {return ''};
40019 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40023 onViewMove : function(e, t){
40024 this.inKeyMode = false;
40028 onViewOver : function(e, t){
40029 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40032 var item = this.view.findItemFromChild(t);
40034 var index = this.view.indexOf(item);
40035 this.select(index, false);
40040 onViewClick : function(doFocus)
40042 var index = this.view.getSelectedIndexes()[0];
40043 var r = this.store.getAt(index);
40045 this.onSelect(r, index);
40047 if(doFocus !== false && !this.blockFocus){
40053 restrictHeight : function(){
40054 this.innerList.dom.style.height = '';
40055 var inner = this.innerList.dom;
40056 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40057 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40058 this.list.beginUpdate();
40059 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40060 this.list.alignTo(this.el, this.listAlign);
40061 this.list.endUpdate();
40065 onEmptyResults : function(){
40070 * Returns true if the dropdown list is expanded, else false.
40072 isExpanded : function(){
40073 return this.list.isVisible();
40077 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40078 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40079 * @param {String} value The data value of the item to select
40080 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40081 * selected item if it is not currently in view (defaults to true)
40082 * @return {Boolean} True if the value matched an item in the list, else false
40084 selectByValue : function(v, scrollIntoView){
40085 if(v !== undefined && v !== null){
40086 var r = this.findRecord(this.valueField || this.displayField, v);
40088 this.select(this.store.indexOf(r), scrollIntoView);
40096 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40097 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40098 * @param {Number} index The zero-based index of the list item to select
40099 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40100 * selected item if it is not currently in view (defaults to true)
40102 select : function(index, scrollIntoView){
40103 this.selectedIndex = index;
40104 this.view.select(index);
40105 if(scrollIntoView !== false){
40106 var el = this.view.getNode(index);
40108 this.innerList.scrollChildIntoView(el, false);
40114 selectNext : function(){
40115 var ct = this.store.getCount();
40117 if(this.selectedIndex == -1){
40119 }else if(this.selectedIndex < ct-1){
40120 this.select(this.selectedIndex+1);
40126 selectPrev : function(){
40127 var ct = this.store.getCount();
40129 if(this.selectedIndex == -1){
40131 }else if(this.selectedIndex != 0){
40132 this.select(this.selectedIndex-1);
40138 onKeyUp : function(e){
40139 if(this.editable !== false && !e.isSpecialKey()){
40140 this.lastKey = e.getKey();
40141 this.dqTask.delay(this.queryDelay);
40146 validateBlur : function(){
40147 return !this.list || !this.list.isVisible();
40151 initQuery : function(){
40152 this.doQuery(this.getRawValue());
40156 doForce : function(){
40157 if(this.el.dom.value.length > 0){
40158 this.el.dom.value =
40159 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40165 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40166 * query allowing the query action to be canceled if needed.
40167 * @param {String} query The SQL query to execute
40168 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40169 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40170 * saved in the current store (defaults to false)
40172 doQuery : function(q, forceAll){
40173 if(q === undefined || q === null){
40178 forceAll: forceAll,
40182 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40186 forceAll = qe.forceAll;
40187 if(forceAll === true || (q.length >= this.minChars)){
40188 if(this.lastQuery != q || this.alwaysQuery){
40189 this.lastQuery = q;
40190 if(this.mode == 'local'){
40191 this.selectedIndex = -1;
40193 this.store.clearFilter();
40195 this.store.filter(this.displayField, q);
40199 this.store.baseParams[this.queryParam] = q;
40201 params: this.getParams(q)
40206 this.selectedIndex = -1;
40213 getParams : function(q){
40215 //p[this.queryParam] = q;
40218 p.limit = this.pageSize;
40224 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40226 collapse : function(){
40227 if(!this.isExpanded()){
40231 Roo.get(document).un('mousedown', this.collapseIf, this);
40232 Roo.get(document).un('mousewheel', this.collapseIf, this);
40233 if (!this.editable) {
40234 Roo.get(document).un('keydown', this.listKeyPress, this);
40236 this.fireEvent('collapse', this);
40240 collapseIf : function(e){
40241 if(!e.within(this.wrap) && !e.within(this.list)){
40247 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40249 expand : function(){
40250 if(this.isExpanded() || !this.hasFocus){
40253 this.list.alignTo(this.el, this.listAlign);
40255 Roo.get(document).on('mousedown', this.collapseIf, this);
40256 Roo.get(document).on('mousewheel', this.collapseIf, this);
40257 if (!this.editable) {
40258 Roo.get(document).on('keydown', this.listKeyPress, this);
40261 this.fireEvent('expand', this);
40265 // Implements the default empty TriggerField.onTriggerClick function
40266 onTriggerClick : function(){
40270 if(this.isExpanded()){
40272 if (!this.blockFocus) {
40277 this.hasFocus = true;
40278 if(this.triggerAction == 'all') {
40279 this.doQuery(this.allQuery, true);
40281 this.doQuery(this.getRawValue());
40283 if (!this.blockFocus) {
40288 listKeyPress : function(e)
40290 //Roo.log('listkeypress');
40291 // scroll to first matching element based on key pres..
40292 if (e.isSpecialKey()) {
40295 var k = String.fromCharCode(e.getKey()).toUpperCase();
40298 var csel = this.view.getSelectedNodes();
40299 var cselitem = false;
40301 var ix = this.view.indexOf(csel[0]);
40302 cselitem = this.store.getAt(ix);
40303 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40309 this.store.each(function(v) {
40311 // start at existing selection.
40312 if (cselitem.id == v.id) {
40318 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40319 match = this.store.indexOf(v);
40324 if (match === false) {
40325 return true; // no more action?
40328 this.view.select(match);
40329 var sn = Roo.get(this.view.getSelectedNodes()[0])
40330 sn.scrollIntoView(sn.dom.parentNode, false);
40334 * @cfg {Boolean} grow
40338 * @cfg {Number} growMin
40342 * @cfg {Number} growMax
40350 * Copyright(c) 2010-2012, Roo J Solutions Limited
40357 * @class Roo.form.ComboBoxArray
40358 * @extends Roo.form.TextField
40359 * A facebook style adder... for lists of email / people / countries etc...
40360 * pick multiple items from a combo box, and shows each one.
40362 * Fred [x] Brian [x] [Pick another |v]
40365 * For this to work: it needs various extra information
40366 * - normal combo problay has
40368 * + displayField, valueField
40370 * For our purpose...
40373 * If we change from 'extends' to wrapping...
40380 * Create a new ComboBoxArray.
40381 * @param {Object} config Configuration options
40385 Roo.form.ComboBoxArray = function(config)
40389 * @event beforeremove
40390 * Fires before remove the value from the list
40391 * @param {Roo.form.ComboBoxArray} _self This combo box array
40392 * @param {Roo.form.ComboBoxArray.Item} item removed item
40394 'beforeremove' : true,
40397 * Fires when remove the value from the list
40398 * @param {Roo.form.ComboBoxArray} _self This combo box array
40399 * @param {Roo.form.ComboBoxArray.Item} item removed item
40406 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40408 this.items = new Roo.util.MixedCollection(false);
40410 // construct the child combo...
40420 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40423 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40428 // behavies liek a hiddne field
40429 inputType: 'hidden',
40431 * @cfg {Number} width The width of the box that displays the selected element
40438 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40442 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40444 hiddenName : false,
40447 // private the array of items that are displayed..
40449 // private - the hidden field el.
40451 // private - the filed el..
40454 //validateValue : function() { return true; }, // all values are ok!
40455 //onAddClick: function() { },
40457 onRender : function(ct, position)
40460 // create the standard hidden element
40461 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40464 // give fake names to child combo;
40465 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40466 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40468 this.combo = Roo.factory(this.combo, Roo.form);
40469 this.combo.onRender(ct, position);
40470 if (typeof(this.combo.width) != 'undefined') {
40471 this.combo.onResize(this.combo.width,0);
40474 this.combo.initEvents();
40476 // assigned so form know we need to do this..
40477 this.store = this.combo.store;
40478 this.valueField = this.combo.valueField;
40479 this.displayField = this.combo.displayField ;
40482 this.combo.wrap.addClass('x-cbarray-grp');
40484 var cbwrap = this.combo.wrap.createChild(
40485 {tag: 'div', cls: 'x-cbarray-cb'},
40490 this.hiddenEl = this.combo.wrap.createChild({
40491 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40493 this.el = this.combo.wrap.createChild({
40494 tag: 'input', type:'hidden' , name: this.name, value : ''
40496 // this.el.dom.removeAttribute("name");
40499 this.outerWrap = this.combo.wrap;
40500 this.wrap = cbwrap;
40502 this.outerWrap.setWidth(this.width);
40503 this.outerWrap.dom.removeChild(this.el.dom);
40505 this.wrap.dom.appendChild(this.el.dom);
40506 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40507 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40509 this.combo.trigger.setStyle('position','relative');
40510 this.combo.trigger.setStyle('left', '0px');
40511 this.combo.trigger.setStyle('top', '2px');
40513 this.combo.el.setStyle('vertical-align', 'text-bottom');
40515 //this.trigger.setStyle('vertical-align', 'top');
40517 // this should use the code from combo really... on('add' ....)
40521 this.adder = this.outerWrap.createChild(
40522 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40524 this.adder.on('click', function(e) {
40525 _t.fireEvent('adderclick', this, e);
40529 //this.adder.on('click', this.onAddClick, _t);
40532 this.combo.on('select', function(cb, rec, ix) {
40533 this.addItem(rec.data);
40536 cb.el.dom.value = '';
40537 //cb.lastData = rec.data;
40546 getName: function()
40548 // returns hidden if it's set..
40549 if (!this.rendered) {return ''};
40550 return this.hiddenName ? this.hiddenName : this.name;
40555 onResize: function(w, h){
40558 // not sure if this is needed..
40559 //this.combo.onResize(w,h);
40561 if(typeof w != 'number'){
40562 // we do not handle it!?!?
40565 var tw = this.combo.trigger.getWidth();
40566 tw += this.addicon ? this.addicon.getWidth() : 0;
40567 tw += this.editicon ? this.editicon.getWidth() : 0;
40569 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40571 this.combo.trigger.setStyle('left', '0px');
40573 if(this.list && this.listWidth === undefined){
40574 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40575 this.list.setWidth(lw);
40576 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40583 addItem: function(rec)
40585 var valueField = this.combo.valueField;
40586 var displayField = this.combo.displayField;
40587 if (this.items.indexOfKey(rec[valueField]) > -1) {
40588 //console.log("GOT " + rec.data.id);
40592 var x = new Roo.form.ComboBoxArray.Item({
40593 //id : rec[this.idField],
40595 displayField : displayField ,
40596 tipField : displayField ,
40600 this.items.add(rec[valueField],x);
40601 // add it before the element..
40602 this.updateHiddenEl();
40603 x.render(this.outerWrap, this.wrap.dom);
40604 // add the image handler..
40607 updateHiddenEl : function()
40610 if (!this.hiddenEl) {
40614 var idField = this.combo.valueField;
40616 this.items.each(function(f) {
40617 ar.push(f.data[idField]);
40620 this.hiddenEl.dom.value = ar.join(',');
40626 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40627 this.items.each(function(f) {
40630 this.el.dom.value = '';
40631 if (this.hiddenEl) {
40632 this.hiddenEl.dom.value = '';
40636 getValue: function()
40638 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40640 setValue: function(v) // not a valid action - must use addItems..
40647 if (this.store.isLocal && (typeof(v) == 'string')) {
40648 // then we can use the store to find the values..
40649 // comma seperated at present.. this needs to allow JSON based encoding..
40650 this.hiddenEl.value = v;
40652 Roo.each(v.split(','), function(k) {
40653 Roo.log("CHECK " + this.valueField + ',' + k);
40654 var li = this.store.query(this.valueField, k);
40659 add[this.valueField] = k;
40660 add[this.displayField] = li.item(0).data[this.displayField];
40666 if (typeof(v) == 'object' ) {
40667 // then let's assume it's an array of objects..
40668 Roo.each(v, function(l) {
40676 setFromData: function(v)
40678 // this recieves an object, if setValues is called.
40680 this.el.dom.value = v[this.displayField];
40681 this.hiddenEl.dom.value = v[this.valueField];
40682 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40685 var kv = v[this.valueField];
40686 var dv = v[this.displayField];
40687 kv = typeof(kv) != 'string' ? '' : kv;
40688 dv = typeof(dv) != 'string' ? '' : dv;
40691 var keys = kv.split(',');
40692 var display = dv.split(',');
40693 for (var i = 0 ; i < keys.length; i++) {
40696 add[this.valueField] = keys[i];
40697 add[this.displayField] = display[i];
40705 * Validates the combox array value
40706 * @return {Boolean} True if the value is valid, else false
40708 validate : function(){
40709 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40710 this.clearInvalid();
40716 validateValue : function(value){
40717 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40725 isDirty : function() {
40726 if(this.disabled) {
40731 var d = Roo.decode(String(this.originalValue));
40733 return String(this.getValue()) !== String(this.originalValue);
40736 var originalValue = [];
40738 for (var i = 0; i < d.length; i++){
40739 originalValue.push(d[i][this.valueField]);
40742 return String(this.getValue()) !== String(originalValue.join(','));
40751 * @class Roo.form.ComboBoxArray.Item
40752 * @extends Roo.BoxComponent
40753 * A selected item in the list
40754 * Fred [x] Brian [x] [Pick another |v]
40757 * Create a new item.
40758 * @param {Object} config Configuration options
40761 Roo.form.ComboBoxArray.Item = function(config) {
40762 config.id = Roo.id();
40763 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40766 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40769 displayField : false,
40773 defaultAutoCreate : {
40775 cls: 'x-cbarray-item',
40782 src : Roo.BLANK_IMAGE_URL ,
40790 onRender : function(ct, position)
40792 Roo.form.Field.superclass.onRender.call(this, ct, position);
40795 var cfg = this.getAutoCreate();
40796 this.el = ct.createChild(cfg, position);
40799 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40801 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40802 this.cb.renderer(this.data) :
40803 String.format('{0}',this.data[this.displayField]);
40806 this.el.child('div').dom.setAttribute('qtip',
40807 String.format('{0}',this.data[this.tipField])
40810 this.el.child('img').on('click', this.remove, this);
40814 remove : function()
40816 if(this.cb.disabled){
40820 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40821 this.cb.items.remove(this);
40822 this.el.child('img').un('click', this.remove, this);
40824 this.cb.updateHiddenEl();
40826 this.cb.fireEvent('remove', this.cb, this);
40832 * Ext JS Library 1.1.1
40833 * Copyright(c) 2006-2007, Ext JS, LLC.
40835 * Originally Released Under LGPL - original licence link has changed is not relivant.
40838 * <script type="text/javascript">
40841 * @class Roo.form.Checkbox
40842 * @extends Roo.form.Field
40843 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40845 * Creates a new Checkbox
40846 * @param {Object} config Configuration options
40848 Roo.form.Checkbox = function(config){
40849 Roo.form.Checkbox.superclass.constructor.call(this, config);
40853 * Fires when the checkbox is checked or unchecked.
40854 * @param {Roo.form.Checkbox} this This checkbox
40855 * @param {Boolean} checked The new checked value
40861 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40863 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40865 focusClass : undefined,
40867 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40869 fieldClass: "x-form-field",
40871 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40875 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40876 * {tag: "input", type: "checkbox", autocomplete: "off"})
40878 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40880 * @cfg {String} boxLabel The text that appears beside the checkbox
40884 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40888 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40890 valueOff: '0', // value when not checked..
40892 actionMode : 'viewEl',
40895 itemCls : 'x-menu-check-item x-form-item',
40896 groupClass : 'x-menu-group-item',
40897 inputType : 'hidden',
40900 inSetChecked: false, // check that we are not calling self...
40902 inputElement: false, // real input element?
40903 basedOn: false, // ????
40905 isFormField: true, // not sure where this is needed!!!!
40907 onResize : function(){
40908 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40909 if(!this.boxLabel){
40910 this.el.alignTo(this.wrap, 'c-c');
40914 initEvents : function(){
40915 Roo.form.Checkbox.superclass.initEvents.call(this);
40916 this.el.on("click", this.onClick, this);
40917 this.el.on("change", this.onClick, this);
40921 getResizeEl : function(){
40925 getPositionEl : function(){
40930 onRender : function(ct, position){
40931 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40933 if(this.inputValue !== undefined){
40934 this.el.dom.value = this.inputValue;
40937 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40938 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40939 var viewEl = this.wrap.createChild({
40940 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40941 this.viewEl = viewEl;
40942 this.wrap.on('click', this.onClick, this);
40944 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40945 this.el.on('propertychange', this.setFromHidden, this); //ie
40950 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40951 // viewEl.on('click', this.onClick, this);
40953 //if(this.checked){
40954 this.setChecked(this.checked);
40956 //this.checked = this.el.dom;
40962 initValue : Roo.emptyFn,
40965 * Returns the checked state of the checkbox.
40966 * @return {Boolean} True if checked, else false
40968 getValue : function(){
40970 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40972 return this.valueOff;
40977 onClick : function(){
40978 if (this.disabled) {
40981 this.setChecked(!this.checked);
40983 //if(this.el.dom.checked != this.checked){
40984 // this.setValue(this.el.dom.checked);
40989 * Sets the checked state of the checkbox.
40990 * On is always based on a string comparison between inputValue and the param.
40991 * @param {Boolean/String} value - the value to set
40992 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40994 setValue : function(v,suppressEvent){
40997 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40998 //if(this.el && this.el.dom){
40999 // this.el.dom.checked = this.checked;
41000 // this.el.dom.defaultChecked = this.checked;
41002 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
41003 //this.fireEvent("check", this, this.checked);
41006 setChecked : function(state,suppressEvent)
41008 if (this.inSetChecked) {
41009 this.checked = state;
41015 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41017 this.checked = state;
41018 if(suppressEvent !== true){
41019 this.fireEvent('check', this, state);
41021 this.inSetChecked = true;
41022 this.el.dom.value = state ? this.inputValue : this.valueOff;
41023 this.inSetChecked = false;
41026 // handle setting of hidden value by some other method!!?!?
41027 setFromHidden: function()
41032 //console.log("SET FROM HIDDEN");
41033 //alert('setFrom hidden');
41034 this.setValue(this.el.dom.value);
41037 onDestroy : function()
41040 Roo.get(this.viewEl).remove();
41043 Roo.form.Checkbox.superclass.onDestroy.call(this);
41048 * Ext JS Library 1.1.1
41049 * Copyright(c) 2006-2007, Ext JS, LLC.
41051 * Originally Released Under LGPL - original licence link has changed is not relivant.
41054 * <script type="text/javascript">
41058 * @class Roo.form.Radio
41059 * @extends Roo.form.Checkbox
41060 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41061 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41063 * Creates a new Radio
41064 * @param {Object} config Configuration options
41066 Roo.form.Radio = function(){
41067 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41069 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41070 inputType: 'radio',
41073 * If this radio is part of a group, it will return the selected value
41076 getGroupValue : function(){
41077 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41081 onRender : function(ct, position){
41082 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41084 if(this.inputValue !== undefined){
41085 this.el.dom.value = this.inputValue;
41088 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41089 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41090 //var viewEl = this.wrap.createChild({
41091 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41092 //this.viewEl = viewEl;
41093 //this.wrap.on('click', this.onClick, this);
41095 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41096 //this.el.on('propertychange', this.setFromHidden, this); //ie
41101 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41102 // viewEl.on('click', this.onClick, this);
41105 this.el.dom.checked = 'checked' ;
41111 });//<script type="text/javascript">
41114 * Based Ext JS Library 1.1.1
41115 * Copyright(c) 2006-2007, Ext JS, LLC.
41121 * @class Roo.HtmlEditorCore
41122 * @extends Roo.Component
41123 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41125 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41128 Roo.HtmlEditorCore = function(config){
41131 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41136 * @event initialize
41137 * Fires when the editor is fully initialized (including the iframe)
41138 * @param {Roo.HtmlEditorCore} this
41143 * Fires when the editor is first receives the focus. Any insertion must wait
41144 * until after this event.
41145 * @param {Roo.HtmlEditorCore} this
41149 * @event beforesync
41150 * Fires before the textarea is updated with content from the editor iframe. Return false
41151 * to cancel the sync.
41152 * @param {Roo.HtmlEditorCore} this
41153 * @param {String} html
41157 * @event beforepush
41158 * Fires before the iframe editor is updated with content from the textarea. Return false
41159 * to cancel the push.
41160 * @param {Roo.HtmlEditorCore} this
41161 * @param {String} html
41166 * Fires when the textarea is updated with content from the editor iframe.
41167 * @param {Roo.HtmlEditorCore} this
41168 * @param {String} html
41173 * Fires when the iframe editor is updated with content from the textarea.
41174 * @param {Roo.HtmlEditorCore} this
41175 * @param {String} html
41180 * @event editorevent
41181 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41182 * @param {Roo.HtmlEditorCore} this
41188 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41190 // defaults : white / black...
41191 this.applyBlacklists();
41198 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41202 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41208 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41213 * @cfg {Number} height (in pixels)
41217 * @cfg {Number} width (in pixels)
41222 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41225 stylesheets: false,
41230 // private properties
41231 validationEvent : false,
41233 initialized : false,
41235 sourceEditMode : false,
41236 onFocus : Roo.emptyFn,
41238 hideMode:'offsets',
41242 // blacklist + whitelisted elements..
41249 * Protected method that will not generally be called directly. It
41250 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41251 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41253 getDocMarkup : function(){
41257 // inherit styels from page...??
41258 if (this.stylesheets === false) {
41260 Roo.get(document.head).select('style').each(function(node) {
41261 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41264 Roo.get(document.head).select('link').each(function(node) {
41265 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41268 } else if (!this.stylesheets.length) {
41270 st = '<style type="text/css">' +
41271 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41277 st += '<style type="text/css">' +
41278 'IMG { cursor: pointer } ' +
41282 return '<html><head>' + st +
41283 //<style type="text/css">' +
41284 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41286 ' </head><body class="roo-htmleditor-body"></body></html>';
41290 onRender : function(ct, position)
41293 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41294 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41297 this.el.dom.style.border = '0 none';
41298 this.el.dom.setAttribute('tabIndex', -1);
41299 this.el.addClass('x-hidden hide');
41303 if(Roo.isIE){ // fix IE 1px bogus margin
41304 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41308 this.frameId = Roo.id();
41312 var iframe = this.owner.wrap.createChild({
41314 cls: 'form-control', // bootstrap..
41316 name: this.frameId,
41317 frameBorder : 'no',
41318 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41323 this.iframe = iframe.dom;
41325 this.assignDocWin();
41327 this.doc.designMode = 'on';
41330 this.doc.write(this.getDocMarkup());
41334 var task = { // must defer to wait for browser to be ready
41336 //console.log("run task?" + this.doc.readyState);
41337 this.assignDocWin();
41338 if(this.doc.body || this.doc.readyState == 'complete'){
41340 this.doc.designMode="on";
41344 Roo.TaskMgr.stop(task);
41345 this.initEditor.defer(10, this);
41352 Roo.TaskMgr.start(task);
41357 onResize : function(w, h)
41359 Roo.log('resize: ' +w + ',' + h );
41360 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41364 if(typeof w == 'number'){
41366 this.iframe.style.width = w + 'px';
41368 if(typeof h == 'number'){
41370 this.iframe.style.height = h + 'px';
41372 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41379 * Toggles the editor between standard and source edit mode.
41380 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41382 toggleSourceEdit : function(sourceEditMode){
41384 this.sourceEditMode = sourceEditMode === true;
41386 if(this.sourceEditMode){
41388 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41391 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41392 //this.iframe.className = '';
41395 //this.setSize(this.owner.wrap.getSize());
41396 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41403 * Protected method that will not generally be called directly. If you need/want
41404 * custom HTML cleanup, this is the method you should override.
41405 * @param {String} html The HTML to be cleaned
41406 * return {String} The cleaned HTML
41408 cleanHtml : function(html){
41409 html = String(html);
41410 if(html.length > 5){
41411 if(Roo.isSafari){ // strip safari nonsense
41412 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41415 if(html == ' '){
41422 * HTML Editor -> Textarea
41423 * Protected method that will not generally be called directly. Syncs the contents
41424 * of the editor iframe with the textarea.
41426 syncValue : function(){
41427 if(this.initialized){
41428 var bd = (this.doc.body || this.doc.documentElement);
41429 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41430 var html = bd.innerHTML;
41432 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41433 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41435 html = '<div style="'+m[0]+'">' + html + '</div>';
41438 html = this.cleanHtml(html);
41439 // fix up the special chars.. normaly like back quotes in word...
41440 // however we do not want to do this with chinese..
41441 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41442 var cc = b.charCodeAt();
41444 (cc >= 0x4E00 && cc < 0xA000 ) ||
41445 (cc >= 0x3400 && cc < 0x4E00 ) ||
41446 (cc >= 0xf900 && cc < 0xfb00 )
41452 if(this.owner.fireEvent('beforesync', this, html) !== false){
41453 this.el.dom.value = html;
41454 this.owner.fireEvent('sync', this, html);
41460 * Protected method that will not generally be called directly. Pushes the value of the textarea
41461 * into the iframe editor.
41463 pushValue : function(){
41464 if(this.initialized){
41465 var v = this.el.dom.value.trim();
41467 // if(v.length < 1){
41471 if(this.owner.fireEvent('beforepush', this, v) !== false){
41472 var d = (this.doc.body || this.doc.documentElement);
41474 this.cleanUpPaste();
41475 this.el.dom.value = d.innerHTML;
41476 this.owner.fireEvent('push', this, v);
41482 deferFocus : function(){
41483 this.focus.defer(10, this);
41487 focus : function(){
41488 if(this.win && !this.sourceEditMode){
41495 assignDocWin: function()
41497 var iframe = this.iframe;
41500 this.doc = iframe.contentWindow.document;
41501 this.win = iframe.contentWindow;
41503 // if (!Roo.get(this.frameId)) {
41506 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41507 // this.win = Roo.get(this.frameId).dom.contentWindow;
41509 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41513 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41514 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41519 initEditor : function(){
41520 //console.log("INIT EDITOR");
41521 this.assignDocWin();
41525 this.doc.designMode="on";
41527 this.doc.write(this.getDocMarkup());
41530 var dbody = (this.doc.body || this.doc.documentElement);
41531 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41532 // this copies styles from the containing element into thsi one..
41533 // not sure why we need all of this..
41534 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41536 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41537 //ss['background-attachment'] = 'fixed'; // w3c
41538 dbody.bgProperties = 'fixed'; // ie
41539 //Roo.DomHelper.applyStyles(dbody, ss);
41540 Roo.EventManager.on(this.doc, {
41541 //'mousedown': this.onEditorEvent,
41542 'mouseup': this.onEditorEvent,
41543 'dblclick': this.onEditorEvent,
41544 'click': this.onEditorEvent,
41545 'keyup': this.onEditorEvent,
41550 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41552 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41553 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41555 this.initialized = true;
41557 this.owner.fireEvent('initialize', this);
41562 onDestroy : function(){
41568 //for (var i =0; i < this.toolbars.length;i++) {
41569 // // fixme - ask toolbars for heights?
41570 // this.toolbars[i].onDestroy();
41573 //this.wrap.dom.innerHTML = '';
41574 //this.wrap.remove();
41579 onFirstFocus : function(){
41581 this.assignDocWin();
41584 this.activated = true;
41587 if(Roo.isGecko){ // prevent silly gecko errors
41589 var s = this.win.getSelection();
41590 if(!s.focusNode || s.focusNode.nodeType != 3){
41591 var r = s.getRangeAt(0);
41592 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41597 this.execCmd('useCSS', true);
41598 this.execCmd('styleWithCSS', false);
41601 this.owner.fireEvent('activate', this);
41605 adjustFont: function(btn){
41606 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41607 //if(Roo.isSafari){ // safari
41610 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41611 if(Roo.isSafari){ // safari
41612 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41613 v = (v < 10) ? 10 : v;
41614 v = (v > 48) ? 48 : v;
41615 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41620 v = Math.max(1, v+adjust);
41622 this.execCmd('FontSize', v );
41625 onEditorEvent : function(e)
41627 this.owner.fireEvent('editorevent', this, e);
41628 // this.updateToolbar();
41629 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41632 insertTag : function(tg)
41634 // could be a bit smarter... -> wrap the current selected tRoo..
41635 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41637 range = this.createRange(this.getSelection());
41638 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41639 wrappingNode.appendChild(range.extractContents());
41640 range.insertNode(wrappingNode);
41647 this.execCmd("formatblock", tg);
41651 insertText : function(txt)
41655 var range = this.createRange();
41656 range.deleteContents();
41657 //alert(Sender.getAttribute('label'));
41659 range.insertNode(this.doc.createTextNode(txt));
41665 * Executes a Midas editor command on the editor document and performs necessary focus and
41666 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41667 * @param {String} cmd The Midas command
41668 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41670 relayCmd : function(cmd, value){
41672 this.execCmd(cmd, value);
41673 this.owner.fireEvent('editorevent', this);
41674 //this.updateToolbar();
41675 this.owner.deferFocus();
41679 * Executes a Midas editor command directly on the editor document.
41680 * For visual commands, you should use {@link #relayCmd} instead.
41681 * <b>This should only be called after the editor is initialized.</b>
41682 * @param {String} cmd The Midas command
41683 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41685 execCmd : function(cmd, value){
41686 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41693 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41695 * @param {String} text | dom node..
41697 insertAtCursor : function(text)
41702 if(!this.activated){
41708 var r = this.doc.selection.createRange();
41719 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41723 // from jquery ui (MIT licenced)
41725 var win = this.win;
41727 if (win.getSelection && win.getSelection().getRangeAt) {
41728 range = win.getSelection().getRangeAt(0);
41729 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41730 range.insertNode(node);
41731 } else if (win.document.selection && win.document.selection.createRange) {
41732 // no firefox support
41733 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41734 win.document.selection.createRange().pasteHTML(txt);
41736 // no firefox support
41737 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41738 this.execCmd('InsertHTML', txt);
41747 mozKeyPress : function(e){
41749 var c = e.getCharCode(), cmd;
41752 c = String.fromCharCode(c).toLowerCase();
41766 this.cleanUpPaste.defer(100, this);
41774 e.preventDefault();
41782 fixKeys : function(){ // load time branching for fastest keydown performance
41784 return function(e){
41785 var k = e.getKey(), r;
41788 r = this.doc.selection.createRange();
41791 r.pasteHTML('    ');
41798 r = this.doc.selection.createRange();
41800 var target = r.parentElement();
41801 if(!target || target.tagName.toLowerCase() != 'li'){
41803 r.pasteHTML('<br />');
41809 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41810 this.cleanUpPaste.defer(100, this);
41816 }else if(Roo.isOpera){
41817 return function(e){
41818 var k = e.getKey();
41822 this.execCmd('InsertHTML','    ');
41825 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41826 this.cleanUpPaste.defer(100, this);
41831 }else if(Roo.isSafari){
41832 return function(e){
41833 var k = e.getKey();
41837 this.execCmd('InsertText','\t');
41841 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41842 this.cleanUpPaste.defer(100, this);
41850 getAllAncestors: function()
41852 var p = this.getSelectedNode();
41855 a.push(p); // push blank onto stack..
41856 p = this.getParentElement();
41860 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41864 a.push(this.doc.body);
41868 lastSelNode : false,
41871 getSelection : function()
41873 this.assignDocWin();
41874 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41877 getSelectedNode: function()
41879 // this may only work on Gecko!!!
41881 // should we cache this!!!!
41886 var range = this.createRange(this.getSelection()).cloneRange();
41889 var parent = range.parentElement();
41891 var testRange = range.duplicate();
41892 testRange.moveToElementText(parent);
41893 if (testRange.inRange(range)) {
41896 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41899 parent = parent.parentElement;
41904 // is ancestor a text element.
41905 var ac = range.commonAncestorContainer;
41906 if (ac.nodeType == 3) {
41907 ac = ac.parentNode;
41910 var ar = ac.childNodes;
41913 var other_nodes = [];
41914 var has_other_nodes = false;
41915 for (var i=0;i<ar.length;i++) {
41916 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41919 // fullly contained node.
41921 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41926 // probably selected..
41927 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41928 other_nodes.push(ar[i]);
41932 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41937 has_other_nodes = true;
41939 if (!nodes.length && other_nodes.length) {
41940 nodes= other_nodes;
41942 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41948 createRange: function(sel)
41950 // this has strange effects when using with
41951 // top toolbar - not sure if it's a great idea.
41952 //this.editor.contentWindow.focus();
41953 if (typeof sel != "undefined") {
41955 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41957 return this.doc.createRange();
41960 return this.doc.createRange();
41963 getParentElement: function()
41966 this.assignDocWin();
41967 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41969 var range = this.createRange(sel);
41972 var p = range.commonAncestorContainer;
41973 while (p.nodeType == 3) { // text node
41984 * Range intersection.. the hard stuff...
41988 * [ -- selected range --- ]
41992 * if end is before start or hits it. fail.
41993 * if start is after end or hits it fail.
41995 * if either hits (but other is outside. - then it's not
42001 // @see http://www.thismuchiknow.co.uk/?p=64.
42002 rangeIntersectsNode : function(range, node)
42004 var nodeRange = node.ownerDocument.createRange();
42006 nodeRange.selectNode(node);
42008 nodeRange.selectNodeContents(node);
42011 var rangeStartRange = range.cloneRange();
42012 rangeStartRange.collapse(true);
42014 var rangeEndRange = range.cloneRange();
42015 rangeEndRange.collapse(false);
42017 var nodeStartRange = nodeRange.cloneRange();
42018 nodeStartRange.collapse(true);
42020 var nodeEndRange = nodeRange.cloneRange();
42021 nodeEndRange.collapse(false);
42023 return rangeStartRange.compareBoundaryPoints(
42024 Range.START_TO_START, nodeEndRange) == -1 &&
42025 rangeEndRange.compareBoundaryPoints(
42026 Range.START_TO_START, nodeStartRange) == 1;
42030 rangeCompareNode : function(range, node)
42032 var nodeRange = node.ownerDocument.createRange();
42034 nodeRange.selectNode(node);
42036 nodeRange.selectNodeContents(node);
42040 range.collapse(true);
42042 nodeRange.collapse(true);
42044 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42045 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42047 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42049 var nodeIsBefore = ss == 1;
42050 var nodeIsAfter = ee == -1;
42052 if (nodeIsBefore && nodeIsAfter)
42054 if (!nodeIsBefore && nodeIsAfter)
42055 return 1; //right trailed.
42057 if (nodeIsBefore && !nodeIsAfter)
42058 return 2; // left trailed.
42063 // private? - in a new class?
42064 cleanUpPaste : function()
42066 // cleans up the whole document..
42067 Roo.log('cleanuppaste');
42069 this.cleanUpChildren(this.doc.body);
42070 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42071 if (clean != this.doc.body.innerHTML) {
42072 this.doc.body.innerHTML = clean;
42077 cleanWordChars : function(input) {// change the chars to hex code
42078 var he = Roo.HtmlEditorCore;
42080 var output = input;
42081 Roo.each(he.swapCodes, function(sw) {
42082 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42084 output = output.replace(swapper, sw[1]);
42091 cleanUpChildren : function (n)
42093 if (!n.childNodes.length) {
42096 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42097 this.cleanUpChild(n.childNodes[i]);
42104 cleanUpChild : function (node)
42107 //console.log(node);
42108 if (node.nodeName == "#text") {
42109 // clean up silly Windows -- stuff?
42112 if (node.nodeName == "#comment") {
42113 node.parentNode.removeChild(node);
42114 // clean up silly Windows -- stuff?
42117 var lcname = node.tagName.toLowerCase();
42118 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42119 // whitelist of tags..
42121 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42123 node.parentNode.removeChild(node);
42128 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42130 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42131 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42133 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42134 // remove_keep_children = true;
42137 if (remove_keep_children) {
42138 this.cleanUpChildren(node);
42139 // inserts everything just before this node...
42140 while (node.childNodes.length) {
42141 var cn = node.childNodes[0];
42142 node.removeChild(cn);
42143 node.parentNode.insertBefore(cn, node);
42145 node.parentNode.removeChild(node);
42149 if (!node.attributes || !node.attributes.length) {
42150 this.cleanUpChildren(node);
42154 function cleanAttr(n,v)
42157 if (v.match(/^\./) || v.match(/^\//)) {
42160 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42163 if (v.match(/^#/)) {
42166 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42167 node.removeAttribute(n);
42171 var cwhite = this.cwhite;
42172 var cblack = this.cblack;
42174 function cleanStyle(n,v)
42176 if (v.match(/expression/)) { //XSS?? should we even bother..
42177 node.removeAttribute(n);
42181 var parts = v.split(/;/);
42184 Roo.each(parts, function(p) {
42185 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42189 var l = p.split(':').shift().replace(/\s+/g,'');
42190 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42192 if ( cwhite.length && cblack.indexOf(l) > -1) {
42193 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42194 //node.removeAttribute(n);
42198 // only allow 'c whitelisted system attributes'
42199 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42200 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42201 //node.removeAttribute(n);
42211 if (clean.length) {
42212 node.setAttribute(n, clean.join(';'));
42214 node.removeAttribute(n);
42220 for (var i = node.attributes.length-1; i > -1 ; i--) {
42221 var a = node.attributes[i];
42224 if (a.name.toLowerCase().substr(0,2)=='on') {
42225 node.removeAttribute(a.name);
42228 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42229 node.removeAttribute(a.name);
42232 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42233 cleanAttr(a.name,a.value); // fixme..
42236 if (a.name == 'style') {
42237 cleanStyle(a.name,a.value);
42240 /// clean up MS crap..
42241 // tecnically this should be a list of valid class'es..
42244 if (a.name == 'class') {
42245 if (a.value.match(/^Mso/)) {
42246 node.className = '';
42249 if (a.value.match(/body/)) {
42250 node.className = '';
42261 this.cleanUpChildren(node);
42267 * Clean up MS wordisms...
42269 cleanWord : function(node)
42274 this.cleanWord(this.doc.body);
42277 if (node.nodeName == "#text") {
42278 // clean up silly Windows -- stuff?
42281 if (node.nodeName == "#comment") {
42282 node.parentNode.removeChild(node);
42283 // clean up silly Windows -- stuff?
42287 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42288 node.parentNode.removeChild(node);
42292 // remove - but keep children..
42293 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42294 while (node.childNodes.length) {
42295 var cn = node.childNodes[0];
42296 node.removeChild(cn);
42297 node.parentNode.insertBefore(cn, node);
42299 node.parentNode.removeChild(node);
42300 this.iterateChildren(node, this.cleanWord);
42304 if (node.className.length) {
42306 var cn = node.className.split(/\W+/);
42308 Roo.each(cn, function(cls) {
42309 if (cls.match(/Mso[a-zA-Z]+/)) {
42314 node.className = cna.length ? cna.join(' ') : '';
42316 node.removeAttribute("class");
42320 if (node.hasAttribute("lang")) {
42321 node.removeAttribute("lang");
42324 if (node.hasAttribute("style")) {
42326 var styles = node.getAttribute("style").split(";");
42328 Roo.each(styles, function(s) {
42329 if (!s.match(/:/)) {
42332 var kv = s.split(":");
42333 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42336 // what ever is left... we allow.
42339 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42340 if (!nstyle.length) {
42341 node.removeAttribute('style');
42344 this.iterateChildren(node, this.cleanWord);
42350 * iterateChildren of a Node, calling fn each time, using this as the scole..
42351 * @param {DomNode} node node to iterate children of.
42352 * @param {Function} fn method of this class to call on each item.
42354 iterateChildren : function(node, fn)
42356 if (!node.childNodes.length) {
42359 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42360 fn.call(this, node.childNodes[i])
42366 * cleanTableWidths.
42368 * Quite often pasting from word etc.. results in tables with column and widths.
42369 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42372 cleanTableWidths : function(node)
42377 this.cleanTableWidths(this.doc.body);
42382 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42385 Roo.log(node.tagName);
42386 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42387 this.iterateChildren(node, this.cleanTableWidths);
42390 if (node.hasAttribute('width')) {
42391 node.removeAttribute('width');
42395 if (node.hasAttribute("style")) {
42398 var styles = node.getAttribute("style").split(";");
42400 Roo.each(styles, function(s) {
42401 if (!s.match(/:/)) {
42404 var kv = s.split(":");
42405 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42408 // what ever is left... we allow.
42411 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42412 if (!nstyle.length) {
42413 node.removeAttribute('style');
42417 this.iterateChildren(node, this.cleanTableWidths);
42425 domToHTML : function(currentElement, depth, nopadtext) {
42427 depth = depth || 0;
42428 nopadtext = nopadtext || false;
42430 if (!currentElement) {
42431 return this.domToHTML(this.doc.body);
42434 //Roo.log(currentElement);
42436 var allText = false;
42437 var nodeName = currentElement.nodeName;
42438 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42440 if (nodeName == '#text') {
42442 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42447 if (nodeName != 'BODY') {
42450 // Prints the node tagName, such as <A>, <IMG>, etc
42453 for(i = 0; i < currentElement.attributes.length;i++) {
42455 var aname = currentElement.attributes.item(i).name;
42456 if (!currentElement.attributes.item(i).value.length) {
42459 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42462 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42471 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42474 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42479 // Traverse the tree
42481 var currentElementChild = currentElement.childNodes.item(i);
42482 var allText = true;
42483 var innerHTML = '';
42485 while (currentElementChild) {
42486 // Formatting code (indent the tree so it looks nice on the screen)
42487 var nopad = nopadtext;
42488 if (lastnode == 'SPAN') {
42492 if (currentElementChild.nodeName == '#text') {
42493 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42494 toadd = nopadtext ? toadd : toadd.trim();
42495 if (!nopad && toadd.length > 80) {
42496 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42498 innerHTML += toadd;
42501 currentElementChild = currentElement.childNodes.item(i);
42507 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42509 // Recursively traverse the tree structure of the child node
42510 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42511 lastnode = currentElementChild.nodeName;
42513 currentElementChild=currentElement.childNodes.item(i);
42519 // The remaining code is mostly for formatting the tree
42520 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42525 ret+= "</"+tagName+">";
42531 applyBlacklists : function()
42533 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42534 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42538 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42539 if (b.indexOf(tag) > -1) {
42542 this.white.push(tag);
42546 Roo.each(w, function(tag) {
42547 if (b.indexOf(tag) > -1) {
42550 if (this.white.indexOf(tag) > -1) {
42553 this.white.push(tag);
42558 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42559 if (w.indexOf(tag) > -1) {
42562 this.black.push(tag);
42566 Roo.each(b, function(tag) {
42567 if (w.indexOf(tag) > -1) {
42570 if (this.black.indexOf(tag) > -1) {
42573 this.black.push(tag);
42578 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42579 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42583 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42584 if (b.indexOf(tag) > -1) {
42587 this.cwhite.push(tag);
42591 Roo.each(w, function(tag) {
42592 if (b.indexOf(tag) > -1) {
42595 if (this.cwhite.indexOf(tag) > -1) {
42598 this.cwhite.push(tag);
42603 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42604 if (w.indexOf(tag) > -1) {
42607 this.cblack.push(tag);
42611 Roo.each(b, function(tag) {
42612 if (w.indexOf(tag) > -1) {
42615 if (this.cblack.indexOf(tag) > -1) {
42618 this.cblack.push(tag);
42623 setStylesheets : function(stylesheets)
42625 if(typeof(stylesheets) == 'string'){
42626 Roo.get(this.iframe.contentDocument.head).createChild({
42628 rel : 'stylesheet',
42637 Roo.each(stylesheets, function(s) {
42642 Roo.get(_this.iframe.contentDocument.head).createChild({
42644 rel : 'stylesheet',
42653 removeStylesheets : function()
42657 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42662 // hide stuff that is not compatible
42676 * @event specialkey
42680 * @cfg {String} fieldClass @hide
42683 * @cfg {String} focusClass @hide
42686 * @cfg {String} autoCreate @hide
42689 * @cfg {String} inputType @hide
42692 * @cfg {String} invalidClass @hide
42695 * @cfg {String} invalidText @hide
42698 * @cfg {String} msgFx @hide
42701 * @cfg {String} validateOnBlur @hide
42705 Roo.HtmlEditorCore.white = [
42706 'area', 'br', 'img', 'input', 'hr', 'wbr',
42708 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42709 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42710 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42711 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42712 'table', 'ul', 'xmp',
42714 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42717 'dir', 'menu', 'ol', 'ul', 'dl',
42723 Roo.HtmlEditorCore.black = [
42724 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42726 'base', 'basefont', 'bgsound', 'blink', 'body',
42727 'frame', 'frameset', 'head', 'html', 'ilayer',
42728 'iframe', 'layer', 'link', 'meta', 'object',
42729 'script', 'style' ,'title', 'xml' // clean later..
42731 Roo.HtmlEditorCore.clean = [
42732 'script', 'style', 'title', 'xml'
42734 Roo.HtmlEditorCore.remove = [
42739 Roo.HtmlEditorCore.ablack = [
42743 Roo.HtmlEditorCore.aclean = [
42744 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42748 Roo.HtmlEditorCore.pwhite= [
42749 'http', 'https', 'mailto'
42752 // white listed style attributes.
42753 Roo.HtmlEditorCore.cwhite= [
42754 // 'text-align', /// default is to allow most things..
42760 // black listed style attributes.
42761 Roo.HtmlEditorCore.cblack= [
42762 // 'font-size' -- this can be set by the project
42766 Roo.HtmlEditorCore.swapCodes =[
42777 //<script type="text/javascript">
42780 * Ext JS Library 1.1.1
42781 * Copyright(c) 2006-2007, Ext JS, LLC.
42787 Roo.form.HtmlEditor = function(config){
42791 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42793 if (!this.toolbars) {
42794 this.toolbars = [];
42796 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42802 * @class Roo.form.HtmlEditor
42803 * @extends Roo.form.Field
42804 * Provides a lightweight HTML Editor component.
42806 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42808 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42809 * supported by this editor.</b><br/><br/>
42810 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42811 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42813 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42815 * @cfg {Boolean} clearUp
42819 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42824 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42829 * @cfg {Number} height (in pixels)
42833 * @cfg {Number} width (in pixels)
42838 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42841 stylesheets: false,
42845 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42850 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42856 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42861 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42869 // private properties
42870 validationEvent : false,
42872 initialized : false,
42875 onFocus : Roo.emptyFn,
42877 hideMode:'offsets',
42879 actionMode : 'container', // defaults to hiding it...
42881 defaultAutoCreate : { // modified by initCompnoent..
42883 style:"width:500px;height:300px;",
42884 autocomplete: "new-password"
42888 initComponent : function(){
42891 * @event initialize
42892 * Fires when the editor is fully initialized (including the iframe)
42893 * @param {HtmlEditor} this
42898 * Fires when the editor is first receives the focus. Any insertion must wait
42899 * until after this event.
42900 * @param {HtmlEditor} this
42904 * @event beforesync
42905 * Fires before the textarea is updated with content from the editor iframe. Return false
42906 * to cancel the sync.
42907 * @param {HtmlEditor} this
42908 * @param {String} html
42912 * @event beforepush
42913 * Fires before the iframe editor is updated with content from the textarea. Return false
42914 * to cancel the push.
42915 * @param {HtmlEditor} this
42916 * @param {String} html
42921 * Fires when the textarea is updated with content from the editor iframe.
42922 * @param {HtmlEditor} this
42923 * @param {String} html
42928 * Fires when the iframe editor is updated with content from the textarea.
42929 * @param {HtmlEditor} this
42930 * @param {String} html
42934 * @event editmodechange
42935 * Fires when the editor switches edit modes
42936 * @param {HtmlEditor} this
42937 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42939 editmodechange: true,
42941 * @event editorevent
42942 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42943 * @param {HtmlEditor} this
42947 * @event firstfocus
42948 * Fires when on first focus - needed by toolbars..
42949 * @param {HtmlEditor} this
42954 * Auto save the htmlEditor value as a file into Events
42955 * @param {HtmlEditor} this
42959 * @event savedpreview
42960 * preview the saved version of htmlEditor
42961 * @param {HtmlEditor} this
42963 savedpreview: true,
42966 * @event stylesheetsclick
42967 * Fires when press the Sytlesheets button
42968 * @param {Roo.HtmlEditorCore} this
42970 stylesheetsclick: true
42972 this.defaultAutoCreate = {
42974 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42975 autocomplete: "new-password"
42980 * Protected method that will not generally be called directly. It
42981 * is called when the editor creates its toolbar. Override this method if you need to
42982 * add custom toolbar buttons.
42983 * @param {HtmlEditor} editor
42985 createToolbar : function(editor){
42986 Roo.log("create toolbars");
42987 if (!editor.toolbars || !editor.toolbars.length) {
42988 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42991 for (var i =0 ; i < editor.toolbars.length;i++) {
42992 editor.toolbars[i] = Roo.factory(
42993 typeof(editor.toolbars[i]) == 'string' ?
42994 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42995 Roo.form.HtmlEditor);
42996 editor.toolbars[i].init(editor);
43004 onRender : function(ct, position)
43007 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43009 this.wrap = this.el.wrap({
43010 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43013 this.editorcore.onRender(ct, position);
43015 if (this.resizable) {
43016 this.resizeEl = new Roo.Resizable(this.wrap, {
43020 minHeight : this.height,
43021 height: this.height,
43022 handles : this.resizable,
43025 resize : function(r, w, h) {
43026 _t.onResize(w,h); // -something
43032 this.createToolbar(this);
43036 this.setSize(this.wrap.getSize());
43038 if (this.resizeEl) {
43039 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43040 // should trigger onReize..
43043 this.keyNav = new Roo.KeyNav(this.el, {
43045 "tab" : function(e){
43046 e.preventDefault();
43048 var value = this.getValue();
43050 var start = this.el.dom.selectionStart;
43051 var end = this.el.dom.selectionEnd;
43055 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43056 this.el.dom.setSelectionRange(end + 1, end + 1);
43060 var f = value.substring(0, start).split("\t");
43062 if(f.pop().length != 0){
43066 this.setValue(f.join("\t") + value.substring(end));
43067 this.el.dom.setSelectionRange(start - 1, start - 1);
43071 "home" : function(e){
43072 e.preventDefault();
43074 var curr = this.el.dom.selectionStart;
43075 var lines = this.getValue().split("\n");
43082 this.el.dom.setSelectionRange(0, 0);
43088 for (var i = 0; i < lines.length;i++) {
43089 pos += lines[i].length;
43099 pos -= lines[i].length;
43105 this.el.dom.setSelectionRange(pos, pos);
43109 this.el.dom.selectionStart = pos;
43110 this.el.dom.selectionEnd = curr;
43113 "end" : function(e){
43114 e.preventDefault();
43116 var curr = this.el.dom.selectionStart;
43117 var lines = this.getValue().split("\n");
43124 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43130 for (var i = 0; i < lines.length;i++) {
43132 pos += lines[i].length;
43146 this.el.dom.setSelectionRange(pos, pos);
43150 this.el.dom.selectionStart = curr;
43151 this.el.dom.selectionEnd = pos;
43156 doRelay : function(foo, bar, hname){
43157 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43163 // if(this.autosave && this.w){
43164 // this.autoSaveFn = setInterval(this.autosave, 1000);
43169 onResize : function(w, h)
43171 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43176 if(typeof w == 'number'){
43177 var aw = w - this.wrap.getFrameWidth('lr');
43178 this.el.setWidth(this.adjustWidth('textarea', aw));
43181 if(typeof h == 'number'){
43183 for (var i =0; i < this.toolbars.length;i++) {
43184 // fixme - ask toolbars for heights?
43185 tbh += this.toolbars[i].tb.el.getHeight();
43186 if (this.toolbars[i].footer) {
43187 tbh += this.toolbars[i].footer.el.getHeight();
43194 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43195 ah -= 5; // knock a few pixes off for look..
43197 this.el.setHeight(this.adjustWidth('textarea', ah));
43201 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43202 this.editorcore.onResize(ew,eh);
43207 * Toggles the editor between standard and source edit mode.
43208 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43210 toggleSourceEdit : function(sourceEditMode)
43212 this.editorcore.toggleSourceEdit(sourceEditMode);
43214 if(this.editorcore.sourceEditMode){
43215 Roo.log('editor - showing textarea');
43218 // Roo.log(this.syncValue());
43219 this.editorcore.syncValue();
43220 this.el.removeClass('x-hidden');
43221 this.el.dom.removeAttribute('tabIndex');
43224 for (var i = 0; i < this.toolbars.length; i++) {
43225 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43226 this.toolbars[i].tb.hide();
43227 this.toolbars[i].footer.hide();
43232 Roo.log('editor - hiding textarea');
43234 // Roo.log(this.pushValue());
43235 this.editorcore.pushValue();
43237 this.el.addClass('x-hidden');
43238 this.el.dom.setAttribute('tabIndex', -1);
43240 for (var i = 0; i < this.toolbars.length; i++) {
43241 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43242 this.toolbars[i].tb.show();
43243 this.toolbars[i].footer.show();
43247 //this.deferFocus();
43250 this.setSize(this.wrap.getSize());
43251 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43253 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43256 // private (for BoxComponent)
43257 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43259 // private (for BoxComponent)
43260 getResizeEl : function(){
43264 // private (for BoxComponent)
43265 getPositionEl : function(){
43270 initEvents : function(){
43271 this.originalValue = this.getValue();
43275 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43278 markInvalid : Roo.emptyFn,
43280 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43283 clearInvalid : Roo.emptyFn,
43285 setValue : function(v){
43286 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43287 this.editorcore.pushValue();
43292 deferFocus : function(){
43293 this.focus.defer(10, this);
43297 focus : function(){
43298 this.editorcore.focus();
43304 onDestroy : function(){
43310 for (var i =0; i < this.toolbars.length;i++) {
43311 // fixme - ask toolbars for heights?
43312 this.toolbars[i].onDestroy();
43315 this.wrap.dom.innerHTML = '';
43316 this.wrap.remove();
43321 onFirstFocus : function(){
43322 //Roo.log("onFirstFocus");
43323 this.editorcore.onFirstFocus();
43324 for (var i =0; i < this.toolbars.length;i++) {
43325 this.toolbars[i].onFirstFocus();
43331 syncValue : function()
43333 this.editorcore.syncValue();
43336 pushValue : function()
43338 this.editorcore.pushValue();
43341 setStylesheets : function(stylesheets)
43343 this.editorcore.setStylesheets(stylesheets);
43346 removeStylesheets : function()
43348 this.editorcore.removeStylesheets();
43352 // hide stuff that is not compatible
43366 * @event specialkey
43370 * @cfg {String} fieldClass @hide
43373 * @cfg {String} focusClass @hide
43376 * @cfg {String} autoCreate @hide
43379 * @cfg {String} inputType @hide
43382 * @cfg {String} invalidClass @hide
43385 * @cfg {String} invalidText @hide
43388 * @cfg {String} msgFx @hide
43391 * @cfg {String} validateOnBlur @hide
43395 // <script type="text/javascript">
43398 * Ext JS Library 1.1.1
43399 * Copyright(c) 2006-2007, Ext JS, LLC.
43405 * @class Roo.form.HtmlEditorToolbar1
43410 new Roo.form.HtmlEditor({
43413 new Roo.form.HtmlEditorToolbar1({
43414 disable : { fonts: 1 , format: 1, ..., ... , ...],
43420 * @cfg {Object} disable List of elements to disable..
43421 * @cfg {Array} btns List of additional buttons.
43425 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43428 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43431 Roo.apply(this, config);
43433 // default disabled, based on 'good practice'..
43434 this.disable = this.disable || {};
43435 Roo.applyIf(this.disable, {
43438 specialElements : true
43442 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43443 // dont call parent... till later.
43446 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43453 editorcore : false,
43455 * @cfg {Object} disable List of toolbar elements to disable
43462 * @cfg {String} createLinkText The default text for the create link prompt
43464 createLinkText : 'Please enter the URL for the link:',
43466 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43468 defaultLinkValue : 'http:/'+'/',
43472 * @cfg {Array} fontFamilies An array of available font families
43490 // "á" , ?? a acute?
43495 "°" // , // degrees
43497 // "é" , // e ecute
43498 // "ú" , // u ecute?
43501 specialElements : [
43503 text: "Insert Table",
43506 ihtml : '<table><tr><td>Cell</td></tr></table>'
43510 text: "Insert Image",
43513 ihtml : '<img src="about:blank"/>'
43522 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43523 "input:submit", "input:button", "select", "textarea", "label" ],
43526 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43528 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43536 * @cfg {String} defaultFont default font to use.
43538 defaultFont: 'tahoma',
43540 fontSelect : false,
43543 formatCombo : false,
43545 init : function(editor)
43547 this.editor = editor;
43548 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43549 var editorcore = this.editorcore;
43553 var fid = editorcore.frameId;
43555 function btn(id, toggle, handler){
43556 var xid = fid + '-'+ id ;
43560 cls : 'x-btn-icon x-edit-'+id,
43561 enableToggle:toggle !== false,
43562 scope: _t, // was editor...
43563 handler:handler||_t.relayBtnCmd,
43564 clickEvent:'mousedown',
43565 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43572 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43574 // stop form submits
43575 tb.el.on('click', function(e){
43576 e.preventDefault(); // what does this do?
43579 if(!this.disable.font) { // && !Roo.isSafari){
43580 /* why no safari for fonts
43581 editor.fontSelect = tb.el.createChild({
43584 cls:'x-font-select',
43585 html: this.createFontOptions()
43588 editor.fontSelect.on('change', function(){
43589 var font = editor.fontSelect.dom.value;
43590 editor.relayCmd('fontname', font);
43591 editor.deferFocus();
43595 editor.fontSelect.dom,
43601 if(!this.disable.formats){
43602 this.formatCombo = new Roo.form.ComboBox({
43603 store: new Roo.data.SimpleStore({
43606 data : this.formats // from states.js
43610 //autoCreate : {tag: "div", size: "20"},
43611 displayField:'tag',
43615 triggerAction: 'all',
43616 emptyText:'Add tag',
43617 selectOnFocus:true,
43620 'select': function(c, r, i) {
43621 editorcore.insertTag(r.get('tag'));
43627 tb.addField(this.formatCombo);
43631 if(!this.disable.format){
43638 if(!this.disable.fontSize){
43643 btn('increasefontsize', false, editorcore.adjustFont),
43644 btn('decreasefontsize', false, editorcore.adjustFont)
43649 if(!this.disable.colors){
43652 id:editorcore.frameId +'-forecolor',
43653 cls:'x-btn-icon x-edit-forecolor',
43654 clickEvent:'mousedown',
43655 tooltip: this.buttonTips['forecolor'] || undefined,
43657 menu : new Roo.menu.ColorMenu({
43658 allowReselect: true,
43659 focus: Roo.emptyFn,
43662 selectHandler: function(cp, color){
43663 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43664 editor.deferFocus();
43667 clickEvent:'mousedown'
43670 id:editorcore.frameId +'backcolor',
43671 cls:'x-btn-icon x-edit-backcolor',
43672 clickEvent:'mousedown',
43673 tooltip: this.buttonTips['backcolor'] || undefined,
43675 menu : new Roo.menu.ColorMenu({
43676 focus: Roo.emptyFn,
43679 allowReselect: true,
43680 selectHandler: function(cp, color){
43682 editorcore.execCmd('useCSS', false);
43683 editorcore.execCmd('hilitecolor', color);
43684 editorcore.execCmd('useCSS', true);
43685 editor.deferFocus();
43687 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43688 Roo.isSafari || Roo.isIE ? '#'+color : color);
43689 editor.deferFocus();
43693 clickEvent:'mousedown'
43698 // now add all the items...
43701 if(!this.disable.alignments){
43704 btn('justifyleft'),
43705 btn('justifycenter'),
43706 btn('justifyright')
43710 //if(!Roo.isSafari){
43711 if(!this.disable.links){
43714 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43718 if(!this.disable.lists){
43721 btn('insertorderedlist'),
43722 btn('insertunorderedlist')
43725 if(!this.disable.sourceEdit){
43728 btn('sourceedit', true, function(btn){
43729 this.toggleSourceEdit(btn.pressed);
43736 // special menu.. - needs to be tidied up..
43737 if (!this.disable.special) {
43740 cls: 'x-edit-none',
43746 for (var i =0; i < this.specialChars.length; i++) {
43747 smenu.menu.items.push({
43749 html: this.specialChars[i],
43750 handler: function(a,b) {
43751 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43752 //editor.insertAtCursor(a.html);
43766 if (!this.disable.cleanStyles) {
43768 cls: 'x-btn-icon x-btn-clear',
43774 for (var i =0; i < this.cleanStyles.length; i++) {
43775 cmenu.menu.items.push({
43776 actiontype : this.cleanStyles[i],
43777 html: 'Remove ' + this.cleanStyles[i],
43778 handler: function(a,b) {
43781 var c = Roo.get(editorcore.doc.body);
43782 c.select('[style]').each(function(s) {
43783 s.dom.style.removeProperty(a.actiontype);
43785 editorcore.syncValue();
43790 cmenu.menu.items.push({
43791 actiontype : 'tablewidths',
43792 html: 'Remove Table Widths',
43793 handler: function(a,b) {
43794 editorcore.cleanTableWidths();
43795 editorcore.syncValue();
43799 cmenu.menu.items.push({
43800 actiontype : 'word',
43801 html: 'Remove MS Word Formating',
43802 handler: function(a,b) {
43803 editorcore.cleanWord();
43804 editorcore.syncValue();
43809 cmenu.menu.items.push({
43810 actiontype : 'all',
43811 html: 'Remove All Styles',
43812 handler: function(a,b) {
43814 var c = Roo.get(editorcore.doc.body);
43815 c.select('[style]').each(function(s) {
43816 s.dom.removeAttribute('style');
43818 editorcore.syncValue();
43823 cmenu.menu.items.push({
43824 actiontype : 'all',
43825 html: 'Remove All CSS Classes',
43826 handler: function(a,b) {
43828 var c = Roo.get(editorcore.doc.body);
43829 c.select('[class]').each(function(s) {
43830 s.dom.className = '';
43832 editorcore.syncValue();
43837 cmenu.menu.items.push({
43838 actiontype : 'tidy',
43839 html: 'Tidy HTML Source',
43840 handler: function(a,b) {
43841 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43842 editorcore.syncValue();
43851 if (!this.disable.specialElements) {
43854 cls: 'x-edit-none',
43859 for (var i =0; i < this.specialElements.length; i++) {
43860 semenu.menu.items.push(
43862 handler: function(a,b) {
43863 editor.insertAtCursor(this.ihtml);
43865 }, this.specialElements[i])
43877 for(var i =0; i< this.btns.length;i++) {
43878 var b = Roo.factory(this.btns[i],Roo.form);
43879 b.cls = 'x-edit-none';
43881 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43882 b.cls += ' x-init-enable';
43885 b.scope = editorcore;
43893 // disable everything...
43895 this.tb.items.each(function(item){
43898 item.id != editorcore.frameId+ '-sourceedit' &&
43899 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43905 this.rendered = true;
43907 // the all the btns;
43908 editor.on('editorevent', this.updateToolbar, this);
43909 // other toolbars need to implement this..
43910 //editor.on('editmodechange', this.updateToolbar, this);
43914 relayBtnCmd : function(btn) {
43915 this.editorcore.relayCmd(btn.cmd);
43917 // private used internally
43918 createLink : function(){
43919 Roo.log("create link?");
43920 var url = prompt(this.createLinkText, this.defaultLinkValue);
43921 if(url && url != 'http:/'+'/'){
43922 this.editorcore.relayCmd('createlink', url);
43928 * Protected method that will not generally be called directly. It triggers
43929 * a toolbar update by reading the markup state of the current selection in the editor.
43931 updateToolbar: function(){
43933 if(!this.editorcore.activated){
43934 this.editor.onFirstFocus();
43938 var btns = this.tb.items.map,
43939 doc = this.editorcore.doc,
43940 frameId = this.editorcore.frameId;
43942 if(!this.disable.font && !Roo.isSafari){
43944 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43945 if(name != this.fontSelect.dom.value){
43946 this.fontSelect.dom.value = name;
43950 if(!this.disable.format){
43951 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43952 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43953 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43955 if(!this.disable.alignments){
43956 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43957 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43958 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43960 if(!Roo.isSafari && !this.disable.lists){
43961 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43962 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43965 var ans = this.editorcore.getAllAncestors();
43966 if (this.formatCombo) {
43969 var store = this.formatCombo.store;
43970 this.formatCombo.setValue("");
43971 for (var i =0; i < ans.length;i++) {
43972 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43974 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43982 // hides menus... - so this cant be on a menu...
43983 Roo.menu.MenuMgr.hideAll();
43985 //this.editorsyncValue();
43989 createFontOptions : function(){
43990 var buf = [], fs = this.fontFamilies, ff, lc;
43994 for(var i = 0, len = fs.length; i< len; i++){
43996 lc = ff.toLowerCase();
43998 '<option value="',lc,'" style="font-family:',ff,';"',
43999 (this.defaultFont == lc ? ' selected="true">' : '>'),
44004 return buf.join('');
44007 toggleSourceEdit : function(sourceEditMode){
44009 Roo.log("toolbar toogle");
44010 if(sourceEditMode === undefined){
44011 sourceEditMode = !this.sourceEditMode;
44013 this.sourceEditMode = sourceEditMode === true;
44014 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
44015 // just toggle the button?
44016 if(btn.pressed !== this.sourceEditMode){
44017 btn.toggle(this.sourceEditMode);
44021 if(sourceEditMode){
44022 Roo.log("disabling buttons");
44023 this.tb.items.each(function(item){
44024 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44030 Roo.log("enabling buttons");
44031 if(this.editorcore.initialized){
44032 this.tb.items.each(function(item){
44038 Roo.log("calling toggole on editor");
44039 // tell the editor that it's been pressed..
44040 this.editor.toggleSourceEdit(sourceEditMode);
44044 * Object collection of toolbar tooltips for the buttons in the editor. The key
44045 * is the command id associated with that button and the value is a valid QuickTips object.
44050 title: 'Bold (Ctrl+B)',
44051 text: 'Make the selected text bold.',
44052 cls: 'x-html-editor-tip'
44055 title: 'Italic (Ctrl+I)',
44056 text: 'Make the selected text italic.',
44057 cls: 'x-html-editor-tip'
44065 title: 'Bold (Ctrl+B)',
44066 text: 'Make the selected text bold.',
44067 cls: 'x-html-editor-tip'
44070 title: 'Italic (Ctrl+I)',
44071 text: 'Make the selected text italic.',
44072 cls: 'x-html-editor-tip'
44075 title: 'Underline (Ctrl+U)',
44076 text: 'Underline the selected text.',
44077 cls: 'x-html-editor-tip'
44079 increasefontsize : {
44080 title: 'Grow Text',
44081 text: 'Increase the font size.',
44082 cls: 'x-html-editor-tip'
44084 decreasefontsize : {
44085 title: 'Shrink Text',
44086 text: 'Decrease the font size.',
44087 cls: 'x-html-editor-tip'
44090 title: 'Text Highlight Color',
44091 text: 'Change the background color of the selected text.',
44092 cls: 'x-html-editor-tip'
44095 title: 'Font Color',
44096 text: 'Change the color of the selected text.',
44097 cls: 'x-html-editor-tip'
44100 title: 'Align Text Left',
44101 text: 'Align text to the left.',
44102 cls: 'x-html-editor-tip'
44105 title: 'Center Text',
44106 text: 'Center text in the editor.',
44107 cls: 'x-html-editor-tip'
44110 title: 'Align Text Right',
44111 text: 'Align text to the right.',
44112 cls: 'x-html-editor-tip'
44114 insertunorderedlist : {
44115 title: 'Bullet List',
44116 text: 'Start a bulleted list.',
44117 cls: 'x-html-editor-tip'
44119 insertorderedlist : {
44120 title: 'Numbered List',
44121 text: 'Start a numbered list.',
44122 cls: 'x-html-editor-tip'
44125 title: 'Hyperlink',
44126 text: 'Make the selected text a hyperlink.',
44127 cls: 'x-html-editor-tip'
44130 title: 'Source Edit',
44131 text: 'Switch to source editing mode.',
44132 cls: 'x-html-editor-tip'
44136 onDestroy : function(){
44139 this.tb.items.each(function(item){
44141 item.menu.removeAll();
44143 item.menu.el.destroy();
44151 onFirstFocus: function() {
44152 this.tb.items.each(function(item){
44161 // <script type="text/javascript">
44164 * Ext JS Library 1.1.1
44165 * Copyright(c) 2006-2007, Ext JS, LLC.
44172 * @class Roo.form.HtmlEditor.ToolbarContext
44177 new Roo.form.HtmlEditor({
44180 { xtype: 'ToolbarStandard', styles : {} }
44181 { xtype: 'ToolbarContext', disable : {} }
44187 * @config : {Object} disable List of elements to disable.. (not done yet.)
44188 * @config : {Object} styles Map of styles available.
44192 Roo.form.HtmlEditor.ToolbarContext = function(config)
44195 Roo.apply(this, config);
44196 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44197 // dont call parent... till later.
44198 this.styles = this.styles || {};
44203 Roo.form.HtmlEditor.ToolbarContext.types = {
44215 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44281 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44286 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44296 style : 'fontFamily',
44297 displayField: 'display',
44298 optname : 'font-family',
44347 // should we really allow this??
44348 // should this just be
44359 style : 'fontFamily',
44360 displayField: 'display',
44361 optname : 'font-family',
44368 style : 'fontFamily',
44369 displayField: 'display',
44370 optname : 'font-family',
44377 style : 'fontFamily',
44378 displayField: 'display',
44379 optname : 'font-family',
44390 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44391 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44393 Roo.form.HtmlEditor.ToolbarContext.options = {
44395 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44396 [ 'Courier New', 'Courier New'],
44397 [ 'Tahoma', 'Tahoma'],
44398 [ 'Times New Roman,serif', 'Times'],
44399 [ 'Verdana','Verdana' ]
44403 // fixme - these need to be configurable..
44406 //Roo.form.HtmlEditor.ToolbarContext.types
44409 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44416 editorcore : false,
44418 * @cfg {Object} disable List of toolbar elements to disable
44423 * @cfg {Object} styles List of styles
44424 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44426 * These must be defined in the page, so they get rendered correctly..
44437 init : function(editor)
44439 this.editor = editor;
44440 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44441 var editorcore = this.editorcore;
44443 var fid = editorcore.frameId;
44445 function btn(id, toggle, handler){
44446 var xid = fid + '-'+ id ;
44450 cls : 'x-btn-icon x-edit-'+id,
44451 enableToggle:toggle !== false,
44452 scope: editorcore, // was editor...
44453 handler:handler||editorcore.relayBtnCmd,
44454 clickEvent:'mousedown',
44455 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44459 // create a new element.
44460 var wdiv = editor.wrap.createChild({
44462 }, editor.wrap.dom.firstChild.nextSibling, true);
44464 // can we do this more than once??
44466 // stop form submits
44469 // disable everything...
44470 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44471 this.toolbars = {};
44473 for (var i in ty) {
44475 this.toolbars[i] = this.buildToolbar(ty[i],i);
44477 this.tb = this.toolbars.BODY;
44479 this.buildFooter();
44480 this.footer.show();
44481 editor.on('hide', function( ) { this.footer.hide() }, this);
44482 editor.on('show', function( ) { this.footer.show() }, this);
44485 this.rendered = true;
44487 // the all the btns;
44488 editor.on('editorevent', this.updateToolbar, this);
44489 // other toolbars need to implement this..
44490 //editor.on('editmodechange', this.updateToolbar, this);
44496 * Protected method that will not generally be called directly. It triggers
44497 * a toolbar update by reading the markup state of the current selection in the editor.
44499 * Note you can force an update by calling on('editorevent', scope, false)
44501 updateToolbar: function(editor,ev,sel){
44504 // capture mouse up - this is handy for selecting images..
44505 // perhaps should go somewhere else...
44506 if(!this.editorcore.activated){
44507 this.editor.onFirstFocus();
44513 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44514 // selectNode - might want to handle IE?
44516 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44517 ev.target && ev.target.tagName == 'IMG') {
44518 // they have click on an image...
44519 // let's see if we can change the selection...
44522 var nodeRange = sel.ownerDocument.createRange();
44524 nodeRange.selectNode(sel);
44526 nodeRange.selectNodeContents(sel);
44528 //nodeRange.collapse(true);
44529 var s = this.editorcore.win.getSelection();
44530 s.removeAllRanges();
44531 s.addRange(nodeRange);
44535 var updateFooter = sel ? false : true;
44538 var ans = this.editorcore.getAllAncestors();
44541 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44544 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44545 sel = sel ? sel : this.editorcore.doc.body;
44546 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44549 // pick a menu that exists..
44550 var tn = sel.tagName.toUpperCase();
44551 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44553 tn = sel.tagName.toUpperCase();
44555 var lastSel = this.tb.selectedNode;
44557 this.tb.selectedNode = sel;
44559 // if current menu does not match..
44561 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44564 ///console.log("show: " + tn);
44565 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44568 this.tb.items.first().el.innerHTML = tn + ': ';
44571 // update attributes
44572 if (this.tb.fields) {
44573 this.tb.fields.each(function(e) {
44575 e.setValue(sel.style[e.stylename]);
44578 e.setValue(sel.getAttribute(e.attrname));
44582 var hasStyles = false;
44583 for(var i in this.styles) {
44590 var st = this.tb.fields.item(0);
44592 st.store.removeAll();
44595 var cn = sel.className.split(/\s+/);
44598 if (this.styles['*']) {
44600 Roo.each(this.styles['*'], function(v) {
44601 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44604 if (this.styles[tn]) {
44605 Roo.each(this.styles[tn], function(v) {
44606 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44610 st.store.loadData(avs);
44614 // flag our selected Node.
44615 this.tb.selectedNode = sel;
44618 Roo.menu.MenuMgr.hideAll();
44622 if (!updateFooter) {
44623 //this.footDisp.dom.innerHTML = '';
44626 // update the footer
44630 this.footerEls = ans.reverse();
44631 Roo.each(this.footerEls, function(a,i) {
44632 if (!a) { return; }
44633 html += html.length ? ' > ' : '';
44635 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44640 var sz = this.footDisp.up('td').getSize();
44641 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44642 this.footDisp.dom.style.marginLeft = '5px';
44644 this.footDisp.dom.style.overflow = 'hidden';
44646 this.footDisp.dom.innerHTML = html;
44648 //this.editorsyncValue();
44655 onDestroy : function(){
44658 this.tb.items.each(function(item){
44660 item.menu.removeAll();
44662 item.menu.el.destroy();
44670 onFirstFocus: function() {
44671 // need to do this for all the toolbars..
44672 this.tb.items.each(function(item){
44676 buildToolbar: function(tlist, nm)
44678 var editor = this.editor;
44679 var editorcore = this.editorcore;
44680 // create a new element.
44681 var wdiv = editor.wrap.createChild({
44683 }, editor.wrap.dom.firstChild.nextSibling, true);
44686 var tb = new Roo.Toolbar(wdiv);
44689 tb.add(nm+ ": ");
44692 for(var i in this.styles) {
44697 if (styles && styles.length) {
44699 // this needs a multi-select checkbox...
44700 tb.addField( new Roo.form.ComboBox({
44701 store: new Roo.data.SimpleStore({
44703 fields: ['val', 'selected'],
44706 name : '-roo-edit-className',
44707 attrname : 'className',
44708 displayField: 'val',
44712 triggerAction: 'all',
44713 emptyText:'Select Style',
44714 selectOnFocus:true,
44717 'select': function(c, r, i) {
44718 // initial support only for on class per el..
44719 tb.selectedNode.className = r ? r.get('val') : '';
44720 editorcore.syncValue();
44727 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44728 var tbops = tbc.options;
44730 for (var i in tlist) {
44732 var item = tlist[i];
44733 tb.add(item.title + ": ");
44736 //optname == used so you can configure the options available..
44737 var opts = item.opts ? item.opts : false;
44738 if (item.optname) {
44739 opts = tbops[item.optname];
44744 // opts == pulldown..
44745 tb.addField( new Roo.form.ComboBox({
44746 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44748 fields: ['val', 'display'],
44751 name : '-roo-edit-' + i,
44753 stylename : item.style ? item.style : false,
44754 displayField: item.displayField ? item.displayField : 'val',
44755 valueField : 'val',
44757 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44759 triggerAction: 'all',
44760 emptyText:'Select',
44761 selectOnFocus:true,
44762 width: item.width ? item.width : 130,
44764 'select': function(c, r, i) {
44766 tb.selectedNode.style[c.stylename] = r.get('val');
44769 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44778 tb.addField( new Roo.form.TextField({
44781 //allowBlank:false,
44786 tb.addField( new Roo.form.TextField({
44787 name: '-roo-edit-' + i,
44794 'change' : function(f, nv, ov) {
44795 tb.selectedNode.setAttribute(f.attrname, nv);
44808 text: 'Stylesheets',
44811 click : function ()
44813 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44821 text: 'Remove Tag',
44824 click : function ()
44827 // undo does not work.
44829 var sn = tb.selectedNode;
44831 var pn = sn.parentNode;
44833 var stn = sn.childNodes[0];
44834 var en = sn.childNodes[sn.childNodes.length - 1 ];
44835 while (sn.childNodes.length) {
44836 var node = sn.childNodes[0];
44837 sn.removeChild(node);
44839 pn.insertBefore(node, sn);
44842 pn.removeChild(sn);
44843 var range = editorcore.createRange();
44845 range.setStart(stn,0);
44846 range.setEnd(en,0); //????
44847 //range.selectNode(sel);
44850 var selection = editorcore.getSelection();
44851 selection.removeAllRanges();
44852 selection.addRange(range);
44856 //_this.updateToolbar(null, null, pn);
44857 _this.updateToolbar(null, null, null);
44858 _this.footDisp.dom.innerHTML = '';
44868 tb.el.on('click', function(e){
44869 e.preventDefault(); // what does this do?
44871 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44874 // dont need to disable them... as they will get hidden
44879 buildFooter : function()
44882 var fel = this.editor.wrap.createChild();
44883 this.footer = new Roo.Toolbar(fel);
44884 // toolbar has scrolly on left / right?
44885 var footDisp= new Roo.Toolbar.Fill();
44891 handler : function() {
44892 _t.footDisp.scrollTo('left',0,true)
44896 this.footer.add( footDisp );
44901 handler : function() {
44903 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44907 var fel = Roo.get(footDisp.el);
44908 fel.addClass('x-editor-context');
44909 this.footDispWrap = fel;
44910 this.footDispWrap.overflow = 'hidden';
44912 this.footDisp = fel.createChild();
44913 this.footDispWrap.on('click', this.onContextClick, this)
44917 onContextClick : function (ev,dom)
44919 ev.preventDefault();
44920 var cn = dom.className;
44922 if (!cn.match(/x-ed-loc-/)) {
44925 var n = cn.split('-').pop();
44926 var ans = this.footerEls;
44930 var range = this.editorcore.createRange();
44932 range.selectNodeContents(sel);
44933 //range.selectNode(sel);
44936 var selection = this.editorcore.getSelection();
44937 selection.removeAllRanges();
44938 selection.addRange(range);
44942 this.updateToolbar(null, null, sel);
44959 * Ext JS Library 1.1.1
44960 * Copyright(c) 2006-2007, Ext JS, LLC.
44962 * Originally Released Under LGPL - original licence link has changed is not relivant.
44965 * <script type="text/javascript">
44969 * @class Roo.form.BasicForm
44970 * @extends Roo.util.Observable
44971 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44973 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44974 * @param {Object} config Configuration options
44976 Roo.form.BasicForm = function(el, config){
44977 this.allItems = [];
44978 this.childForms = [];
44979 Roo.apply(this, config);
44981 * The Roo.form.Field items in this form.
44982 * @type MixedCollection
44986 this.items = new Roo.util.MixedCollection(false, function(o){
44987 return o.id || (o.id = Roo.id());
44991 * @event beforeaction
44992 * Fires before any action is performed. Return false to cancel the action.
44993 * @param {Form} this
44994 * @param {Action} action The action to be performed
44996 beforeaction: true,
44998 * @event actionfailed
44999 * Fires when an action fails.
45000 * @param {Form} this
45001 * @param {Action} action The action that failed
45003 actionfailed : true,
45005 * @event actioncomplete
45006 * Fires when an action is completed.
45007 * @param {Form} this
45008 * @param {Action} action The action that completed
45010 actioncomplete : true
45015 Roo.form.BasicForm.superclass.constructor.call(this);
45018 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
45020 * @cfg {String} method
45021 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45024 * @cfg {DataReader} reader
45025 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45026 * This is optional as there is built-in support for processing JSON.
45029 * @cfg {DataReader} errorReader
45030 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45031 * This is completely optional as there is built-in support for processing JSON.
45034 * @cfg {String} url
45035 * The URL to use for form actions if one isn't supplied in the action options.
45038 * @cfg {Boolean} fileUpload
45039 * Set to true if this form is a file upload.
45043 * @cfg {Object} baseParams
45044 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45049 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45054 activeAction : null,
45057 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45058 * or setValues() data instead of when the form was first created.
45060 trackResetOnLoad : false,
45064 * childForms - used for multi-tab forms
45067 childForms : false,
45070 * allItems - full list of fields.
45076 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45077 * element by passing it or its id or mask the form itself by passing in true.
45080 waitMsgTarget : false,
45083 initEl : function(el){
45084 this.el = Roo.get(el);
45085 this.id = this.el.id || Roo.id();
45086 this.el.on('submit', this.onSubmit, this);
45087 this.el.addClass('x-form');
45091 onSubmit : function(e){
45096 * Returns true if client-side validation on the form is successful.
45099 isValid : function(){
45101 this.items.each(function(f){
45110 * Returns true if any fields in this form have changed since their original load.
45113 isDirty : function(){
45115 this.items.each(function(f){
45125 * Performs a predefined action (submit or load) or custom actions you define on this form.
45126 * @param {String} actionName The name of the action type
45127 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45128 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45129 * accept other config options):
45131 Property Type Description
45132 ---------------- --------------- ----------------------------------------------------------------------------------
45133 url String The url for the action (defaults to the form's url)
45134 method String The form method to use (defaults to the form's method, or POST if not defined)
45135 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45136 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45137 validate the form on the client (defaults to false)
45139 * @return {BasicForm} this
45141 doAction : function(action, options){
45142 if(typeof action == 'string'){
45143 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45145 if(this.fireEvent('beforeaction', this, action) !== false){
45146 this.beforeAction(action);
45147 action.run.defer(100, action);
45153 * Shortcut to do a submit action.
45154 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45155 * @return {BasicForm} this
45157 submit : function(options){
45158 this.doAction('submit', options);
45163 * Shortcut to do a load action.
45164 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45165 * @return {BasicForm} this
45167 load : function(options){
45168 this.doAction('load', options);
45173 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45174 * @param {Record} record The record to edit
45175 * @return {BasicForm} this
45177 updateRecord : function(record){
45178 record.beginEdit();
45179 var fs = record.fields;
45180 fs.each(function(f){
45181 var field = this.findField(f.name);
45183 record.set(f.name, field.getValue());
45191 * Loads an Roo.data.Record into this form.
45192 * @param {Record} record The record to load
45193 * @return {BasicForm} this
45195 loadRecord : function(record){
45196 this.setValues(record.data);
45201 beforeAction : function(action){
45202 var o = action.options;
45205 if(this.waitMsgTarget === true){
45206 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45207 }else if(this.waitMsgTarget){
45208 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45209 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45211 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45217 afterAction : function(action, success){
45218 this.activeAction = null;
45219 var o = action.options;
45221 if(this.waitMsgTarget === true){
45223 }else if(this.waitMsgTarget){
45224 this.waitMsgTarget.unmask();
45226 Roo.MessageBox.updateProgress(1);
45227 Roo.MessageBox.hide();
45234 Roo.callback(o.success, o.scope, [this, action]);
45235 this.fireEvent('actioncomplete', this, action);
45239 // failure condition..
45240 // we have a scenario where updates need confirming.
45241 // eg. if a locking scenario exists..
45242 // we look for { errors : { needs_confirm : true }} in the response.
45244 (typeof(action.result) != 'undefined') &&
45245 (typeof(action.result.errors) != 'undefined') &&
45246 (typeof(action.result.errors.needs_confirm) != 'undefined')
45249 Roo.MessageBox.confirm(
45250 "Change requires confirmation",
45251 action.result.errorMsg,
45256 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45266 Roo.callback(o.failure, o.scope, [this, action]);
45267 // show an error message if no failed handler is set..
45268 if (!this.hasListener('actionfailed')) {
45269 Roo.MessageBox.alert("Error",
45270 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45271 action.result.errorMsg :
45272 "Saving Failed, please check your entries or try again"
45276 this.fireEvent('actionfailed', this, action);
45282 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45283 * @param {String} id The value to search for
45286 findField : function(id){
45287 var field = this.items.get(id);
45289 this.items.each(function(f){
45290 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45296 return field || null;
45300 * Add a secondary form to this one,
45301 * Used to provide tabbed forms. One form is primary, with hidden values
45302 * which mirror the elements from the other forms.
45304 * @param {Roo.form.Form} form to add.
45307 addForm : function(form)
45310 if (this.childForms.indexOf(form) > -1) {
45314 this.childForms.push(form);
45316 Roo.each(form.allItems, function (fe) {
45318 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45319 if (this.findField(n)) { // already added..
45322 var add = new Roo.form.Hidden({
45325 add.render(this.el);
45332 * Mark fields in this form invalid in bulk.
45333 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45334 * @return {BasicForm} this
45336 markInvalid : function(errors){
45337 if(errors instanceof Array){
45338 for(var i = 0, len = errors.length; i < len; i++){
45339 var fieldError = errors[i];
45340 var f = this.findField(fieldError.id);
45342 f.markInvalid(fieldError.msg);
45348 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45349 field.markInvalid(errors[id]);
45353 Roo.each(this.childForms || [], function (f) {
45354 f.markInvalid(errors);
45361 * Set values for fields in this form in bulk.
45362 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45363 * @return {BasicForm} this
45365 setValues : function(values){
45366 if(values instanceof Array){ // array of objects
45367 for(var i = 0, len = values.length; i < len; i++){
45369 var f = this.findField(v.id);
45371 f.setValue(v.value);
45372 if(this.trackResetOnLoad){
45373 f.originalValue = f.getValue();
45377 }else{ // object hash
45380 if(typeof values[id] != 'function' && (field = this.findField(id))){
45382 if (field.setFromData &&
45383 field.valueField &&
45384 field.displayField &&
45385 // combos' with local stores can
45386 // be queried via setValue()
45387 // to set their value..
45388 (field.store && !field.store.isLocal)
45392 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45393 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45394 field.setFromData(sd);
45397 field.setValue(values[id]);
45401 if(this.trackResetOnLoad){
45402 field.originalValue = field.getValue();
45408 Roo.each(this.childForms || [], function (f) {
45409 f.setValues(values);
45416 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45417 * they are returned as an array.
45418 * @param {Boolean} asString
45421 getValues : function(asString){
45422 if (this.childForms) {
45423 // copy values from the child forms
45424 Roo.each(this.childForms, function (f) {
45425 this.setValues(f.getValues());
45431 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45432 if(asString === true){
45435 return Roo.urlDecode(fs);
45439 * Returns the fields in this form as an object with key/value pairs.
45440 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45443 getFieldValues : function(with_hidden)
45445 if (this.childForms) {
45446 // copy values from the child forms
45447 // should this call getFieldValues - probably not as we do not currently copy
45448 // hidden fields when we generate..
45449 Roo.each(this.childForms, function (f) {
45450 this.setValues(f.getValues());
45455 this.items.each(function(f){
45456 if (!f.getName()) {
45459 var v = f.getValue();
45460 if (f.inputType =='radio') {
45461 if (typeof(ret[f.getName()]) == 'undefined') {
45462 ret[f.getName()] = ''; // empty..
45465 if (!f.el.dom.checked) {
45469 v = f.el.dom.value;
45473 // not sure if this supported any more..
45474 if ((typeof(v) == 'object') && f.getRawValue) {
45475 v = f.getRawValue() ; // dates..
45477 // combo boxes where name != hiddenName...
45478 if (f.name != f.getName()) {
45479 ret[f.name] = f.getRawValue();
45481 ret[f.getName()] = v;
45488 * Clears all invalid messages in this form.
45489 * @return {BasicForm} this
45491 clearInvalid : function(){
45492 this.items.each(function(f){
45496 Roo.each(this.childForms || [], function (f) {
45505 * Resets this form.
45506 * @return {BasicForm} this
45508 reset : function(){
45509 this.items.each(function(f){
45513 Roo.each(this.childForms || [], function (f) {
45522 * Add Roo.form components to this form.
45523 * @param {Field} field1
45524 * @param {Field} field2 (optional)
45525 * @param {Field} etc (optional)
45526 * @return {BasicForm} this
45529 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45535 * Removes a field from the items collection (does NOT remove its markup).
45536 * @param {Field} field
45537 * @return {BasicForm} this
45539 remove : function(field){
45540 this.items.remove(field);
45545 * Looks at the fields in this form, checks them for an id attribute,
45546 * and calls applyTo on the existing dom element with that id.
45547 * @return {BasicForm} this
45549 render : function(){
45550 this.items.each(function(f){
45551 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45559 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45560 * @param {Object} values
45561 * @return {BasicForm} this
45563 applyToFields : function(o){
45564 this.items.each(function(f){
45571 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45572 * @param {Object} values
45573 * @return {BasicForm} this
45575 applyIfToFields : function(o){
45576 this.items.each(function(f){
45584 Roo.BasicForm = Roo.form.BasicForm;/*
45586 * Ext JS Library 1.1.1
45587 * Copyright(c) 2006-2007, Ext JS, LLC.
45589 * Originally Released Under LGPL - original licence link has changed is not relivant.
45592 * <script type="text/javascript">
45596 * @class Roo.form.Form
45597 * @extends Roo.form.BasicForm
45598 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45600 * @param {Object} config Configuration options
45602 Roo.form.Form = function(config){
45604 if (config.items) {
45605 xitems = config.items;
45606 delete config.items;
45610 Roo.form.Form.superclass.constructor.call(this, null, config);
45611 this.url = this.url || this.action;
45613 this.root = new Roo.form.Layout(Roo.applyIf({
45617 this.active = this.root;
45619 * Array of all the buttons that have been added to this form via {@link addButton}
45623 this.allItems = [];
45626 * @event clientvalidation
45627 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45628 * @param {Form} this
45629 * @param {Boolean} valid true if the form has passed client-side validation
45631 clientvalidation: true,
45634 * Fires when the form is rendered
45635 * @param {Roo.form.Form} form
45640 if (this.progressUrl) {
45641 // push a hidden field onto the list of fields..
45645 name : 'UPLOAD_IDENTIFIER'
45650 Roo.each(xitems, this.addxtype, this);
45656 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45658 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45661 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45664 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45666 buttonAlign:'center',
45669 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45674 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45675 * This property cascades to child containers if not set.
45680 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45681 * fires a looping event with that state. This is required to bind buttons to the valid
45682 * state using the config value formBind:true on the button.
45684 monitorValid : false,
45687 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45692 * @cfg {String} progressUrl - Url to return progress data
45695 progressUrl : false,
45698 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45699 * fields are added and the column is closed. If no fields are passed the column remains open
45700 * until end() is called.
45701 * @param {Object} config The config to pass to the column
45702 * @param {Field} field1 (optional)
45703 * @param {Field} field2 (optional)
45704 * @param {Field} etc (optional)
45705 * @return Column The column container object
45707 column : function(c){
45708 var col = new Roo.form.Column(c);
45710 if(arguments.length > 1){ // duplicate code required because of Opera
45711 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45718 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45719 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45720 * until end() is called.
45721 * @param {Object} config The config to pass to the fieldset
45722 * @param {Field} field1 (optional)
45723 * @param {Field} field2 (optional)
45724 * @param {Field} etc (optional)
45725 * @return FieldSet The fieldset container object
45727 fieldset : function(c){
45728 var fs = new Roo.form.FieldSet(c);
45730 if(arguments.length > 1){ // duplicate code required because of Opera
45731 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45738 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45739 * fields are added and the container is closed. If no fields are passed the container remains open
45740 * until end() is called.
45741 * @param {Object} config The config to pass to the Layout
45742 * @param {Field} field1 (optional)
45743 * @param {Field} field2 (optional)
45744 * @param {Field} etc (optional)
45745 * @return Layout The container object
45747 container : function(c){
45748 var l = new Roo.form.Layout(c);
45750 if(arguments.length > 1){ // duplicate code required because of Opera
45751 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45758 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45759 * @param {Object} container A Roo.form.Layout or subclass of Layout
45760 * @return {Form} this
45762 start : function(c){
45763 // cascade label info
45764 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45765 this.active.stack.push(c);
45766 c.ownerCt = this.active;
45772 * Closes the current open container
45773 * @return {Form} this
45776 if(this.active == this.root){
45779 this.active = this.active.ownerCt;
45784 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45785 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45786 * as the label of the field.
45787 * @param {Field} field1
45788 * @param {Field} field2 (optional)
45789 * @param {Field} etc. (optional)
45790 * @return {Form} this
45793 this.active.stack.push.apply(this.active.stack, arguments);
45794 this.allItems.push.apply(this.allItems,arguments);
45796 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45797 if(a[i].isFormField){
45802 Roo.form.Form.superclass.add.apply(this, r);
45812 * Find any element that has been added to a form, using it's ID or name
45813 * This can include framesets, columns etc. along with regular fields..
45814 * @param {String} id - id or name to find.
45816 * @return {Element} e - or false if nothing found.
45818 findbyId : function(id)
45824 Roo.each(this.allItems, function(f){
45825 if (f.id == id || f.name == id ){
45836 * Render this form into the passed container. This should only be called once!
45837 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45838 * @return {Form} this
45840 render : function(ct)
45846 var o = this.autoCreate || {
45848 method : this.method || 'POST',
45849 id : this.id || Roo.id()
45851 this.initEl(ct.createChild(o));
45853 this.root.render(this.el);
45857 this.items.each(function(f){
45858 f.render('x-form-el-'+f.id);
45861 if(this.buttons.length > 0){
45862 // tables are required to maintain order and for correct IE layout
45863 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45864 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45865 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45867 var tr = tb.getElementsByTagName('tr')[0];
45868 for(var i = 0, len = this.buttons.length; i < len; i++) {
45869 var b = this.buttons[i];
45870 var td = document.createElement('td');
45871 td.className = 'x-form-btn-td';
45872 b.render(tr.appendChild(td));
45875 if(this.monitorValid){ // initialize after render
45876 this.startMonitoring();
45878 this.fireEvent('rendered', this);
45883 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45884 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45885 * object or a valid Roo.DomHelper element config
45886 * @param {Function} handler The function called when the button is clicked
45887 * @param {Object} scope (optional) The scope of the handler function
45888 * @return {Roo.Button}
45890 addButton : function(config, handler, scope){
45894 minWidth: this.minButtonWidth,
45897 if(typeof config == "string"){
45900 Roo.apply(bc, config);
45902 var btn = new Roo.Button(null, bc);
45903 this.buttons.push(btn);
45908 * Adds a series of form elements (using the xtype property as the factory method.
45909 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45910 * @param {Object} config
45913 addxtype : function()
45915 var ar = Array.prototype.slice.call(arguments, 0);
45917 for(var i = 0; i < ar.length; i++) {
45919 continue; // skip -- if this happends something invalid got sent, we
45920 // should ignore it, as basically that interface element will not show up
45921 // and that should be pretty obvious!!
45924 if (Roo.form[ar[i].xtype]) {
45926 var fe = Roo.factory(ar[i], Roo.form);
45932 fe.store.form = this;
45937 this.allItems.push(fe);
45938 if (fe.items && fe.addxtype) {
45939 fe.addxtype.apply(fe, fe.items);
45949 // console.log('adding ' + ar[i].xtype);
45951 if (ar[i].xtype == 'Button') {
45952 //console.log('adding button');
45953 //console.log(ar[i]);
45954 this.addButton(ar[i]);
45955 this.allItems.push(fe);
45959 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45960 alert('end is not supported on xtype any more, use items');
45962 // //console.log('adding end');
45970 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45971 * option "monitorValid"
45973 startMonitoring : function(){
45976 Roo.TaskMgr.start({
45977 run : this.bindHandler,
45978 interval : this.monitorPoll || 200,
45985 * Stops monitoring of the valid state of this form
45987 stopMonitoring : function(){
45988 this.bound = false;
45992 bindHandler : function(){
45994 return false; // stops binding
45997 this.items.each(function(f){
45998 if(!f.isValid(true)){
46003 for(var i = 0, len = this.buttons.length; i < len; i++){
46004 var btn = this.buttons[i];
46005 if(btn.formBind === true && btn.disabled === valid){
46006 btn.setDisabled(!valid);
46009 this.fireEvent('clientvalidation', this, valid);
46023 Roo.Form = Roo.form.Form;
46026 * Ext JS Library 1.1.1
46027 * Copyright(c) 2006-2007, Ext JS, LLC.
46029 * Originally Released Under LGPL - original licence link has changed is not relivant.
46032 * <script type="text/javascript">
46035 // as we use this in bootstrap.
46036 Roo.namespace('Roo.form');
46038 * @class Roo.form.Action
46039 * Internal Class used to handle form actions
46041 * @param {Roo.form.BasicForm} el The form element or its id
46042 * @param {Object} config Configuration options
46047 // define the action interface
46048 Roo.form.Action = function(form, options){
46050 this.options = options || {};
46053 * Client Validation Failed
46056 Roo.form.Action.CLIENT_INVALID = 'client';
46058 * Server Validation Failed
46061 Roo.form.Action.SERVER_INVALID = 'server';
46063 * Connect to Server Failed
46066 Roo.form.Action.CONNECT_FAILURE = 'connect';
46068 * Reading Data from Server Failed
46071 Roo.form.Action.LOAD_FAILURE = 'load';
46073 Roo.form.Action.prototype = {
46075 failureType : undefined,
46076 response : undefined,
46077 result : undefined,
46079 // interface method
46080 run : function(options){
46084 // interface method
46085 success : function(response){
46089 // interface method
46090 handleResponse : function(response){
46094 // default connection failure
46095 failure : function(response){
46097 this.response = response;
46098 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46099 this.form.afterAction(this, false);
46102 processResponse : function(response){
46103 this.response = response;
46104 if(!response.responseText){
46107 this.result = this.handleResponse(response);
46108 return this.result;
46111 // utility functions used internally
46112 getUrl : function(appendParams){
46113 var url = this.options.url || this.form.url || this.form.el.dom.action;
46115 var p = this.getParams();
46117 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46123 getMethod : function(){
46124 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46127 getParams : function(){
46128 var bp = this.form.baseParams;
46129 var p = this.options.params;
46131 if(typeof p == "object"){
46132 p = Roo.urlEncode(Roo.applyIf(p, bp));
46133 }else if(typeof p == 'string' && bp){
46134 p += '&' + Roo.urlEncode(bp);
46137 p = Roo.urlEncode(bp);
46142 createCallback : function(){
46144 success: this.success,
46145 failure: this.failure,
46147 timeout: (this.form.timeout*1000),
46148 upload: this.form.fileUpload ? this.success : undefined
46153 Roo.form.Action.Submit = function(form, options){
46154 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46157 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46160 haveProgress : false,
46161 uploadComplete : false,
46163 // uploadProgress indicator.
46164 uploadProgress : function()
46166 if (!this.form.progressUrl) {
46170 if (!this.haveProgress) {
46171 Roo.MessageBox.progress("Uploading", "Uploading");
46173 if (this.uploadComplete) {
46174 Roo.MessageBox.hide();
46178 this.haveProgress = true;
46180 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46182 var c = new Roo.data.Connection();
46184 url : this.form.progressUrl,
46189 success : function(req){
46190 //console.log(data);
46194 rdata = Roo.decode(req.responseText)
46196 Roo.log("Invalid data from server..");
46200 if (!rdata || !rdata.success) {
46202 Roo.MessageBox.alert(Roo.encode(rdata));
46205 var data = rdata.data;
46207 if (this.uploadComplete) {
46208 Roo.MessageBox.hide();
46213 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46214 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46217 this.uploadProgress.defer(2000,this);
46220 failure: function(data) {
46221 Roo.log('progress url failed ');
46232 // run get Values on the form, so it syncs any secondary forms.
46233 this.form.getValues();
46235 var o = this.options;
46236 var method = this.getMethod();
46237 var isPost = method == 'POST';
46238 if(o.clientValidation === false || this.form.isValid()){
46240 if (this.form.progressUrl) {
46241 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46242 (new Date() * 1) + '' + Math.random());
46247 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46248 form:this.form.el.dom,
46249 url:this.getUrl(!isPost),
46251 params:isPost ? this.getParams() : null,
46252 isUpload: this.form.fileUpload
46255 this.uploadProgress();
46257 }else if (o.clientValidation !== false){ // client validation failed
46258 this.failureType = Roo.form.Action.CLIENT_INVALID;
46259 this.form.afterAction(this, false);
46263 success : function(response)
46265 this.uploadComplete= true;
46266 if (this.haveProgress) {
46267 Roo.MessageBox.hide();
46271 var result = this.processResponse(response);
46272 if(result === true || result.success){
46273 this.form.afterAction(this, true);
46277 this.form.markInvalid(result.errors);
46278 this.failureType = Roo.form.Action.SERVER_INVALID;
46280 this.form.afterAction(this, false);
46282 failure : function(response)
46284 this.uploadComplete= true;
46285 if (this.haveProgress) {
46286 Roo.MessageBox.hide();
46289 this.response = response;
46290 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46291 this.form.afterAction(this, false);
46294 handleResponse : function(response){
46295 if(this.form.errorReader){
46296 var rs = this.form.errorReader.read(response);
46299 for(var i = 0, len = rs.records.length; i < len; i++) {
46300 var r = rs.records[i];
46301 errors[i] = r.data;
46304 if(errors.length < 1){
46308 success : rs.success,
46314 ret = Roo.decode(response.responseText);
46318 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46328 Roo.form.Action.Load = function(form, options){
46329 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46330 this.reader = this.form.reader;
46333 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46338 Roo.Ajax.request(Roo.apply(
46339 this.createCallback(), {
46340 method:this.getMethod(),
46341 url:this.getUrl(false),
46342 params:this.getParams()
46346 success : function(response){
46348 var result = this.processResponse(response);
46349 if(result === true || !result.success || !result.data){
46350 this.failureType = Roo.form.Action.LOAD_FAILURE;
46351 this.form.afterAction(this, false);
46354 this.form.clearInvalid();
46355 this.form.setValues(result.data);
46356 this.form.afterAction(this, true);
46359 handleResponse : function(response){
46360 if(this.form.reader){
46361 var rs = this.form.reader.read(response);
46362 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46364 success : rs.success,
46368 return Roo.decode(response.responseText);
46372 Roo.form.Action.ACTION_TYPES = {
46373 'load' : Roo.form.Action.Load,
46374 'submit' : Roo.form.Action.Submit
46377 * Ext JS Library 1.1.1
46378 * Copyright(c) 2006-2007, Ext JS, LLC.
46380 * Originally Released Under LGPL - original licence link has changed is not relivant.
46383 * <script type="text/javascript">
46387 * @class Roo.form.Layout
46388 * @extends Roo.Component
46389 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46391 * @param {Object} config Configuration options
46393 Roo.form.Layout = function(config){
46395 if (config.items) {
46396 xitems = config.items;
46397 delete config.items;
46399 Roo.form.Layout.superclass.constructor.call(this, config);
46401 Roo.each(xitems, this.addxtype, this);
46405 Roo.extend(Roo.form.Layout, Roo.Component, {
46407 * @cfg {String/Object} autoCreate
46408 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46411 * @cfg {String/Object/Function} style
46412 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46413 * a function which returns such a specification.
46416 * @cfg {String} labelAlign
46417 * Valid values are "left," "top" and "right" (defaults to "left")
46420 * @cfg {Number} labelWidth
46421 * Fixed width in pixels of all field labels (defaults to undefined)
46424 * @cfg {Boolean} clear
46425 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46429 * @cfg {String} labelSeparator
46430 * The separator to use after field labels (defaults to ':')
46432 labelSeparator : ':',
46434 * @cfg {Boolean} hideLabels
46435 * True to suppress the display of field labels in this layout (defaults to false)
46437 hideLabels : false,
46440 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46445 onRender : function(ct, position){
46446 if(this.el){ // from markup
46447 this.el = Roo.get(this.el);
46448 }else { // generate
46449 var cfg = this.getAutoCreate();
46450 this.el = ct.createChild(cfg, position);
46453 this.el.applyStyles(this.style);
46455 if(this.labelAlign){
46456 this.el.addClass('x-form-label-'+this.labelAlign);
46458 if(this.hideLabels){
46459 this.labelStyle = "display:none";
46460 this.elementStyle = "padding-left:0;";
46462 if(typeof this.labelWidth == 'number'){
46463 this.labelStyle = "width:"+this.labelWidth+"px;";
46464 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46466 if(this.labelAlign == 'top'){
46467 this.labelStyle = "width:auto;";
46468 this.elementStyle = "padding-left:0;";
46471 var stack = this.stack;
46472 var slen = stack.length;
46474 if(!this.fieldTpl){
46475 var t = new Roo.Template(
46476 '<div class="x-form-item {5}">',
46477 '<label for="{0}" style="{2}">{1}{4}</label>',
46478 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46480 '</div><div class="x-form-clear-left"></div>'
46482 t.disableFormats = true;
46484 Roo.form.Layout.prototype.fieldTpl = t;
46486 for(var i = 0; i < slen; i++) {
46487 if(stack[i].isFormField){
46488 this.renderField(stack[i]);
46490 this.renderComponent(stack[i]);
46495 this.el.createChild({cls:'x-form-clear'});
46500 renderField : function(f){
46501 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46504 f.labelStyle||this.labelStyle||'', //2
46505 this.elementStyle||'', //3
46506 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46507 f.itemCls||this.itemCls||'' //5
46508 ], true).getPrevSibling());
46512 renderComponent : function(c){
46513 c.render(c.isLayout ? this.el : this.el.createChild());
46516 * Adds a object form elements (using the xtype property as the factory method.)
46517 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46518 * @param {Object} config
46520 addxtype : function(o)
46522 // create the lement.
46523 o.form = this.form;
46524 var fe = Roo.factory(o, Roo.form);
46525 this.form.allItems.push(fe);
46526 this.stack.push(fe);
46528 if (fe.isFormField) {
46529 this.form.items.add(fe);
46537 * @class Roo.form.Column
46538 * @extends Roo.form.Layout
46539 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46541 * @param {Object} config Configuration options
46543 Roo.form.Column = function(config){
46544 Roo.form.Column.superclass.constructor.call(this, config);
46547 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46549 * @cfg {Number/String} width
46550 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46553 * @cfg {String/Object} autoCreate
46554 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46558 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46561 onRender : function(ct, position){
46562 Roo.form.Column.superclass.onRender.call(this, ct, position);
46564 this.el.setWidth(this.width);
46571 * @class Roo.form.Row
46572 * @extends Roo.form.Layout
46573 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46575 * @param {Object} config Configuration options
46579 Roo.form.Row = function(config){
46580 Roo.form.Row.superclass.constructor.call(this, config);
46583 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46585 * @cfg {Number/String} width
46586 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46589 * @cfg {Number/String} height
46590 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46592 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46596 onRender : function(ct, position){
46597 //console.log('row render');
46599 var t = new Roo.Template(
46600 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46601 '<label for="{0}" style="{2}">{1}{4}</label>',
46602 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46606 t.disableFormats = true;
46608 Roo.form.Layout.prototype.rowTpl = t;
46610 this.fieldTpl = this.rowTpl;
46612 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46613 var labelWidth = 100;
46615 if ((this.labelAlign != 'top')) {
46616 if (typeof this.labelWidth == 'number') {
46617 labelWidth = this.labelWidth
46619 this.padWidth = 20 + labelWidth;
46623 Roo.form.Column.superclass.onRender.call(this, ct, position);
46625 this.el.setWidth(this.width);
46628 this.el.setHeight(this.height);
46633 renderField : function(f){
46634 f.fieldEl = this.fieldTpl.append(this.el, [
46635 f.id, f.fieldLabel,
46636 f.labelStyle||this.labelStyle||'',
46637 this.elementStyle||'',
46638 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46639 f.itemCls||this.itemCls||'',
46640 f.width ? f.width + this.padWidth : 160 + this.padWidth
46647 * @class Roo.form.FieldSet
46648 * @extends Roo.form.Layout
46649 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46651 * @param {Object} config Configuration options
46653 Roo.form.FieldSet = function(config){
46654 Roo.form.FieldSet.superclass.constructor.call(this, config);
46657 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46659 * @cfg {String} legend
46660 * The text to display as the legend for the FieldSet (defaults to '')
46663 * @cfg {String/Object} autoCreate
46664 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46668 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46671 onRender : function(ct, position){
46672 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46674 this.setLegend(this.legend);
46679 setLegend : function(text){
46681 this.el.child('legend').update(text);
46686 * Ext JS Library 1.1.1
46687 * Copyright(c) 2006-2007, Ext JS, LLC.
46689 * Originally Released Under LGPL - original licence link has changed is not relivant.
46692 * <script type="text/javascript">
46695 * @class Roo.form.VTypes
46696 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46699 Roo.form.VTypes = function(){
46700 // closure these in so they are only created once.
46701 var alpha = /^[a-zA-Z_]+$/;
46702 var alphanum = /^[a-zA-Z0-9_]+$/;
46703 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46704 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46706 // All these messages and functions are configurable
46709 * The function used to validate email addresses
46710 * @param {String} value The email address
46712 'email' : function(v){
46713 return email.test(v);
46716 * The error text to display when the email validation function returns false
46719 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46721 * The keystroke filter mask to be applied on email input
46724 'emailMask' : /[a-z0-9_\.\-@]/i,
46727 * The function used to validate URLs
46728 * @param {String} value The URL
46730 'url' : function(v){
46731 return url.test(v);
46734 * The error text to display when the url validation function returns false
46737 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46740 * The function used to validate alpha values
46741 * @param {String} value The value
46743 'alpha' : function(v){
46744 return alpha.test(v);
46747 * The error text to display when the alpha validation function returns false
46750 'alphaText' : 'This field should only contain letters and _',
46752 * The keystroke filter mask to be applied on alpha input
46755 'alphaMask' : /[a-z_]/i,
46758 * The function used to validate alphanumeric values
46759 * @param {String} value The value
46761 'alphanum' : function(v){
46762 return alphanum.test(v);
46765 * The error text to display when the alphanumeric validation function returns false
46768 'alphanumText' : 'This field should only contain letters, numbers and _',
46770 * The keystroke filter mask to be applied on alphanumeric input
46773 'alphanumMask' : /[a-z0-9_]/i
46775 }();//<script type="text/javascript">
46778 * @class Roo.form.FCKeditor
46779 * @extends Roo.form.TextArea
46780 * Wrapper around the FCKEditor http://www.fckeditor.net
46782 * Creates a new FCKeditor
46783 * @param {Object} config Configuration options
46785 Roo.form.FCKeditor = function(config){
46786 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46789 * @event editorinit
46790 * Fired when the editor is initialized - you can add extra handlers here..
46791 * @param {FCKeditor} this
46792 * @param {Object} the FCK object.
46799 Roo.form.FCKeditor.editors = { };
46800 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46802 //defaultAutoCreate : {
46803 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46807 * @cfg {Object} fck options - see fck manual for details.
46812 * @cfg {Object} fck toolbar set (Basic or Default)
46814 toolbarSet : 'Basic',
46816 * @cfg {Object} fck BasePath
46818 basePath : '/fckeditor/',
46826 onRender : function(ct, position)
46829 this.defaultAutoCreate = {
46831 style:"width:300px;height:60px;",
46832 autocomplete: "new-password"
46835 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46838 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46839 if(this.preventScrollbars){
46840 this.el.setStyle("overflow", "hidden");
46842 this.el.setHeight(this.growMin);
46845 //console.log('onrender' + this.getId() );
46846 Roo.form.FCKeditor.editors[this.getId()] = this;
46849 this.replaceTextarea() ;
46853 getEditor : function() {
46854 return this.fckEditor;
46857 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46858 * @param {Mixed} value The value to set
46862 setValue : function(value)
46864 //console.log('setValue: ' + value);
46866 if(typeof(value) == 'undefined') { // not sure why this is happending...
46869 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46871 //if(!this.el || !this.getEditor()) {
46872 // this.value = value;
46873 //this.setValue.defer(100,this,[value]);
46877 if(!this.getEditor()) {
46881 this.getEditor().SetData(value);
46888 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46889 * @return {Mixed} value The field value
46891 getValue : function()
46894 if (this.frame && this.frame.dom.style.display == 'none') {
46895 return Roo.form.FCKeditor.superclass.getValue.call(this);
46898 if(!this.el || !this.getEditor()) {
46900 // this.getValue.defer(100,this);
46905 var value=this.getEditor().GetData();
46906 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46907 return Roo.form.FCKeditor.superclass.getValue.call(this);
46913 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46914 * @return {Mixed} value The field value
46916 getRawValue : function()
46918 if (this.frame && this.frame.dom.style.display == 'none') {
46919 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46922 if(!this.el || !this.getEditor()) {
46923 //this.getRawValue.defer(100,this);
46930 var value=this.getEditor().GetData();
46931 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46932 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46936 setSize : function(w,h) {
46940 //if (this.frame && this.frame.dom.style.display == 'none') {
46941 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46944 //if(!this.el || !this.getEditor()) {
46945 // this.setSize.defer(100,this, [w,h]);
46951 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46953 this.frame.dom.setAttribute('width', w);
46954 this.frame.dom.setAttribute('height', h);
46955 this.frame.setSize(w,h);
46959 toggleSourceEdit : function(value) {
46963 this.el.dom.style.display = value ? '' : 'none';
46964 this.frame.dom.style.display = value ? 'none' : '';
46969 focus: function(tag)
46971 if (this.frame.dom.style.display == 'none') {
46972 return Roo.form.FCKeditor.superclass.focus.call(this);
46974 if(!this.el || !this.getEditor()) {
46975 this.focus.defer(100,this, [tag]);
46982 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46983 this.getEditor().Focus();
46985 if (!this.getEditor().Selection.GetSelection()) {
46986 this.focus.defer(100,this, [tag]);
46991 var r = this.getEditor().EditorDocument.createRange();
46992 r.setStart(tgs[0],0);
46993 r.setEnd(tgs[0],0);
46994 this.getEditor().Selection.GetSelection().removeAllRanges();
46995 this.getEditor().Selection.GetSelection().addRange(r);
46996 this.getEditor().Focus();
47003 replaceTextarea : function()
47005 if ( document.getElementById( this.getId() + '___Frame' ) )
47007 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
47009 // We must check the elements firstly using the Id and then the name.
47010 var oTextarea = document.getElementById( this.getId() );
47012 var colElementsByName = document.getElementsByName( this.getId() ) ;
47014 oTextarea.style.display = 'none' ;
47016 if ( oTextarea.tabIndex ) {
47017 this.TabIndex = oTextarea.tabIndex ;
47020 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
47021 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
47022 this.frame = Roo.get(this.getId() + '___Frame')
47025 _getConfigHtml : function()
47029 for ( var o in this.fckconfig ) {
47030 sConfig += sConfig.length > 0 ? '&' : '';
47031 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47034 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47038 _getIFrameHtml : function()
47040 var sFile = 'fckeditor.html' ;
47041 /* no idea what this is about..
47044 if ( (/fcksource=true/i).test( window.top.location.search ) )
47045 sFile = 'fckeditor.original.html' ;
47050 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47051 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47054 var html = '<iframe id="' + this.getId() +
47055 '___Frame" src="' + sLink +
47056 '" width="' + this.width +
47057 '" height="' + this.height + '"' +
47058 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47059 ' frameborder="0" scrolling="no"></iframe>' ;
47064 _insertHtmlBefore : function( html, element )
47066 if ( element.insertAdjacentHTML ) {
47068 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47070 var oRange = document.createRange() ;
47071 oRange.setStartBefore( element ) ;
47072 var oFragment = oRange.createContextualFragment( html );
47073 element.parentNode.insertBefore( oFragment, element ) ;
47086 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47088 function FCKeditor_OnComplete(editorInstance){
47089 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47090 f.fckEditor = editorInstance;
47091 //console.log("loaded");
47092 f.fireEvent('editorinit', f, editorInstance);
47112 //<script type="text/javascript">
47114 * @class Roo.form.GridField
47115 * @extends Roo.form.Field
47116 * Embed a grid (or editable grid into a form)
47119 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47121 * xgrid.store = Roo.data.Store
47122 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47123 * xgrid.store.reader = Roo.data.JsonReader
47127 * Creates a new GridField
47128 * @param {Object} config Configuration options
47130 Roo.form.GridField = function(config){
47131 Roo.form.GridField.superclass.constructor.call(this, config);
47135 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47137 * @cfg {Number} width - used to restrict width of grid..
47141 * @cfg {Number} height - used to restrict height of grid..
47145 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47151 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47152 * {tag: "input", type: "checkbox", autocomplete: "off"})
47154 // defaultAutoCreate : { tag: 'div' },
47155 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47157 * @cfg {String} addTitle Text to include for adding a title.
47161 onResize : function(){
47162 Roo.form.Field.superclass.onResize.apply(this, arguments);
47165 initEvents : function(){
47166 // Roo.form.Checkbox.superclass.initEvents.call(this);
47167 // has no events...
47172 getResizeEl : function(){
47176 getPositionEl : function(){
47181 onRender : function(ct, position){
47183 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47184 var style = this.style;
47187 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47188 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47189 this.viewEl = this.wrap.createChild({ tag: 'div' });
47191 this.viewEl.applyStyles(style);
47194 this.viewEl.setWidth(this.width);
47197 this.viewEl.setHeight(this.height);
47199 //if(this.inputValue !== undefined){
47200 //this.setValue(this.value);
47203 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47206 this.grid.render();
47207 this.grid.getDataSource().on('remove', this.refreshValue, this);
47208 this.grid.getDataSource().on('update', this.refreshValue, this);
47209 this.grid.on('afteredit', this.refreshValue, this);
47215 * Sets the value of the item.
47216 * @param {String} either an object or a string..
47218 setValue : function(v){
47220 v = v || []; // empty set..
47221 // this does not seem smart - it really only affects memoryproxy grids..
47222 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47223 var ds = this.grid.getDataSource();
47224 // assumes a json reader..
47226 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47227 ds.loadData( data);
47229 // clear selection so it does not get stale.
47230 if (this.grid.sm) {
47231 this.grid.sm.clearSelections();
47234 Roo.form.GridField.superclass.setValue.call(this, v);
47235 this.refreshValue();
47236 // should load data in the grid really....
47240 refreshValue: function() {
47242 this.grid.getDataSource().each(function(r) {
47245 this.el.dom.value = Roo.encode(val);
47253 * Ext JS Library 1.1.1
47254 * Copyright(c) 2006-2007, Ext JS, LLC.
47256 * Originally Released Under LGPL - original licence link has changed is not relivant.
47259 * <script type="text/javascript">
47262 * @class Roo.form.DisplayField
47263 * @extends Roo.form.Field
47264 * A generic Field to display non-editable data.
47266 * Creates a new Display Field item.
47267 * @param {Object} config Configuration options
47269 Roo.form.DisplayField = function(config){
47270 Roo.form.DisplayField.superclass.constructor.call(this, config);
47274 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47275 inputType: 'hidden',
47281 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47283 focusClass : undefined,
47285 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47287 fieldClass: 'x-form-field',
47290 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47292 valueRenderer: undefined,
47296 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47297 * {tag: "input", type: "checkbox", autocomplete: "off"})
47300 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47302 onResize : function(){
47303 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47307 initEvents : function(){
47308 // Roo.form.Checkbox.superclass.initEvents.call(this);
47309 // has no events...
47314 getResizeEl : function(){
47318 getPositionEl : function(){
47323 onRender : function(ct, position){
47325 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47326 //if(this.inputValue !== undefined){
47327 this.wrap = this.el.wrap();
47329 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47331 if (this.bodyStyle) {
47332 this.viewEl.applyStyles(this.bodyStyle);
47334 //this.viewEl.setStyle('padding', '2px');
47336 this.setValue(this.value);
47341 initValue : Roo.emptyFn,
47346 onClick : function(){
47351 * Sets the checked state of the checkbox.
47352 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47354 setValue : function(v){
47356 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47357 // this might be called before we have a dom element..
47358 if (!this.viewEl) {
47361 this.viewEl.dom.innerHTML = html;
47362 Roo.form.DisplayField.superclass.setValue.call(this, v);
47372 * @class Roo.form.DayPicker
47373 * @extends Roo.form.Field
47374 * A Day picker show [M] [T] [W] ....
47376 * Creates a new Day Picker
47377 * @param {Object} config Configuration options
47379 Roo.form.DayPicker= function(config){
47380 Roo.form.DayPicker.superclass.constructor.call(this, config);
47384 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47386 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47388 focusClass : undefined,
47390 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47392 fieldClass: "x-form-field",
47395 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47396 * {tag: "input", type: "checkbox", autocomplete: "off"})
47398 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47401 actionMode : 'viewEl',
47405 inputType : 'hidden',
47408 inputElement: false, // real input element?
47409 basedOn: false, // ????
47411 isFormField: true, // not sure where this is needed!!!!
47413 onResize : function(){
47414 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47415 if(!this.boxLabel){
47416 this.el.alignTo(this.wrap, 'c-c');
47420 initEvents : function(){
47421 Roo.form.Checkbox.superclass.initEvents.call(this);
47422 this.el.on("click", this.onClick, this);
47423 this.el.on("change", this.onClick, this);
47427 getResizeEl : function(){
47431 getPositionEl : function(){
47437 onRender : function(ct, position){
47438 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47440 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47442 var r1 = '<table><tr>';
47443 var r2 = '<tr class="x-form-daypick-icons">';
47444 for (var i=0; i < 7; i++) {
47445 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47446 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47449 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47450 viewEl.select('img').on('click', this.onClick, this);
47451 this.viewEl = viewEl;
47454 // this will not work on Chrome!!!
47455 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47456 this.el.on('propertychange', this.setFromHidden, this); //ie
47464 initValue : Roo.emptyFn,
47467 * Returns the checked state of the checkbox.
47468 * @return {Boolean} True if checked, else false
47470 getValue : function(){
47471 return this.el.dom.value;
47476 onClick : function(e){
47477 //this.setChecked(!this.checked);
47478 Roo.get(e.target).toggleClass('x-menu-item-checked');
47479 this.refreshValue();
47480 //if(this.el.dom.checked != this.checked){
47481 // this.setValue(this.el.dom.checked);
47486 refreshValue : function()
47489 this.viewEl.select('img',true).each(function(e,i,n) {
47490 val += e.is(".x-menu-item-checked") ? String(n) : '';
47492 this.setValue(val, true);
47496 * Sets the checked state of the checkbox.
47497 * On is always based on a string comparison between inputValue and the param.
47498 * @param {Boolean/String} value - the value to set
47499 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47501 setValue : function(v,suppressEvent){
47502 if (!this.el.dom) {
47505 var old = this.el.dom.value ;
47506 this.el.dom.value = v;
47507 if (suppressEvent) {
47511 // update display..
47512 this.viewEl.select('img',true).each(function(e,i,n) {
47514 var on = e.is(".x-menu-item-checked");
47515 var newv = v.indexOf(String(n)) > -1;
47517 e.toggleClass('x-menu-item-checked');
47523 this.fireEvent('change', this, v, old);
47528 // handle setting of hidden value by some other method!!?!?
47529 setFromHidden: function()
47534 //console.log("SET FROM HIDDEN");
47535 //alert('setFrom hidden');
47536 this.setValue(this.el.dom.value);
47539 onDestroy : function()
47542 Roo.get(this.viewEl).remove();
47545 Roo.form.DayPicker.superclass.onDestroy.call(this);
47549 * RooJS Library 1.1.1
47550 * Copyright(c) 2008-2011 Alan Knowles
47557 * @class Roo.form.ComboCheck
47558 * @extends Roo.form.ComboBox
47559 * A combobox for multiple select items.
47561 * FIXME - could do with a reset button..
47564 * Create a new ComboCheck
47565 * @param {Object} config Configuration options
47567 Roo.form.ComboCheck = function(config){
47568 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47569 // should verify some data...
47571 // hiddenName = required..
47572 // displayField = required
47573 // valudField == required
47574 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47576 Roo.each(req, function(e) {
47577 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47578 throw "Roo.form.ComboCheck : missing value for: " + e;
47585 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47590 selectedClass: 'x-menu-item-checked',
47593 onRender : function(ct, position){
47599 var cls = 'x-combo-list';
47602 this.tpl = new Roo.Template({
47603 html : '<div class="'+cls+'-item x-menu-check-item">' +
47604 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47605 '<span>{' + this.displayField + '}</span>' +
47612 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47613 this.view.singleSelect = false;
47614 this.view.multiSelect = true;
47615 this.view.toggleSelect = true;
47616 this.pageTb.add(new Roo.Toolbar.Fill(), {
47619 handler: function()
47626 onViewOver : function(e, t){
47632 onViewClick : function(doFocus,index){
47636 select: function () {
47637 //Roo.log("SELECT CALLED");
47640 selectByValue : function(xv, scrollIntoView){
47641 var ar = this.getValueArray();
47644 Roo.each(ar, function(v) {
47645 if(v === undefined || v === null){
47648 var r = this.findRecord(this.valueField, v);
47650 sels.push(this.store.indexOf(r))
47654 this.view.select(sels);
47660 onSelect : function(record, index){
47661 // Roo.log("onselect Called");
47662 // this is only called by the clear button now..
47663 this.view.clearSelections();
47664 this.setValue('[]');
47665 if (this.value != this.valueBefore) {
47666 this.fireEvent('change', this, this.value, this.valueBefore);
47667 this.valueBefore = this.value;
47670 getValueArray : function()
47675 //Roo.log(this.value);
47676 if (typeof(this.value) == 'undefined') {
47679 var ar = Roo.decode(this.value);
47680 return ar instanceof Array ? ar : []; //?? valid?
47683 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47688 expand : function ()
47691 Roo.form.ComboCheck.superclass.expand.call(this);
47692 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47693 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47698 collapse : function(){
47699 Roo.form.ComboCheck.superclass.collapse.call(this);
47700 var sl = this.view.getSelectedIndexes();
47701 var st = this.store;
47705 Roo.each(sl, function(i) {
47707 nv.push(r.get(this.valueField));
47709 this.setValue(Roo.encode(nv));
47710 if (this.value != this.valueBefore) {
47712 this.fireEvent('change', this, this.value, this.valueBefore);
47713 this.valueBefore = this.value;
47718 setValue : function(v){
47722 var vals = this.getValueArray();
47724 Roo.each(vals, function(k) {
47725 var r = this.findRecord(this.valueField, k);
47727 tv.push(r.data[this.displayField]);
47728 }else if(this.valueNotFoundText !== undefined){
47729 tv.push( this.valueNotFoundText );
47734 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47735 this.hiddenField.value = v;
47741 * Ext JS Library 1.1.1
47742 * Copyright(c) 2006-2007, Ext JS, LLC.
47744 * Originally Released Under LGPL - original licence link has changed is not relivant.
47747 * <script type="text/javascript">
47751 * @class Roo.form.Signature
47752 * @extends Roo.form.Field
47756 * @param {Object} config Configuration options
47759 Roo.form.Signature = function(config){
47760 Roo.form.Signature.superclass.constructor.call(this, config);
47762 this.addEvents({// not in used??
47765 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47766 * @param {Roo.form.Signature} combo This combo box
47771 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47772 * @param {Roo.form.ComboBox} combo This combo box
47773 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47779 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47781 * @cfg {Object} labels Label to use when rendering a form.
47785 * confirm : "Confirm"
47790 confirm : "Confirm"
47793 * @cfg {Number} width The signature panel width (defaults to 300)
47797 * @cfg {Number} height The signature panel height (defaults to 100)
47801 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47803 allowBlank : false,
47806 // {Object} signPanel The signature SVG panel element (defaults to {})
47808 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47809 isMouseDown : false,
47810 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47811 isConfirmed : false,
47812 // {String} signatureTmp SVG mapping string (defaults to empty string)
47816 defaultAutoCreate : { // modified by initCompnoent..
47822 onRender : function(ct, position){
47824 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47826 this.wrap = this.el.wrap({
47827 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47830 this.createToolbar(this);
47831 this.signPanel = this.wrap.createChild({
47833 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47837 this.svgID = Roo.id();
47838 this.svgEl = this.signPanel.createChild({
47839 xmlns : 'http://www.w3.org/2000/svg',
47841 id : this.svgID + "-svg",
47843 height: this.height,
47844 viewBox: '0 0 '+this.width+' '+this.height,
47848 id: this.svgID + "-svg-r",
47850 height: this.height,
47855 id: this.svgID + "-svg-l",
47857 y1: (this.height*0.8), // start set the line in 80% of height
47858 x2: this.width, // end
47859 y2: (this.height*0.8), // end set the line in 80% of height
47861 'stroke-width': "1",
47862 'stroke-dasharray': "3",
47863 'shape-rendering': "crispEdges",
47864 'pointer-events': "none"
47868 id: this.svgID + "-svg-p",
47870 'stroke-width': "3",
47872 'pointer-events': 'none'
47877 this.svgBox = this.svgEl.dom.getScreenCTM();
47879 createSVG : function(){
47880 var svg = this.signPanel;
47881 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47884 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47885 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47886 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47887 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47888 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47889 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47890 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47893 isTouchEvent : function(e){
47894 return e.type.match(/^touch/);
47896 getCoords : function (e) {
47897 var pt = this.svgEl.dom.createSVGPoint();
47900 if (this.isTouchEvent(e)) {
47901 pt.x = e.targetTouches[0].clientX;
47902 pt.y = e.targetTouches[0].clientY;
47904 var a = this.svgEl.dom.getScreenCTM();
47905 var b = a.inverse();
47906 var mx = pt.matrixTransform(b);
47907 return mx.x + ',' + mx.y;
47909 //mouse event headler
47910 down : function (e) {
47911 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47912 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47914 this.isMouseDown = true;
47916 e.preventDefault();
47918 move : function (e) {
47919 if (this.isMouseDown) {
47920 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47921 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47924 e.preventDefault();
47926 up : function (e) {
47927 this.isMouseDown = false;
47928 var sp = this.signatureTmp.split(' ');
47931 if(!sp[sp.length-2].match(/^L/)){
47935 this.signatureTmp = sp.join(" ");
47938 if(this.getValue() != this.signatureTmp){
47939 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47940 this.isConfirmed = false;
47942 e.preventDefault();
47946 * Protected method that will not generally be called directly. It
47947 * is called when the editor creates its toolbar. Override this method if you need to
47948 * add custom toolbar buttons.
47949 * @param {HtmlEditor} editor
47951 createToolbar : function(editor){
47952 function btn(id, toggle, handler){
47953 var xid = fid + '-'+ id ;
47957 cls : 'x-btn-icon x-edit-'+id,
47958 enableToggle:toggle !== false,
47959 scope: editor, // was editor...
47960 handler:handler||editor.relayBtnCmd,
47961 clickEvent:'mousedown',
47962 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47968 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47972 cls : ' x-signature-btn x-signature-'+id,
47973 scope: editor, // was editor...
47974 handler: this.reset,
47975 clickEvent:'mousedown',
47976 text: this.labels.clear
47983 cls : ' x-signature-btn x-signature-'+id,
47984 scope: editor, // was editor...
47985 handler: this.confirmHandler,
47986 clickEvent:'mousedown',
47987 text: this.labels.confirm
47994 * when user is clicked confirm then show this image.....
47996 * @return {String} Image Data URI
47998 getImageDataURI : function(){
47999 var svg = this.svgEl.dom.parentNode.innerHTML;
48000 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
48005 * @return {Boolean} this.isConfirmed
48007 getConfirmed : function(){
48008 return this.isConfirmed;
48012 * @return {Number} this.width
48014 getWidth : function(){
48019 * @return {Number} this.height
48021 getHeight : function(){
48022 return this.height;
48025 getSignature : function(){
48026 return this.signatureTmp;
48029 reset : function(){
48030 this.signatureTmp = '';
48031 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48032 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48033 this.isConfirmed = false;
48034 Roo.form.Signature.superclass.reset.call(this);
48036 setSignature : function(s){
48037 this.signatureTmp = s;
48038 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48039 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48041 this.isConfirmed = false;
48042 Roo.form.Signature.superclass.reset.call(this);
48045 // Roo.log(this.signPanel.dom.contentWindow.up())
48048 setConfirmed : function(){
48052 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48055 confirmHandler : function(){
48056 if(!this.getSignature()){
48060 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48061 this.setValue(this.getSignature());
48062 this.isConfirmed = true;
48064 this.fireEvent('confirm', this);
48067 // Subclasses should provide the validation implementation by overriding this
48068 validateValue : function(value){
48069 if(this.allowBlank){
48073 if(this.isConfirmed){
48080 * Ext JS Library 1.1.1
48081 * Copyright(c) 2006-2007, Ext JS, LLC.
48083 * Originally Released Under LGPL - original licence link has changed is not relivant.
48086 * <script type="text/javascript">
48091 * @class Roo.form.ComboBox
48092 * @extends Roo.form.TriggerField
48093 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48095 * Create a new ComboBox.
48096 * @param {Object} config Configuration options
48098 Roo.form.Select = function(config){
48099 Roo.form.Select.superclass.constructor.call(this, config);
48103 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48105 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48108 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48109 * rendering into an Roo.Editor, defaults to false)
48112 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48113 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48116 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48119 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48120 * the dropdown list (defaults to undefined, with no header element)
48124 * @cfg {String/Roo.Template} tpl The template to use to render the output
48128 defaultAutoCreate : {tag: "select" },
48130 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48132 listWidth: undefined,
48134 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48135 * mode = 'remote' or 'text' if mode = 'local')
48137 displayField: undefined,
48139 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48140 * mode = 'remote' or 'value' if mode = 'local').
48141 * Note: use of a valueField requires the user make a selection
48142 * in order for a value to be mapped.
48144 valueField: undefined,
48148 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48149 * field's data value (defaults to the underlying DOM element's name)
48151 hiddenName: undefined,
48153 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48157 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48159 selectedClass: 'x-combo-selected',
48161 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48162 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48163 * which displays a downward arrow icon).
48165 triggerClass : 'x-form-arrow-trigger',
48167 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48171 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48172 * anchor positions (defaults to 'tl-bl')
48174 listAlign: 'tl-bl?',
48176 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48180 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48181 * query specified by the allQuery config option (defaults to 'query')
48183 triggerAction: 'query',
48185 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48186 * (defaults to 4, does not apply if editable = false)
48190 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48191 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48195 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48196 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48200 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48201 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48205 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48206 * when editable = true (defaults to false)
48208 selectOnFocus:false,
48210 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48212 queryParam: 'query',
48214 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48215 * when mode = 'remote' (defaults to 'Loading...')
48217 loadingText: 'Loading...',
48219 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48223 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48227 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48228 * traditional select (defaults to true)
48232 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48236 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48240 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48241 * listWidth has a higher value)
48245 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48246 * allow the user to set arbitrary text into the field (defaults to false)
48248 forceSelection:false,
48250 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48251 * if typeAhead = true (defaults to 250)
48253 typeAheadDelay : 250,
48255 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48256 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48258 valueNotFoundText : undefined,
48261 * @cfg {String} defaultValue The value displayed after loading the store.
48266 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48268 blockFocus : false,
48271 * @cfg {Boolean} disableClear Disable showing of clear button.
48273 disableClear : false,
48275 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48277 alwaysQuery : false,
48283 // element that contains real text value.. (when hidden is used..)
48286 onRender : function(ct, position){
48287 Roo.form.Field.prototype.onRender.call(this, ct, position);
48290 this.store.on('beforeload', this.onBeforeLoad, this);
48291 this.store.on('load', this.onLoad, this);
48292 this.store.on('loadexception', this.onLoadException, this);
48293 this.store.load({});
48301 initEvents : function(){
48302 //Roo.form.ComboBox.superclass.initEvents.call(this);
48306 onDestroy : function(){
48309 this.store.un('beforeload', this.onBeforeLoad, this);
48310 this.store.un('load', this.onLoad, this);
48311 this.store.un('loadexception', this.onLoadException, this);
48313 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48317 fireKey : function(e){
48318 if(e.isNavKeyPress() && !this.list.isVisible()){
48319 this.fireEvent("specialkey", this, e);
48324 onResize: function(w, h){
48332 * Allow or prevent the user from directly editing the field text. If false is passed,
48333 * the user will only be able to select from the items defined in the dropdown list. This method
48334 * is the runtime equivalent of setting the 'editable' config option at config time.
48335 * @param {Boolean} value True to allow the user to directly edit the field text
48337 setEditable : function(value){
48342 onBeforeLoad : function(){
48344 Roo.log("Select before load");
48347 this.innerList.update(this.loadingText ?
48348 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48349 //this.restrictHeight();
48350 this.selectedIndex = -1;
48354 onLoad : function(){
48357 var dom = this.el.dom;
48358 dom.innerHTML = '';
48359 var od = dom.ownerDocument;
48361 if (this.emptyText) {
48362 var op = od.createElement('option');
48363 op.setAttribute('value', '');
48364 op.innerHTML = String.format('{0}', this.emptyText);
48365 dom.appendChild(op);
48367 if(this.store.getCount() > 0){
48369 var vf = this.valueField;
48370 var df = this.displayField;
48371 this.store.data.each(function(r) {
48372 // which colmsn to use... testing - cdoe / title..
48373 var op = od.createElement('option');
48374 op.setAttribute('value', r.data[vf]);
48375 op.innerHTML = String.format('{0}', r.data[df]);
48376 dom.appendChild(op);
48378 if (typeof(this.defaultValue != 'undefined')) {
48379 this.setValue(this.defaultValue);
48384 //this.onEmptyResults();
48389 onLoadException : function()
48391 dom.innerHTML = '';
48393 Roo.log("Select on load exception");
48397 Roo.log(this.store.reader.jsonData);
48398 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48399 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48405 onTypeAhead : function(){
48410 onSelect : function(record, index){
48411 Roo.log('on select?');
48413 if(this.fireEvent('beforeselect', this, record, index) !== false){
48414 this.setFromData(index > -1 ? record.data : false);
48416 this.fireEvent('select', this, record, index);
48421 * Returns the currently selected field value or empty string if no value is set.
48422 * @return {String} value The selected value
48424 getValue : function(){
48425 var dom = this.el.dom;
48426 this.value = dom.options[dom.selectedIndex].value;
48432 * Clears any text/value currently set in the field
48434 clearValue : function(){
48436 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48441 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48442 * will be displayed in the field. If the value does not match the data value of an existing item,
48443 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48444 * Otherwise the field will be blank (although the value will still be set).
48445 * @param {String} value The value to match
48447 setValue : function(v){
48448 var d = this.el.dom;
48449 for (var i =0; i < d.options.length;i++) {
48450 if (v == d.options[i].value) {
48451 d.selectedIndex = i;
48459 * @property {Object} the last set data for the element
48464 * Sets the value of the field based on a object which is related to the record format for the store.
48465 * @param {Object} value the value to set as. or false on reset?
48467 setFromData : function(o){
48468 Roo.log('setfrom data?');
48474 reset : function(){
48478 findRecord : function(prop, value){
48483 if(this.store.getCount() > 0){
48484 this.store.each(function(r){
48485 if(r.data[prop] == value){
48495 getName: function()
48497 // returns hidden if it's set..
48498 if (!this.rendered) {return ''};
48499 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48507 onEmptyResults : function(){
48508 Roo.log('empty results');
48513 * Returns true if the dropdown list is expanded, else false.
48515 isExpanded : function(){
48520 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48521 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48522 * @param {String} value The data value of the item to select
48523 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48524 * selected item if it is not currently in view (defaults to true)
48525 * @return {Boolean} True if the value matched an item in the list, else false
48527 selectByValue : function(v, scrollIntoView){
48528 Roo.log('select By Value');
48531 if(v !== undefined && v !== null){
48532 var r = this.findRecord(this.valueField || this.displayField, v);
48534 this.select(this.store.indexOf(r), scrollIntoView);
48542 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48543 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48544 * @param {Number} index The zero-based index of the list item to select
48545 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48546 * selected item if it is not currently in view (defaults to true)
48548 select : function(index, scrollIntoView){
48549 Roo.log('select ');
48552 this.selectedIndex = index;
48553 this.view.select(index);
48554 if(scrollIntoView !== false){
48555 var el = this.view.getNode(index);
48557 this.innerList.scrollChildIntoView(el, false);
48565 validateBlur : function(){
48572 initQuery : function(){
48573 this.doQuery(this.getRawValue());
48577 doForce : function(){
48578 if(this.el.dom.value.length > 0){
48579 this.el.dom.value =
48580 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48586 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48587 * query allowing the query action to be canceled if needed.
48588 * @param {String} query The SQL query to execute
48589 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48590 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48591 * saved in the current store (defaults to false)
48593 doQuery : function(q, forceAll){
48595 Roo.log('doQuery?');
48596 if(q === undefined || q === null){
48601 forceAll: forceAll,
48605 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48609 forceAll = qe.forceAll;
48610 if(forceAll === true || (q.length >= this.minChars)){
48611 if(this.lastQuery != q || this.alwaysQuery){
48612 this.lastQuery = q;
48613 if(this.mode == 'local'){
48614 this.selectedIndex = -1;
48616 this.store.clearFilter();
48618 this.store.filter(this.displayField, q);
48622 this.store.baseParams[this.queryParam] = q;
48624 params: this.getParams(q)
48629 this.selectedIndex = -1;
48636 getParams : function(q){
48638 //p[this.queryParam] = q;
48641 p.limit = this.pageSize;
48647 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48649 collapse : function(){
48654 collapseIf : function(e){
48659 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48661 expand : function(){
48669 * @cfg {Boolean} grow
48673 * @cfg {Number} growMin
48677 * @cfg {Number} growMax
48685 setWidth : function()
48689 getResizeEl : function(){
48692 });//<script type="text/javasscript">
48696 * @class Roo.DDView
48697 * A DnD enabled version of Roo.View.
48698 * @param {Element/String} container The Element in which to create the View.
48699 * @param {String} tpl The template string used to create the markup for each element of the View
48700 * @param {Object} config The configuration properties. These include all the config options of
48701 * {@link Roo.View} plus some specific to this class.<br>
48703 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48704 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48706 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48707 .x-view-drag-insert-above {
48708 border-top:1px dotted #3366cc;
48710 .x-view-drag-insert-below {
48711 border-bottom:1px dotted #3366cc;
48717 Roo.DDView = function(container, tpl, config) {
48718 Roo.DDView.superclass.constructor.apply(this, arguments);
48719 this.getEl().setStyle("outline", "0px none");
48720 this.getEl().unselectable();
48721 if (this.dragGroup) {
48722 this.setDraggable(this.dragGroup.split(","));
48724 if (this.dropGroup) {
48725 this.setDroppable(this.dropGroup.split(","));
48727 if (this.deletable) {
48728 this.setDeletable();
48730 this.isDirtyFlag = false;
48736 Roo.extend(Roo.DDView, Roo.View, {
48737 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48738 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48739 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48740 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48744 reset: Roo.emptyFn,
48746 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48748 validate: function() {
48752 destroy: function() {
48753 this.purgeListeners();
48754 this.getEl.removeAllListeners();
48755 this.getEl().remove();
48756 if (this.dragZone) {
48757 if (this.dragZone.destroy) {
48758 this.dragZone.destroy();
48761 if (this.dropZone) {
48762 if (this.dropZone.destroy) {
48763 this.dropZone.destroy();
48768 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48769 getName: function() {
48773 /** Loads the View from a JSON string representing the Records to put into the Store. */
48774 setValue: function(v) {
48776 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48779 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48780 this.store.proxy = new Roo.data.MemoryProxy(data);
48784 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48785 getValue: function() {
48787 this.store.each(function(rec) {
48788 result += rec.id + ',';
48790 return result.substr(0, result.length - 1) + ')';
48793 getIds: function() {
48794 var i = 0, result = new Array(this.store.getCount());
48795 this.store.each(function(rec) {
48796 result[i++] = rec.id;
48801 isDirty: function() {
48802 return this.isDirtyFlag;
48806 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48807 * whole Element becomes the target, and this causes the drop gesture to append.
48809 getTargetFromEvent : function(e) {
48810 var target = e.getTarget();
48811 while ((target !== null) && (target.parentNode != this.el.dom)) {
48812 target = target.parentNode;
48815 target = this.el.dom.lastChild || this.el.dom;
48821 * Create the drag data which consists of an object which has the property "ddel" as
48822 * the drag proxy element.
48824 getDragData : function(e) {
48825 var target = this.findItemFromChild(e.getTarget());
48827 this.handleSelection(e);
48828 var selNodes = this.getSelectedNodes();
48831 copy: this.copy || (this.allowCopy && e.ctrlKey),
48835 var selectedIndices = this.getSelectedIndexes();
48836 for (var i = 0; i < selectedIndices.length; i++) {
48837 dragData.records.push(this.store.getAt(selectedIndices[i]));
48839 if (selNodes.length == 1) {
48840 dragData.ddel = target.cloneNode(true); // the div element
48842 var div = document.createElement('div'); // create the multi element drag "ghost"
48843 div.className = 'multi-proxy';
48844 for (var i = 0, len = selNodes.length; i < len; i++) {
48845 div.appendChild(selNodes[i].cloneNode(true));
48847 dragData.ddel = div;
48849 //console.log(dragData)
48850 //console.log(dragData.ddel.innerHTML)
48853 //console.log('nodragData')
48857 /** Specify to which ddGroup items in this DDView may be dragged. */
48858 setDraggable: function(ddGroup) {
48859 if (ddGroup instanceof Array) {
48860 Roo.each(ddGroup, this.setDraggable, this);
48863 if (this.dragZone) {
48864 this.dragZone.addToGroup(ddGroup);
48866 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48867 containerScroll: true,
48871 // Draggability implies selection. DragZone's mousedown selects the element.
48872 if (!this.multiSelect) { this.singleSelect = true; }
48874 // Wire the DragZone's handlers up to methods in *this*
48875 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48879 /** Specify from which ddGroup this DDView accepts drops. */
48880 setDroppable: function(ddGroup) {
48881 if (ddGroup instanceof Array) {
48882 Roo.each(ddGroup, this.setDroppable, this);
48885 if (this.dropZone) {
48886 this.dropZone.addToGroup(ddGroup);
48888 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48889 containerScroll: true,
48893 // Wire the DropZone's handlers up to methods in *this*
48894 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48895 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48896 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48897 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48898 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48902 /** Decide whether to drop above or below a View node. */
48903 getDropPoint : function(e, n, dd){
48904 if (n == this.el.dom) { return "above"; }
48905 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48906 var c = t + (b - t) / 2;
48907 var y = Roo.lib.Event.getPageY(e);
48915 onNodeEnter : function(n, dd, e, data){
48919 onNodeOver : function(n, dd, e, data){
48920 var pt = this.getDropPoint(e, n, dd);
48921 // set the insert point style on the target node
48922 var dragElClass = this.dropNotAllowed;
48925 if (pt == "above"){
48926 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48927 targetElClass = "x-view-drag-insert-above";
48929 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48930 targetElClass = "x-view-drag-insert-below";
48932 if (this.lastInsertClass != targetElClass){
48933 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48934 this.lastInsertClass = targetElClass;
48937 return dragElClass;
48940 onNodeOut : function(n, dd, e, data){
48941 this.removeDropIndicators(n);
48944 onNodeDrop : function(n, dd, e, data){
48945 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48948 var pt = this.getDropPoint(e, n, dd);
48949 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48950 if (pt == "below") { insertAt++; }
48951 for (var i = 0; i < data.records.length; i++) {
48952 var r = data.records[i];
48953 var dup = this.store.getById(r.id);
48954 if (dup && (dd != this.dragZone)) {
48955 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48958 this.store.insert(insertAt++, r.copy());
48960 data.source.isDirtyFlag = true;
48962 this.store.insert(insertAt++, r);
48964 this.isDirtyFlag = true;
48967 this.dragZone.cachedTarget = null;
48971 removeDropIndicators : function(n){
48973 Roo.fly(n).removeClass([
48974 "x-view-drag-insert-above",
48975 "x-view-drag-insert-below"]);
48976 this.lastInsertClass = "_noclass";
48981 * Utility method. Add a delete option to the DDView's context menu.
48982 * @param {String} imageUrl The URL of the "delete" icon image.
48984 setDeletable: function(imageUrl) {
48985 if (!this.singleSelect && !this.multiSelect) {
48986 this.singleSelect = true;
48988 var c = this.getContextMenu();
48989 this.contextMenu.on("itemclick", function(item) {
48992 this.remove(this.getSelectedIndexes());
48996 this.contextMenu.add({
49003 /** Return the context menu for this DDView. */
49004 getContextMenu: function() {
49005 if (!this.contextMenu) {
49006 // Create the View's context menu
49007 this.contextMenu = new Roo.menu.Menu({
49008 id: this.id + "-contextmenu"
49010 this.el.on("contextmenu", this.showContextMenu, this);
49012 return this.contextMenu;
49015 disableContextMenu: function() {
49016 if (this.contextMenu) {
49017 this.el.un("contextmenu", this.showContextMenu, this);
49021 showContextMenu: function(e, item) {
49022 item = this.findItemFromChild(e.getTarget());
49025 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49026 this.contextMenu.showAt(e.getXY());
49031 * Remove {@link Roo.data.Record}s at the specified indices.
49032 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49034 remove: function(selectedIndices) {
49035 selectedIndices = [].concat(selectedIndices);
49036 for (var i = 0; i < selectedIndices.length; i++) {
49037 var rec = this.store.getAt(selectedIndices[i]);
49038 this.store.remove(rec);
49043 * Double click fires the event, but also, if this is draggable, and there is only one other
49044 * related DropZone, it transfers the selected node.
49046 onDblClick : function(e){
49047 var item = this.findItemFromChild(e.getTarget());
49049 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49052 if (this.dragGroup) {
49053 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49054 while (targets.indexOf(this.dropZone) > -1) {
49055 targets.remove(this.dropZone);
49057 if (targets.length == 1) {
49058 this.dragZone.cachedTarget = null;
49059 var el = Roo.get(targets[0].getEl());
49060 var box = el.getBox(true);
49061 targets[0].onNodeDrop(el.dom, {
49063 xy: [box.x, box.y + box.height - 1]
49064 }, null, this.getDragData(e));
49070 handleSelection: function(e) {
49071 this.dragZone.cachedTarget = null;
49072 var item = this.findItemFromChild(e.getTarget());
49074 this.clearSelections(true);
49077 if (item && (this.multiSelect || this.singleSelect)){
49078 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49079 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49080 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49081 this.unselect(item);
49083 this.select(item, this.multiSelect && e.ctrlKey);
49084 this.lastSelection = item;
49089 onItemClick : function(item, index, e){
49090 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49096 unselect : function(nodeInfo, suppressEvent){
49097 var node = this.getNode(nodeInfo);
49098 if(node && this.isSelected(node)){
49099 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49100 Roo.fly(node).removeClass(this.selectedClass);
49101 this.selections.remove(node);
49102 if(!suppressEvent){
49103 this.fireEvent("selectionchange", this, this.selections);
49111 * Ext JS Library 1.1.1
49112 * Copyright(c) 2006-2007, Ext JS, LLC.
49114 * Originally Released Under LGPL - original licence link has changed is not relivant.
49117 * <script type="text/javascript">
49121 * @class Roo.LayoutManager
49122 * @extends Roo.util.Observable
49123 * Base class for layout managers.
49125 Roo.LayoutManager = function(container, config){
49126 Roo.LayoutManager.superclass.constructor.call(this);
49127 this.el = Roo.get(container);
49128 // ie scrollbar fix
49129 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49130 document.body.scroll = "no";
49131 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49132 this.el.position('relative');
49134 this.id = this.el.id;
49135 this.el.addClass("x-layout-container");
49136 /** false to disable window resize monitoring @type Boolean */
49137 this.monitorWindowResize = true;
49142 * Fires when a layout is performed.
49143 * @param {Roo.LayoutManager} this
49147 * @event regionresized
49148 * Fires when the user resizes a region.
49149 * @param {Roo.LayoutRegion} region The resized region
49150 * @param {Number} newSize The new size (width for east/west, height for north/south)
49152 "regionresized" : true,
49154 * @event regioncollapsed
49155 * Fires when a region is collapsed.
49156 * @param {Roo.LayoutRegion} region The collapsed region
49158 "regioncollapsed" : true,
49160 * @event regionexpanded
49161 * Fires when a region is expanded.
49162 * @param {Roo.LayoutRegion} region The expanded region
49164 "regionexpanded" : true
49166 this.updating = false;
49167 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49170 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49172 * Returns true if this layout is currently being updated
49173 * @return {Boolean}
49175 isUpdating : function(){
49176 return this.updating;
49180 * Suspend the LayoutManager from doing auto-layouts while
49181 * making multiple add or remove calls
49183 beginUpdate : function(){
49184 this.updating = true;
49188 * Restore auto-layouts and optionally disable the manager from performing a layout
49189 * @param {Boolean} noLayout true to disable a layout update
49191 endUpdate : function(noLayout){
49192 this.updating = false;
49198 layout: function(){
49202 onRegionResized : function(region, newSize){
49203 this.fireEvent("regionresized", region, newSize);
49207 onRegionCollapsed : function(region){
49208 this.fireEvent("regioncollapsed", region);
49211 onRegionExpanded : function(region){
49212 this.fireEvent("regionexpanded", region);
49216 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49217 * performs box-model adjustments.
49218 * @return {Object} The size as an object {width: (the width), height: (the height)}
49220 getViewSize : function(){
49222 if(this.el.dom != document.body){
49223 size = this.el.getSize();
49225 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49227 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49228 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49233 * Returns the Element this layout is bound to.
49234 * @return {Roo.Element}
49236 getEl : function(){
49241 * Returns the specified region.
49242 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49243 * @return {Roo.LayoutRegion}
49245 getRegion : function(target){
49246 return this.regions[target.toLowerCase()];
49249 onWindowResize : function(){
49250 if(this.monitorWindowResize){
49256 * Ext JS Library 1.1.1
49257 * Copyright(c) 2006-2007, Ext JS, LLC.
49259 * Originally Released Under LGPL - original licence link has changed is not relivant.
49262 * <script type="text/javascript">
49265 * @class Roo.BorderLayout
49266 * @extends Roo.LayoutManager
49267 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49268 * please see: <br><br>
49269 * <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>
49270 * <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>
49273 var layout = new Roo.BorderLayout(document.body, {
49307 preferredTabWidth: 150
49312 var CP = Roo.ContentPanel;
49314 layout.beginUpdate();
49315 layout.add("north", new CP("north", "North"));
49316 layout.add("south", new CP("south", {title: "South", closable: true}));
49317 layout.add("west", new CP("west", {title: "West"}));
49318 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49319 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49320 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49321 layout.getRegion("center").showPanel("center1");
49322 layout.endUpdate();
49325 <b>The container the layout is rendered into can be either the body element or any other element.
49326 If it is not the body element, the container needs to either be an absolute positioned element,
49327 or you will need to add "position:relative" to the css of the container. You will also need to specify
49328 the container size if it is not the body element.</b>
49331 * Create a new BorderLayout
49332 * @param {String/HTMLElement/Element} container The container this layout is bound to
49333 * @param {Object} config Configuration options
49335 Roo.BorderLayout = function(container, config){
49336 config = config || {};
49337 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49338 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49339 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49340 var target = this.factory.validRegions[i];
49341 if(config[target]){
49342 this.addRegion(target, config[target]);
49347 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49349 * Creates and adds a new region if it doesn't already exist.
49350 * @param {String} target The target region key (north, south, east, west or center).
49351 * @param {Object} config The regions config object
49352 * @return {BorderLayoutRegion} The new region
49354 addRegion : function(target, config){
49355 if(!this.regions[target]){
49356 var r = this.factory.create(target, this, config);
49357 this.bindRegion(target, r);
49359 return this.regions[target];
49363 bindRegion : function(name, r){
49364 this.regions[name] = r;
49365 r.on("visibilitychange", this.layout, this);
49366 r.on("paneladded", this.layout, this);
49367 r.on("panelremoved", this.layout, this);
49368 r.on("invalidated", this.layout, this);
49369 r.on("resized", this.onRegionResized, this);
49370 r.on("collapsed", this.onRegionCollapsed, this);
49371 r.on("expanded", this.onRegionExpanded, this);
49375 * Performs a layout update.
49377 layout : function(){
49378 if(this.updating) return;
49379 var size = this.getViewSize();
49380 var w = size.width;
49381 var h = size.height;
49386 //var x = 0, y = 0;
49388 var rs = this.regions;
49389 var north = rs["north"];
49390 var south = rs["south"];
49391 var west = rs["west"];
49392 var east = rs["east"];
49393 var center = rs["center"];
49394 //if(this.hideOnLayout){ // not supported anymore
49395 //c.el.setStyle("display", "none");
49397 if(north && north.isVisible()){
49398 var b = north.getBox();
49399 var m = north.getMargins();
49400 b.width = w - (m.left+m.right);
49403 centerY = b.height + b.y + m.bottom;
49404 centerH -= centerY;
49405 north.updateBox(this.safeBox(b));
49407 if(south && south.isVisible()){
49408 var b = south.getBox();
49409 var m = south.getMargins();
49410 b.width = w - (m.left+m.right);
49412 var totalHeight = (b.height + m.top + m.bottom);
49413 b.y = h - totalHeight + m.top;
49414 centerH -= totalHeight;
49415 south.updateBox(this.safeBox(b));
49417 if(west && west.isVisible()){
49418 var b = west.getBox();
49419 var m = west.getMargins();
49420 b.height = centerH - (m.top+m.bottom);
49422 b.y = centerY + m.top;
49423 var totalWidth = (b.width + m.left + m.right);
49424 centerX += totalWidth;
49425 centerW -= totalWidth;
49426 west.updateBox(this.safeBox(b));
49428 if(east && east.isVisible()){
49429 var b = east.getBox();
49430 var m = east.getMargins();
49431 b.height = centerH - (m.top+m.bottom);
49432 var totalWidth = (b.width + m.left + m.right);
49433 b.x = w - totalWidth + m.left;
49434 b.y = centerY + m.top;
49435 centerW -= totalWidth;
49436 east.updateBox(this.safeBox(b));
49439 var m = center.getMargins();
49441 x: centerX + m.left,
49442 y: centerY + m.top,
49443 width: centerW - (m.left+m.right),
49444 height: centerH - (m.top+m.bottom)
49446 //if(this.hideOnLayout){
49447 //center.el.setStyle("display", "block");
49449 center.updateBox(this.safeBox(centerBox));
49452 this.fireEvent("layout", this);
49456 safeBox : function(box){
49457 box.width = Math.max(0, box.width);
49458 box.height = Math.max(0, box.height);
49463 * Adds a ContentPanel (or subclass) to this layout.
49464 * @param {String} target The target region key (north, south, east, west or center).
49465 * @param {Roo.ContentPanel} panel The panel to add
49466 * @return {Roo.ContentPanel} The added panel
49468 add : function(target, panel){
49470 target = target.toLowerCase();
49471 return this.regions[target].add(panel);
49475 * Remove a ContentPanel (or subclass) to this layout.
49476 * @param {String} target The target region key (north, south, east, west or center).
49477 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49478 * @return {Roo.ContentPanel} The removed panel
49480 remove : function(target, panel){
49481 target = target.toLowerCase();
49482 return this.regions[target].remove(panel);
49486 * Searches all regions for a panel with the specified id
49487 * @param {String} panelId
49488 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49490 findPanel : function(panelId){
49491 var rs = this.regions;
49492 for(var target in rs){
49493 if(typeof rs[target] != "function"){
49494 var p = rs[target].getPanel(panelId);
49504 * Searches all regions for a panel with the specified id and activates (shows) it.
49505 * @param {String/ContentPanel} panelId The panels id or the panel itself
49506 * @return {Roo.ContentPanel} The shown panel or null
49508 showPanel : function(panelId) {
49509 var rs = this.regions;
49510 for(var target in rs){
49511 var r = rs[target];
49512 if(typeof r != "function"){
49513 if(r.hasPanel(panelId)){
49514 return r.showPanel(panelId);
49522 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49523 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49525 restoreState : function(provider){
49527 provider = Roo.state.Manager;
49529 var sm = new Roo.LayoutStateManager();
49530 sm.init(this, provider);
49534 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49535 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49536 * a valid ContentPanel config object. Example:
49538 // Create the main layout
49539 var layout = new Roo.BorderLayout('main-ct', {
49550 // Create and add multiple ContentPanels at once via configs
49553 id: 'source-files',
49555 title:'Ext Source Files',
49568 * @param {Object} regions An object containing ContentPanel configs by region name
49570 batchAdd : function(regions){
49571 this.beginUpdate();
49572 for(var rname in regions){
49573 var lr = this.regions[rname];
49575 this.addTypedPanels(lr, regions[rname]);
49582 addTypedPanels : function(lr, ps){
49583 if(typeof ps == 'string'){
49584 lr.add(new Roo.ContentPanel(ps));
49586 else if(ps instanceof Array){
49587 for(var i =0, len = ps.length; i < len; i++){
49588 this.addTypedPanels(lr, ps[i]);
49591 else if(!ps.events){ // raw config?
49593 delete ps.el; // prevent conflict
49594 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49596 else { // panel object assumed!
49601 * Adds a xtype elements to the layout.
49605 xtype : 'ContentPanel',
49612 xtype : 'NestedLayoutPanel',
49618 items : [ ... list of content panels or nested layout panels.. ]
49622 * @param {Object} cfg Xtype definition of item to add.
49624 addxtype : function(cfg)
49626 // basically accepts a pannel...
49627 // can accept a layout region..!?!?
49628 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49630 if (!cfg.xtype.match(/Panel$/)) {
49635 if (typeof(cfg.region) == 'undefined') {
49636 Roo.log("Failed to add Panel, region was not set");
49640 var region = cfg.region;
49646 xitems = cfg.items;
49653 case 'ContentPanel': // ContentPanel (el, cfg)
49654 case 'ScrollPanel': // ContentPanel (el, cfg)
49656 if(cfg.autoCreate) {
49657 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49659 var el = this.el.createChild();
49660 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49663 this.add(region, ret);
49667 case 'TreePanel': // our new panel!
49668 cfg.el = this.el.createChild();
49669 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49670 this.add(region, ret);
49673 case 'NestedLayoutPanel':
49674 // create a new Layout (which is a Border Layout...
49675 var el = this.el.createChild();
49676 var clayout = cfg.layout;
49678 clayout.items = clayout.items || [];
49679 // replace this exitems with the clayout ones..
49680 xitems = clayout.items;
49683 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49684 cfg.background = false;
49686 var layout = new Roo.BorderLayout(el, clayout);
49688 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49689 //console.log('adding nested layout panel ' + cfg.toSource());
49690 this.add(region, ret);
49691 nb = {}; /// find first...
49696 // needs grid and region
49698 //var el = this.getRegion(region).el.createChild();
49699 var el = this.el.createChild();
49700 // create the grid first...
49702 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49704 if (region == 'center' && this.active ) {
49705 cfg.background = false;
49707 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49709 this.add(region, ret);
49710 if (cfg.background) {
49711 ret.on('activate', function(gp) {
49712 if (!gp.grid.rendered) {
49727 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49729 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49730 this.add(region, ret);
49733 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49737 // GridPanel (grid, cfg)
49740 this.beginUpdate();
49744 Roo.each(xitems, function(i) {
49745 region = nb && i.region ? i.region : false;
49747 var add = ret.addxtype(i);
49750 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49751 if (!i.background) {
49752 abn[region] = nb[region] ;
49759 // make the last non-background panel active..
49760 //if (nb) { Roo.log(abn); }
49763 for(var r in abn) {
49764 region = this.getRegion(r);
49766 // tried using nb[r], but it does not work..
49768 region.showPanel(abn[r]);
49779 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49780 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49781 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49782 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49785 var CP = Roo.ContentPanel;
49787 var layout = Roo.BorderLayout.create({
49791 panels: [new CP("north", "North")]
49800 panels: [new CP("west", {title: "West"})]
49809 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49818 panels: [new CP("south", {title: "South", closable: true})]
49825 preferredTabWidth: 150,
49827 new CP("center1", {title: "Close Me", closable: true}),
49828 new CP("center2", {title: "Center Panel", closable: false})
49833 layout.getRegion("center").showPanel("center1");
49838 Roo.BorderLayout.create = function(config, targetEl){
49839 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49840 layout.beginUpdate();
49841 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49842 for(var j = 0, jlen = regions.length; j < jlen; j++){
49843 var lr = regions[j];
49844 if(layout.regions[lr] && config[lr].panels){
49845 var r = layout.regions[lr];
49846 var ps = config[lr].panels;
49847 layout.addTypedPanels(r, ps);
49850 layout.endUpdate();
49855 Roo.BorderLayout.RegionFactory = {
49857 validRegions : ["north","south","east","west","center"],
49860 create : function(target, mgr, config){
49861 target = target.toLowerCase();
49862 if(config.lightweight || config.basic){
49863 return new Roo.BasicLayoutRegion(mgr, config, target);
49867 return new Roo.NorthLayoutRegion(mgr, config);
49869 return new Roo.SouthLayoutRegion(mgr, config);
49871 return new Roo.EastLayoutRegion(mgr, config);
49873 return new Roo.WestLayoutRegion(mgr, config);
49875 return new Roo.CenterLayoutRegion(mgr, config);
49877 throw 'Layout region "'+target+'" not supported.';
49881 * Ext JS Library 1.1.1
49882 * Copyright(c) 2006-2007, Ext JS, LLC.
49884 * Originally Released Under LGPL - original licence link has changed is not relivant.
49887 * <script type="text/javascript">
49891 * @class Roo.BasicLayoutRegion
49892 * @extends Roo.util.Observable
49893 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49894 * and does not have a titlebar, tabs or any other features. All it does is size and position
49895 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49897 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49899 this.position = pos;
49902 * @scope Roo.BasicLayoutRegion
49906 * @event beforeremove
49907 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49908 * @param {Roo.LayoutRegion} this
49909 * @param {Roo.ContentPanel} panel The panel
49910 * @param {Object} e The cancel event object
49912 "beforeremove" : true,
49914 * @event invalidated
49915 * Fires when the layout for this region is changed.
49916 * @param {Roo.LayoutRegion} this
49918 "invalidated" : true,
49920 * @event visibilitychange
49921 * Fires when this region is shown or hidden
49922 * @param {Roo.LayoutRegion} this
49923 * @param {Boolean} visibility true or false
49925 "visibilitychange" : true,
49927 * @event paneladded
49928 * Fires when a panel is added.
49929 * @param {Roo.LayoutRegion} this
49930 * @param {Roo.ContentPanel} panel The panel
49932 "paneladded" : true,
49934 * @event panelremoved
49935 * Fires when a panel is removed.
49936 * @param {Roo.LayoutRegion} this
49937 * @param {Roo.ContentPanel} panel The panel
49939 "panelremoved" : true,
49942 * Fires when this region is collapsed.
49943 * @param {Roo.LayoutRegion} this
49945 "collapsed" : true,
49948 * Fires when this region is expanded.
49949 * @param {Roo.LayoutRegion} this
49954 * Fires when this region is slid into view.
49955 * @param {Roo.LayoutRegion} this
49957 "slideshow" : true,
49960 * Fires when this region slides out of view.
49961 * @param {Roo.LayoutRegion} this
49963 "slidehide" : true,
49965 * @event panelactivated
49966 * Fires when a panel is activated.
49967 * @param {Roo.LayoutRegion} this
49968 * @param {Roo.ContentPanel} panel The activated panel
49970 "panelactivated" : true,
49973 * Fires when the user resizes this region.
49974 * @param {Roo.LayoutRegion} this
49975 * @param {Number} newSize The new size (width for east/west, height for north/south)
49979 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49980 this.panels = new Roo.util.MixedCollection();
49981 this.panels.getKey = this.getPanelId.createDelegate(this);
49983 this.activePanel = null;
49984 // ensure listeners are added...
49986 if (config.listeners || config.events) {
49987 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49988 listeners : config.listeners || {},
49989 events : config.events || {}
49993 if(skipConfig !== true){
49994 this.applyConfig(config);
49998 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49999 getPanelId : function(p){
50003 applyConfig : function(config){
50004 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50005 this.config = config;
50010 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
50011 * the width, for horizontal (north, south) the height.
50012 * @param {Number} newSize The new width or height
50014 resizeTo : function(newSize){
50015 var el = this.el ? this.el :
50016 (this.activePanel ? this.activePanel.getEl() : null);
50018 switch(this.position){
50021 el.setWidth(newSize);
50022 this.fireEvent("resized", this, newSize);
50026 el.setHeight(newSize);
50027 this.fireEvent("resized", this, newSize);
50033 getBox : function(){
50034 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50037 getMargins : function(){
50038 return this.margins;
50041 updateBox : function(box){
50043 var el = this.activePanel.getEl();
50044 el.dom.style.left = box.x + "px";
50045 el.dom.style.top = box.y + "px";
50046 this.activePanel.setSize(box.width, box.height);
50050 * Returns the container element for this region.
50051 * @return {Roo.Element}
50053 getEl : function(){
50054 return this.activePanel;
50058 * Returns true if this region is currently visible.
50059 * @return {Boolean}
50061 isVisible : function(){
50062 return this.activePanel ? true : false;
50065 setActivePanel : function(panel){
50066 panel = this.getPanel(panel);
50067 if(this.activePanel && this.activePanel != panel){
50068 this.activePanel.setActiveState(false);
50069 this.activePanel.getEl().setLeftTop(-10000,-10000);
50071 this.activePanel = panel;
50072 panel.setActiveState(true);
50074 panel.setSize(this.box.width, this.box.height);
50076 this.fireEvent("panelactivated", this, panel);
50077 this.fireEvent("invalidated");
50081 * Show the specified panel.
50082 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50083 * @return {Roo.ContentPanel} The shown panel or null
50085 showPanel : function(panel){
50086 if(panel = this.getPanel(panel)){
50087 this.setActivePanel(panel);
50093 * Get the active panel for this region.
50094 * @return {Roo.ContentPanel} The active panel or null
50096 getActivePanel : function(){
50097 return this.activePanel;
50101 * Add the passed ContentPanel(s)
50102 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50103 * @return {Roo.ContentPanel} The panel added (if only one was added)
50105 add : function(panel){
50106 if(arguments.length > 1){
50107 for(var i = 0, len = arguments.length; i < len; i++) {
50108 this.add(arguments[i]);
50112 if(this.hasPanel(panel)){
50113 this.showPanel(panel);
50116 var el = panel.getEl();
50117 if(el.dom.parentNode != this.mgr.el.dom){
50118 this.mgr.el.dom.appendChild(el.dom);
50120 if(panel.setRegion){
50121 panel.setRegion(this);
50123 this.panels.add(panel);
50124 el.setStyle("position", "absolute");
50125 if(!panel.background){
50126 this.setActivePanel(panel);
50127 if(this.config.initialSize && this.panels.getCount()==1){
50128 this.resizeTo(this.config.initialSize);
50131 this.fireEvent("paneladded", this, panel);
50136 * Returns true if the panel is in this region.
50137 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50138 * @return {Boolean}
50140 hasPanel : function(panel){
50141 if(typeof panel == "object"){ // must be panel obj
50142 panel = panel.getId();
50144 return this.getPanel(panel) ? true : false;
50148 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50149 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50150 * @param {Boolean} preservePanel Overrides the config preservePanel option
50151 * @return {Roo.ContentPanel} The panel that was removed
50153 remove : function(panel, preservePanel){
50154 panel = this.getPanel(panel);
50159 this.fireEvent("beforeremove", this, panel, e);
50160 if(e.cancel === true){
50163 var panelId = panel.getId();
50164 this.panels.removeKey(panelId);
50169 * Returns the panel specified or null if it's not in this region.
50170 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50171 * @return {Roo.ContentPanel}
50173 getPanel : function(id){
50174 if(typeof id == "object"){ // must be panel obj
50177 return this.panels.get(id);
50181 * Returns this regions position (north/south/east/west/center).
50184 getPosition: function(){
50185 return this.position;
50189 * Ext JS Library 1.1.1
50190 * Copyright(c) 2006-2007, Ext JS, LLC.
50192 * Originally Released Under LGPL - original licence link has changed is not relivant.
50195 * <script type="text/javascript">
50199 * @class Roo.LayoutRegion
50200 * @extends Roo.BasicLayoutRegion
50201 * This class represents a region in a layout manager.
50202 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50203 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50204 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50205 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50206 * @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})
50207 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50208 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50209 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50210 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50211 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50212 * @cfg {String} title The title for the region (overrides panel titles)
50213 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50214 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50215 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50216 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50217 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50218 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50219 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50220 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50221 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50222 * @cfg {Boolean} showPin True to show a pin button
50223 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50224 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50225 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50226 * @cfg {Number} width For East/West panels
50227 * @cfg {Number} height For North/South panels
50228 * @cfg {Boolean} split To show the splitter
50229 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50231 Roo.LayoutRegion = function(mgr, config, pos){
50232 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50233 var dh = Roo.DomHelper;
50234 /** This region's container element
50235 * @type Roo.Element */
50236 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50237 /** This region's title element
50238 * @type Roo.Element */
50240 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50241 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50242 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50244 this.titleEl.enableDisplayMode();
50245 /** This region's title text element
50246 * @type HTMLElement */
50247 this.titleTextEl = this.titleEl.dom.firstChild;
50248 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50249 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50250 this.closeBtn.enableDisplayMode();
50251 this.closeBtn.on("click", this.closeClicked, this);
50252 this.closeBtn.hide();
50254 this.createBody(config);
50255 this.visible = true;
50256 this.collapsed = false;
50258 if(config.hideWhenEmpty){
50260 this.on("paneladded", this.validateVisibility, this);
50261 this.on("panelremoved", this.validateVisibility, this);
50263 this.applyConfig(config);
50266 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50268 createBody : function(){
50269 /** This region's body element
50270 * @type Roo.Element */
50271 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50274 applyConfig : function(c){
50275 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50276 var dh = Roo.DomHelper;
50277 if(c.titlebar !== false){
50278 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50279 this.collapseBtn.on("click", this.collapse, this);
50280 this.collapseBtn.enableDisplayMode();
50282 if(c.showPin === true || this.showPin){
50283 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50284 this.stickBtn.enableDisplayMode();
50285 this.stickBtn.on("click", this.expand, this);
50286 this.stickBtn.hide();
50289 /** This region's collapsed element
50290 * @type Roo.Element */
50291 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50292 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50294 if(c.floatable !== false){
50295 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50296 this.collapsedEl.on("click", this.collapseClick, this);
50299 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50300 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50301 id: "message", unselectable: "on", style:{"float":"left"}});
50302 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50304 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50305 this.expandBtn.on("click", this.expand, this);
50307 if(this.collapseBtn){
50308 this.collapseBtn.setVisible(c.collapsible == true);
50310 this.cmargins = c.cmargins || this.cmargins ||
50311 (this.position == "west" || this.position == "east" ?
50312 {top: 0, left: 2, right:2, bottom: 0} :
50313 {top: 2, left: 0, right:0, bottom: 2});
50314 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50315 this.bottomTabs = c.tabPosition != "top";
50316 this.autoScroll = c.autoScroll || false;
50317 if(this.autoScroll){
50318 this.bodyEl.setStyle("overflow", "auto");
50320 this.bodyEl.setStyle("overflow", "hidden");
50322 //if(c.titlebar !== false){
50323 if((!c.titlebar && !c.title) || c.titlebar === false){
50324 this.titleEl.hide();
50326 this.titleEl.show();
50328 this.titleTextEl.innerHTML = c.title;
50332 this.duration = c.duration || .30;
50333 this.slideDuration = c.slideDuration || .45;
50336 this.collapse(true);
50343 * Returns true if this region is currently visible.
50344 * @return {Boolean}
50346 isVisible : function(){
50347 return this.visible;
50351 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50352 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50354 setCollapsedTitle : function(title){
50355 title = title || " ";
50356 if(this.collapsedTitleTextEl){
50357 this.collapsedTitleTextEl.innerHTML = title;
50361 getBox : function(){
50363 if(!this.collapsed){
50364 b = this.el.getBox(false, true);
50366 b = this.collapsedEl.getBox(false, true);
50371 getMargins : function(){
50372 return this.collapsed ? this.cmargins : this.margins;
50375 highlight : function(){
50376 this.el.addClass("x-layout-panel-dragover");
50379 unhighlight : function(){
50380 this.el.removeClass("x-layout-panel-dragover");
50383 updateBox : function(box){
50385 if(!this.collapsed){
50386 this.el.dom.style.left = box.x + "px";
50387 this.el.dom.style.top = box.y + "px";
50388 this.updateBody(box.width, box.height);
50390 this.collapsedEl.dom.style.left = box.x + "px";
50391 this.collapsedEl.dom.style.top = box.y + "px";
50392 this.collapsedEl.setSize(box.width, box.height);
50395 this.tabs.autoSizeTabs();
50399 updateBody : function(w, h){
50401 this.el.setWidth(w);
50402 w -= this.el.getBorderWidth("rl");
50403 if(this.config.adjustments){
50404 w += this.config.adjustments[0];
50408 this.el.setHeight(h);
50409 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50410 h -= this.el.getBorderWidth("tb");
50411 if(this.config.adjustments){
50412 h += this.config.adjustments[1];
50414 this.bodyEl.setHeight(h);
50416 h = this.tabs.syncHeight(h);
50419 if(this.panelSize){
50420 w = w !== null ? w : this.panelSize.width;
50421 h = h !== null ? h : this.panelSize.height;
50423 if(this.activePanel){
50424 var el = this.activePanel.getEl();
50425 w = w !== null ? w : el.getWidth();
50426 h = h !== null ? h : el.getHeight();
50427 this.panelSize = {width: w, height: h};
50428 this.activePanel.setSize(w, h);
50430 if(Roo.isIE && this.tabs){
50431 this.tabs.el.repaint();
50436 * Returns the container element for this region.
50437 * @return {Roo.Element}
50439 getEl : function(){
50444 * Hides this region.
50447 if(!this.collapsed){
50448 this.el.dom.style.left = "-2000px";
50451 this.collapsedEl.dom.style.left = "-2000px";
50452 this.collapsedEl.hide();
50454 this.visible = false;
50455 this.fireEvent("visibilitychange", this, false);
50459 * Shows this region if it was previously hidden.
50462 if(!this.collapsed){
50465 this.collapsedEl.show();
50467 this.visible = true;
50468 this.fireEvent("visibilitychange", this, true);
50471 closeClicked : function(){
50472 if(this.activePanel){
50473 this.remove(this.activePanel);
50477 collapseClick : function(e){
50479 e.stopPropagation();
50482 e.stopPropagation();
50488 * Collapses this region.
50489 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50491 collapse : function(skipAnim){
50492 if(this.collapsed) return;
50493 this.collapsed = true;
50495 this.split.el.hide();
50497 if(this.config.animate && skipAnim !== true){
50498 this.fireEvent("invalidated", this);
50499 this.animateCollapse();
50501 this.el.setLocation(-20000,-20000);
50503 this.collapsedEl.show();
50504 this.fireEvent("collapsed", this);
50505 this.fireEvent("invalidated", this);
50509 animateCollapse : function(){
50514 * Expands this region if it was previously collapsed.
50515 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50516 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50518 expand : function(e, skipAnim){
50519 if(e) e.stopPropagation();
50520 if(!this.collapsed || this.el.hasActiveFx()) return;
50522 this.afterSlideIn();
50525 this.collapsed = false;
50526 if(this.config.animate && skipAnim !== true){
50527 this.animateExpand();
50531 this.split.el.show();
50533 this.collapsedEl.setLocation(-2000,-2000);
50534 this.collapsedEl.hide();
50535 this.fireEvent("invalidated", this);
50536 this.fireEvent("expanded", this);
50540 animateExpand : function(){
50544 initTabs : function()
50546 this.bodyEl.setStyle("overflow", "hidden");
50547 var ts = new Roo.TabPanel(
50550 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50551 disableTooltips: this.config.disableTabTips,
50552 toolbar : this.config.toolbar
50555 if(this.config.hideTabs){
50556 ts.stripWrap.setDisplayed(false);
50559 ts.resizeTabs = this.config.resizeTabs === true;
50560 ts.minTabWidth = this.config.minTabWidth || 40;
50561 ts.maxTabWidth = this.config.maxTabWidth || 250;
50562 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50563 ts.monitorResize = false;
50564 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50565 ts.bodyEl.addClass('x-layout-tabs-body');
50566 this.panels.each(this.initPanelAsTab, this);
50569 initPanelAsTab : function(panel){
50570 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50571 this.config.closeOnTab && panel.isClosable());
50572 if(panel.tabTip !== undefined){
50573 ti.setTooltip(panel.tabTip);
50575 ti.on("activate", function(){
50576 this.setActivePanel(panel);
50578 if(this.config.closeOnTab){
50579 ti.on("beforeclose", function(t, e){
50581 this.remove(panel);
50587 updatePanelTitle : function(panel, title){
50588 if(this.activePanel == panel){
50589 this.updateTitle(title);
50592 var ti = this.tabs.getTab(panel.getEl().id);
50594 if(panel.tabTip !== undefined){
50595 ti.setTooltip(panel.tabTip);
50600 updateTitle : function(title){
50601 if(this.titleTextEl && !this.config.title){
50602 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50606 setActivePanel : function(panel){
50607 panel = this.getPanel(panel);
50608 if(this.activePanel && this.activePanel != panel){
50609 this.activePanel.setActiveState(false);
50611 this.activePanel = panel;
50612 panel.setActiveState(true);
50613 if(this.panelSize){
50614 panel.setSize(this.panelSize.width, this.panelSize.height);
50617 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50619 this.updateTitle(panel.getTitle());
50621 this.fireEvent("invalidated", this);
50623 this.fireEvent("panelactivated", this, panel);
50627 * Shows the specified panel.
50628 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50629 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50631 showPanel : function(panel)
50633 panel = this.getPanel(panel);
50636 var tab = this.tabs.getTab(panel.getEl().id);
50637 if(tab.isHidden()){
50638 this.tabs.unhideTab(tab.id);
50642 this.setActivePanel(panel);
50649 * Get the active panel for this region.
50650 * @return {Roo.ContentPanel} The active panel or null
50652 getActivePanel : function(){
50653 return this.activePanel;
50656 validateVisibility : function(){
50657 if(this.panels.getCount() < 1){
50658 this.updateTitle(" ");
50659 this.closeBtn.hide();
50662 if(!this.isVisible()){
50669 * Adds the passed ContentPanel(s) to this region.
50670 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50671 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50673 add : function(panel){
50674 if(arguments.length > 1){
50675 for(var i = 0, len = arguments.length; i < len; i++) {
50676 this.add(arguments[i]);
50680 if(this.hasPanel(panel)){
50681 this.showPanel(panel);
50684 panel.setRegion(this);
50685 this.panels.add(panel);
50686 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50687 this.bodyEl.dom.appendChild(panel.getEl().dom);
50688 if(panel.background !== true){
50689 this.setActivePanel(panel);
50691 this.fireEvent("paneladded", this, panel);
50697 this.initPanelAsTab(panel);
50699 if(panel.background !== true){
50700 this.tabs.activate(panel.getEl().id);
50702 this.fireEvent("paneladded", this, panel);
50707 * Hides the tab for the specified panel.
50708 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50710 hidePanel : function(panel){
50711 if(this.tabs && (panel = this.getPanel(panel))){
50712 this.tabs.hideTab(panel.getEl().id);
50717 * Unhides the tab for a previously hidden panel.
50718 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50720 unhidePanel : function(panel){
50721 if(this.tabs && (panel = this.getPanel(panel))){
50722 this.tabs.unhideTab(panel.getEl().id);
50726 clearPanels : function(){
50727 while(this.panels.getCount() > 0){
50728 this.remove(this.panels.first());
50733 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50734 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50735 * @param {Boolean} preservePanel Overrides the config preservePanel option
50736 * @return {Roo.ContentPanel} The panel that was removed
50738 remove : function(panel, preservePanel){
50739 panel = this.getPanel(panel);
50744 this.fireEvent("beforeremove", this, panel, e);
50745 if(e.cancel === true){
50748 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50749 var panelId = panel.getId();
50750 this.panels.removeKey(panelId);
50752 document.body.appendChild(panel.getEl().dom);
50755 this.tabs.removeTab(panel.getEl().id);
50756 }else if (!preservePanel){
50757 this.bodyEl.dom.removeChild(panel.getEl().dom);
50759 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50760 var p = this.panels.first();
50761 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50762 tempEl.appendChild(p.getEl().dom);
50763 this.bodyEl.update("");
50764 this.bodyEl.dom.appendChild(p.getEl().dom);
50766 this.updateTitle(p.getTitle());
50768 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50769 this.setActivePanel(p);
50771 panel.setRegion(null);
50772 if(this.activePanel == panel){
50773 this.activePanel = null;
50775 if(this.config.autoDestroy !== false && preservePanel !== true){
50776 try{panel.destroy();}catch(e){}
50778 this.fireEvent("panelremoved", this, panel);
50783 * Returns the TabPanel component used by this region
50784 * @return {Roo.TabPanel}
50786 getTabs : function(){
50790 createTool : function(parentEl, className){
50791 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50792 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50793 btn.addClassOnOver("x-layout-tools-button-over");
50798 * Ext JS Library 1.1.1
50799 * Copyright(c) 2006-2007, Ext JS, LLC.
50801 * Originally Released Under LGPL - original licence link has changed is not relivant.
50804 * <script type="text/javascript">
50810 * @class Roo.SplitLayoutRegion
50811 * @extends Roo.LayoutRegion
50812 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50814 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50815 this.cursor = cursor;
50816 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50819 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50820 splitTip : "Drag to resize.",
50821 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50822 useSplitTips : false,
50824 applyConfig : function(config){
50825 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50828 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50829 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50830 /** The SplitBar for this region
50831 * @type Roo.SplitBar */
50832 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50833 this.split.on("moved", this.onSplitMove, this);
50834 this.split.useShim = config.useShim === true;
50835 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50836 if(this.useSplitTips){
50837 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50839 if(config.collapsible){
50840 this.split.el.on("dblclick", this.collapse, this);
50843 if(typeof config.minSize != "undefined"){
50844 this.split.minSize = config.minSize;
50846 if(typeof config.maxSize != "undefined"){
50847 this.split.maxSize = config.maxSize;
50849 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50850 this.hideSplitter();
50855 getHMaxSize : function(){
50856 var cmax = this.config.maxSize || 10000;
50857 var center = this.mgr.getRegion("center");
50858 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50861 getVMaxSize : function(){
50862 var cmax = this.config.maxSize || 10000;
50863 var center = this.mgr.getRegion("center");
50864 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50867 onSplitMove : function(split, newSize){
50868 this.fireEvent("resized", this, newSize);
50872 * Returns the {@link Roo.SplitBar} for this region.
50873 * @return {Roo.SplitBar}
50875 getSplitBar : function(){
50880 this.hideSplitter();
50881 Roo.SplitLayoutRegion.superclass.hide.call(this);
50884 hideSplitter : function(){
50886 this.split.el.setLocation(-2000,-2000);
50887 this.split.el.hide();
50893 this.split.el.show();
50895 Roo.SplitLayoutRegion.superclass.show.call(this);
50898 beforeSlide: function(){
50899 if(Roo.isGecko){// firefox overflow auto bug workaround
50900 this.bodyEl.clip();
50901 if(this.tabs) this.tabs.bodyEl.clip();
50902 if(this.activePanel){
50903 this.activePanel.getEl().clip();
50905 if(this.activePanel.beforeSlide){
50906 this.activePanel.beforeSlide();
50912 afterSlide : function(){
50913 if(Roo.isGecko){// firefox overflow auto bug workaround
50914 this.bodyEl.unclip();
50915 if(this.tabs) this.tabs.bodyEl.unclip();
50916 if(this.activePanel){
50917 this.activePanel.getEl().unclip();
50918 if(this.activePanel.afterSlide){
50919 this.activePanel.afterSlide();
50925 initAutoHide : function(){
50926 if(this.autoHide !== false){
50927 if(!this.autoHideHd){
50928 var st = new Roo.util.DelayedTask(this.slideIn, this);
50929 this.autoHideHd = {
50930 "mouseout": function(e){
50931 if(!e.within(this.el, true)){
50935 "mouseover" : function(e){
50941 this.el.on(this.autoHideHd);
50945 clearAutoHide : function(){
50946 if(this.autoHide !== false){
50947 this.el.un("mouseout", this.autoHideHd.mouseout);
50948 this.el.un("mouseover", this.autoHideHd.mouseover);
50952 clearMonitor : function(){
50953 Roo.get(document).un("click", this.slideInIf, this);
50956 // these names are backwards but not changed for compat
50957 slideOut : function(){
50958 if(this.isSlid || this.el.hasActiveFx()){
50961 this.isSlid = true;
50962 if(this.collapseBtn){
50963 this.collapseBtn.hide();
50965 this.closeBtnState = this.closeBtn.getStyle('display');
50966 this.closeBtn.hide();
50968 this.stickBtn.show();
50971 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50972 this.beforeSlide();
50973 this.el.setStyle("z-index", 10001);
50974 this.el.slideIn(this.getSlideAnchor(), {
50975 callback: function(){
50977 this.initAutoHide();
50978 Roo.get(document).on("click", this.slideInIf, this);
50979 this.fireEvent("slideshow", this);
50986 afterSlideIn : function(){
50987 this.clearAutoHide();
50988 this.isSlid = false;
50989 this.clearMonitor();
50990 this.el.setStyle("z-index", "");
50991 if(this.collapseBtn){
50992 this.collapseBtn.show();
50994 this.closeBtn.setStyle('display', this.closeBtnState);
50996 this.stickBtn.hide();
50998 this.fireEvent("slidehide", this);
51001 slideIn : function(cb){
51002 if(!this.isSlid || this.el.hasActiveFx()){
51006 this.isSlid = false;
51007 this.beforeSlide();
51008 this.el.slideOut(this.getSlideAnchor(), {
51009 callback: function(){
51010 this.el.setLeftTop(-10000, -10000);
51012 this.afterSlideIn();
51020 slideInIf : function(e){
51021 if(!e.within(this.el)){
51026 animateCollapse : function(){
51027 this.beforeSlide();
51028 this.el.setStyle("z-index", 20000);
51029 var anchor = this.getSlideAnchor();
51030 this.el.slideOut(anchor, {
51031 callback : function(){
51032 this.el.setStyle("z-index", "");
51033 this.collapsedEl.slideIn(anchor, {duration:.3});
51035 this.el.setLocation(-10000,-10000);
51037 this.fireEvent("collapsed", this);
51044 animateExpand : function(){
51045 this.beforeSlide();
51046 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51047 this.el.setStyle("z-index", 20000);
51048 this.collapsedEl.hide({
51051 this.el.slideIn(this.getSlideAnchor(), {
51052 callback : function(){
51053 this.el.setStyle("z-index", "");
51056 this.split.el.show();
51058 this.fireEvent("invalidated", this);
51059 this.fireEvent("expanded", this);
51087 getAnchor : function(){
51088 return this.anchors[this.position];
51091 getCollapseAnchor : function(){
51092 return this.canchors[this.position];
51095 getSlideAnchor : function(){
51096 return this.sanchors[this.position];
51099 getAlignAdj : function(){
51100 var cm = this.cmargins;
51101 switch(this.position){
51117 getExpandAdj : function(){
51118 var c = this.collapsedEl, cm = this.cmargins;
51119 switch(this.position){
51121 return [-(cm.right+c.getWidth()+cm.left), 0];
51124 return [cm.right+c.getWidth()+cm.left, 0];
51127 return [0, -(cm.top+cm.bottom+c.getHeight())];
51130 return [0, cm.top+cm.bottom+c.getHeight()];
51136 * Ext JS Library 1.1.1
51137 * Copyright(c) 2006-2007, Ext JS, LLC.
51139 * Originally Released Under LGPL - original licence link has changed is not relivant.
51142 * <script type="text/javascript">
51145 * These classes are private internal classes
51147 Roo.CenterLayoutRegion = function(mgr, config){
51148 Roo.LayoutRegion.call(this, mgr, config, "center");
51149 this.visible = true;
51150 this.minWidth = config.minWidth || 20;
51151 this.minHeight = config.minHeight || 20;
51154 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51156 // center panel can't be hidden
51160 // center panel can't be hidden
51163 getMinWidth: function(){
51164 return this.minWidth;
51167 getMinHeight: function(){
51168 return this.minHeight;
51173 Roo.NorthLayoutRegion = function(mgr, config){
51174 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51176 this.split.placement = Roo.SplitBar.TOP;
51177 this.split.orientation = Roo.SplitBar.VERTICAL;
51178 this.split.el.addClass("x-layout-split-v");
51180 var size = config.initialSize || config.height;
51181 if(typeof size != "undefined"){
51182 this.el.setHeight(size);
51185 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51186 orientation: Roo.SplitBar.VERTICAL,
51187 getBox : function(){
51188 if(this.collapsed){
51189 return this.collapsedEl.getBox();
51191 var box = this.el.getBox();
51193 box.height += this.split.el.getHeight();
51198 updateBox : function(box){
51199 if(this.split && !this.collapsed){
51200 box.height -= this.split.el.getHeight();
51201 this.split.el.setLeft(box.x);
51202 this.split.el.setTop(box.y+box.height);
51203 this.split.el.setWidth(box.width);
51205 if(this.collapsed){
51206 this.updateBody(box.width, null);
51208 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51212 Roo.SouthLayoutRegion = function(mgr, config){
51213 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51215 this.split.placement = Roo.SplitBar.BOTTOM;
51216 this.split.orientation = Roo.SplitBar.VERTICAL;
51217 this.split.el.addClass("x-layout-split-v");
51219 var size = config.initialSize || config.height;
51220 if(typeof size != "undefined"){
51221 this.el.setHeight(size);
51224 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51225 orientation: Roo.SplitBar.VERTICAL,
51226 getBox : function(){
51227 if(this.collapsed){
51228 return this.collapsedEl.getBox();
51230 var box = this.el.getBox();
51232 var sh = this.split.el.getHeight();
51239 updateBox : function(box){
51240 if(this.split && !this.collapsed){
51241 var sh = this.split.el.getHeight();
51244 this.split.el.setLeft(box.x);
51245 this.split.el.setTop(box.y-sh);
51246 this.split.el.setWidth(box.width);
51248 if(this.collapsed){
51249 this.updateBody(box.width, null);
51251 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51255 Roo.EastLayoutRegion = function(mgr, config){
51256 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51258 this.split.placement = Roo.SplitBar.RIGHT;
51259 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51260 this.split.el.addClass("x-layout-split-h");
51262 var size = config.initialSize || config.width;
51263 if(typeof size != "undefined"){
51264 this.el.setWidth(size);
51267 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51268 orientation: Roo.SplitBar.HORIZONTAL,
51269 getBox : function(){
51270 if(this.collapsed){
51271 return this.collapsedEl.getBox();
51273 var box = this.el.getBox();
51275 var sw = this.split.el.getWidth();
51282 updateBox : function(box){
51283 if(this.split && !this.collapsed){
51284 var sw = this.split.el.getWidth();
51286 this.split.el.setLeft(box.x);
51287 this.split.el.setTop(box.y);
51288 this.split.el.setHeight(box.height);
51291 if(this.collapsed){
51292 this.updateBody(null, box.height);
51294 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51298 Roo.WestLayoutRegion = function(mgr, config){
51299 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51301 this.split.placement = Roo.SplitBar.LEFT;
51302 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51303 this.split.el.addClass("x-layout-split-h");
51305 var size = config.initialSize || config.width;
51306 if(typeof size != "undefined"){
51307 this.el.setWidth(size);
51310 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51311 orientation: Roo.SplitBar.HORIZONTAL,
51312 getBox : function(){
51313 if(this.collapsed){
51314 return this.collapsedEl.getBox();
51316 var box = this.el.getBox();
51318 box.width += this.split.el.getWidth();
51323 updateBox : function(box){
51324 if(this.split && !this.collapsed){
51325 var sw = this.split.el.getWidth();
51327 this.split.el.setLeft(box.x+box.width);
51328 this.split.el.setTop(box.y);
51329 this.split.el.setHeight(box.height);
51331 if(this.collapsed){
51332 this.updateBody(null, box.height);
51334 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51339 * Ext JS Library 1.1.1
51340 * Copyright(c) 2006-2007, Ext JS, LLC.
51342 * Originally Released Under LGPL - original licence link has changed is not relivant.
51345 * <script type="text/javascript">
51350 * Private internal class for reading and applying state
51352 Roo.LayoutStateManager = function(layout){
51353 // default empty state
51362 Roo.LayoutStateManager.prototype = {
51363 init : function(layout, provider){
51364 this.provider = provider;
51365 var state = provider.get(layout.id+"-layout-state");
51367 var wasUpdating = layout.isUpdating();
51369 layout.beginUpdate();
51371 for(var key in state){
51372 if(typeof state[key] != "function"){
51373 var rstate = state[key];
51374 var r = layout.getRegion(key);
51377 r.resizeTo(rstate.size);
51379 if(rstate.collapsed == true){
51382 r.expand(null, true);
51388 layout.endUpdate();
51390 this.state = state;
51392 this.layout = layout;
51393 layout.on("regionresized", this.onRegionResized, this);
51394 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51395 layout.on("regionexpanded", this.onRegionExpanded, this);
51398 storeState : function(){
51399 this.provider.set(this.layout.id+"-layout-state", this.state);
51402 onRegionResized : function(region, newSize){
51403 this.state[region.getPosition()].size = newSize;
51407 onRegionCollapsed : function(region){
51408 this.state[region.getPosition()].collapsed = true;
51412 onRegionExpanded : function(region){
51413 this.state[region.getPosition()].collapsed = false;
51418 * Ext JS Library 1.1.1
51419 * Copyright(c) 2006-2007, Ext JS, LLC.
51421 * Originally Released Under LGPL - original licence link has changed is not relivant.
51424 * <script type="text/javascript">
51427 * @class Roo.ContentPanel
51428 * @extends Roo.util.Observable
51429 * A basic ContentPanel element.
51430 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51431 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51432 * @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
51433 * @cfg {Boolean} closable True if the panel can be closed/removed
51434 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51435 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51436 * @cfg {Toolbar} toolbar A toolbar for this panel
51437 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51438 * @cfg {String} title The title for this panel
51439 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51440 * @cfg {String} url Calls {@link #setUrl} with this value
51441 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51442 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51443 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51444 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51447 * Create a new ContentPanel.
51448 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51449 * @param {String/Object} config A string to set only the title or a config object
51450 * @param {String} content (optional) Set the HTML content for this panel
51451 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51453 Roo.ContentPanel = function(el, config, content){
51457 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51461 if (config && config.parentLayout) {
51462 el = config.parentLayout.el.createChild();
51465 if(el.autoCreate){ // xtype is available if this is called from factory
51469 this.el = Roo.get(el);
51470 if(!this.el && config && config.autoCreate){
51471 if(typeof config.autoCreate == "object"){
51472 if(!config.autoCreate.id){
51473 config.autoCreate.id = config.id||el;
51475 this.el = Roo.DomHelper.append(document.body,
51476 config.autoCreate, true);
51478 this.el = Roo.DomHelper.append(document.body,
51479 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51482 this.closable = false;
51483 this.loaded = false;
51484 this.active = false;
51485 if(typeof config == "string"){
51486 this.title = config;
51488 Roo.apply(this, config);
51491 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51492 this.wrapEl = this.el.wrap();
51493 this.toolbar.container = this.el.insertSibling(false, 'before');
51494 this.toolbar = new Roo.Toolbar(this.toolbar);
51497 // xtype created footer. - not sure if will work as we normally have to render first..
51498 if (this.footer && !this.footer.el && this.footer.xtype) {
51499 if (!this.wrapEl) {
51500 this.wrapEl = this.el.wrap();
51503 this.footer.container = this.wrapEl.createChild();
51505 this.footer = Roo.factory(this.footer, Roo);
51510 this.resizeEl = Roo.get(this.resizeEl, true);
51512 this.resizeEl = this.el;
51514 // handle view.xtype
51522 * Fires when this panel is activated.
51523 * @param {Roo.ContentPanel} this
51527 * @event deactivate
51528 * Fires when this panel is activated.
51529 * @param {Roo.ContentPanel} this
51531 "deactivate" : true,
51535 * Fires when this panel is resized if fitToFrame is true.
51536 * @param {Roo.ContentPanel} this
51537 * @param {Number} width The width after any component adjustments
51538 * @param {Number} height The height after any component adjustments
51544 * Fires when this tab is created
51545 * @param {Roo.ContentPanel} this
51556 if(this.autoScroll){
51557 this.resizeEl.setStyle("overflow", "auto");
51559 // fix randome scrolling
51560 this.el.on('scroll', function() {
51561 Roo.log('fix random scolling');
51562 this.scrollTo('top',0);
51565 content = content || this.content;
51567 this.setContent(content);
51569 if(config && config.url){
51570 this.setUrl(this.url, this.params, this.loadOnce);
51575 Roo.ContentPanel.superclass.constructor.call(this);
51577 if (this.view && typeof(this.view.xtype) != 'undefined') {
51578 this.view.el = this.el.appendChild(document.createElement("div"));
51579 this.view = Roo.factory(this.view);
51580 this.view.render && this.view.render(false, '');
51584 this.fireEvent('render', this);
51587 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51589 setRegion : function(region){
51590 this.region = region;
51592 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51594 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51599 * Returns the toolbar for this Panel if one was configured.
51600 * @return {Roo.Toolbar}
51602 getToolbar : function(){
51603 return this.toolbar;
51606 setActiveState : function(active){
51607 this.active = active;
51609 this.fireEvent("deactivate", this);
51611 this.fireEvent("activate", this);
51615 * Updates this panel's element
51616 * @param {String} content The new content
51617 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51619 setContent : function(content, loadScripts){
51620 this.el.update(content, loadScripts);
51623 ignoreResize : function(w, h){
51624 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51627 this.lastSize = {width: w, height: h};
51632 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51633 * @return {Roo.UpdateManager} The UpdateManager
51635 getUpdateManager : function(){
51636 return this.el.getUpdateManager();
51639 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51640 * @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:
51643 url: "your-url.php",
51644 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51645 callback: yourFunction,
51646 scope: yourObject, //(optional scope)
51649 text: "Loading...",
51654 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51655 * 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.
51656 * @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}
51657 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51658 * @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.
51659 * @return {Roo.ContentPanel} this
51662 var um = this.el.getUpdateManager();
51663 um.update.apply(um, arguments);
51669 * 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.
51670 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51671 * @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)
51672 * @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)
51673 * @return {Roo.UpdateManager} The UpdateManager
51675 setUrl : function(url, params, loadOnce){
51676 if(this.refreshDelegate){
51677 this.removeListener("activate", this.refreshDelegate);
51679 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51680 this.on("activate", this.refreshDelegate);
51681 return this.el.getUpdateManager();
51684 _handleRefresh : function(url, params, loadOnce){
51685 if(!loadOnce || !this.loaded){
51686 var updater = this.el.getUpdateManager();
51687 updater.update(url, params, this._setLoaded.createDelegate(this));
51691 _setLoaded : function(){
51692 this.loaded = true;
51696 * Returns this panel's id
51699 getId : function(){
51704 * Returns this panel's element - used by regiosn to add.
51705 * @return {Roo.Element}
51707 getEl : function(){
51708 return this.wrapEl || this.el;
51711 adjustForComponents : function(width, height)
51713 //Roo.log('adjustForComponents ');
51714 if(this.resizeEl != this.el){
51715 width -= this.el.getFrameWidth('lr');
51716 height -= this.el.getFrameWidth('tb');
51719 var te = this.toolbar.getEl();
51720 height -= te.getHeight();
51721 te.setWidth(width);
51724 var te = this.footer.getEl();
51725 Roo.log("footer:" + te.getHeight());
51727 height -= te.getHeight();
51728 te.setWidth(width);
51732 if(this.adjustments){
51733 width += this.adjustments[0];
51734 height += this.adjustments[1];
51736 return {"width": width, "height": height};
51739 setSize : function(width, height){
51740 if(this.fitToFrame && !this.ignoreResize(width, height)){
51741 if(this.fitContainer && this.resizeEl != this.el){
51742 this.el.setSize(width, height);
51744 var size = this.adjustForComponents(width, height);
51745 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51746 this.fireEvent('resize', this, size.width, size.height);
51751 * Returns this panel's title
51754 getTitle : function(){
51759 * Set this panel's title
51760 * @param {String} title
51762 setTitle : function(title){
51763 this.title = title;
51765 this.region.updatePanelTitle(this, title);
51770 * Returns true is this panel was configured to be closable
51771 * @return {Boolean}
51773 isClosable : function(){
51774 return this.closable;
51777 beforeSlide : function(){
51779 this.resizeEl.clip();
51782 afterSlide : function(){
51784 this.resizeEl.unclip();
51788 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51789 * Will fail silently if the {@link #setUrl} method has not been called.
51790 * This does not activate the panel, just updates its content.
51792 refresh : function(){
51793 if(this.refreshDelegate){
51794 this.loaded = false;
51795 this.refreshDelegate();
51800 * Destroys this panel
51802 destroy : function(){
51803 this.el.removeAllListeners();
51804 var tempEl = document.createElement("span");
51805 tempEl.appendChild(this.el.dom);
51806 tempEl.innerHTML = "";
51812 * form - if the content panel contains a form - this is a reference to it.
51813 * @type {Roo.form.Form}
51817 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51818 * This contains a reference to it.
51824 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51834 * @param {Object} cfg Xtype definition of item to add.
51837 addxtype : function(cfg) {
51839 if (cfg.xtype.match(/^Form$/)) {
51842 //if (this.footer) {
51843 // el = this.footer.container.insertSibling(false, 'before');
51845 el = this.el.createChild();
51848 this.form = new Roo.form.Form(cfg);
51851 if ( this.form.allItems.length) this.form.render(el.dom);
51854 // should only have one of theses..
51855 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51856 // views.. should not be just added - used named prop 'view''
51858 cfg.el = this.el.appendChild(document.createElement("div"));
51861 var ret = new Roo.factory(cfg);
51863 ret.render && ret.render(false, ''); // render blank..
51872 * @class Roo.GridPanel
51873 * @extends Roo.ContentPanel
51875 * Create a new GridPanel.
51876 * @param {Roo.grid.Grid} grid The grid for this panel
51877 * @param {String/Object} config A string to set only the panel's title, or a config object
51879 Roo.GridPanel = function(grid, config){
51882 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51883 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51885 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51887 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51890 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51892 // xtype created footer. - not sure if will work as we normally have to render first..
51893 if (this.footer && !this.footer.el && this.footer.xtype) {
51895 this.footer.container = this.grid.getView().getFooterPanel(true);
51896 this.footer.dataSource = this.grid.dataSource;
51897 this.footer = Roo.factory(this.footer, Roo);
51901 grid.monitorWindowResize = false; // turn off autosizing
51902 grid.autoHeight = false;
51903 grid.autoWidth = false;
51905 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51908 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51909 getId : function(){
51910 return this.grid.id;
51914 * Returns the grid for this panel
51915 * @return {Roo.grid.Grid}
51917 getGrid : function(){
51921 setSize : function(width, height){
51922 if(!this.ignoreResize(width, height)){
51923 var grid = this.grid;
51924 var size = this.adjustForComponents(width, height);
51925 grid.getGridEl().setSize(size.width, size.height);
51930 beforeSlide : function(){
51931 this.grid.getView().scroller.clip();
51934 afterSlide : function(){
51935 this.grid.getView().scroller.unclip();
51938 destroy : function(){
51939 this.grid.destroy();
51941 Roo.GridPanel.superclass.destroy.call(this);
51947 * @class Roo.NestedLayoutPanel
51948 * @extends Roo.ContentPanel
51950 * Create a new NestedLayoutPanel.
51953 * @param {Roo.BorderLayout} layout The layout for this panel
51954 * @param {String/Object} config A string to set only the title or a config object
51956 Roo.NestedLayoutPanel = function(layout, config)
51958 // construct with only one argument..
51959 /* FIXME - implement nicer consturctors
51960 if (layout.layout) {
51962 layout = config.layout;
51963 delete config.layout;
51965 if (layout.xtype && !layout.getEl) {
51966 // then layout needs constructing..
51967 layout = Roo.factory(layout, Roo);
51972 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51974 layout.monitorWindowResize = false; // turn off autosizing
51975 this.layout = layout;
51976 this.layout.getEl().addClass("x-layout-nested-layout");
51983 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51985 setSize : function(width, height){
51986 if(!this.ignoreResize(width, height)){
51987 var size = this.adjustForComponents(width, height);
51988 var el = this.layout.getEl();
51989 el.setSize(size.width, size.height);
51990 var touch = el.dom.offsetWidth;
51991 this.layout.layout();
51992 // ie requires a double layout on the first pass
51993 if(Roo.isIE && !this.initialized){
51994 this.initialized = true;
51995 this.layout.layout();
52000 // activate all subpanels if not currently active..
52002 setActiveState : function(active){
52003 this.active = active;
52005 this.fireEvent("deactivate", this);
52009 this.fireEvent("activate", this);
52010 // not sure if this should happen before or after..
52011 if (!this.layout) {
52012 return; // should not happen..
52015 for (var r in this.layout.regions) {
52016 reg = this.layout.getRegion(r);
52017 if (reg.getActivePanel()) {
52018 //reg.showPanel(reg.getActivePanel()); // force it to activate..
52019 reg.setActivePanel(reg.getActivePanel());
52022 if (!reg.panels.length) {
52025 reg.showPanel(reg.getPanel(0));
52034 * Returns the nested BorderLayout for this panel
52035 * @return {Roo.BorderLayout}
52037 getLayout : function(){
52038 return this.layout;
52042 * Adds a xtype elements to the layout of the nested panel
52046 xtype : 'ContentPanel',
52053 xtype : 'NestedLayoutPanel',
52059 items : [ ... list of content panels or nested layout panels.. ]
52063 * @param {Object} cfg Xtype definition of item to add.
52065 addxtype : function(cfg) {
52066 return this.layout.addxtype(cfg);
52071 Roo.ScrollPanel = function(el, config, content){
52072 config = config || {};
52073 config.fitToFrame = true;
52074 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52076 this.el.dom.style.overflow = "hidden";
52077 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52078 this.el.removeClass("x-layout-inactive-content");
52079 this.el.on("mousewheel", this.onWheel, this);
52081 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52082 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52083 up.unselectable(); down.unselectable();
52084 up.on("click", this.scrollUp, this);
52085 down.on("click", this.scrollDown, this);
52086 up.addClassOnOver("x-scroller-btn-over");
52087 down.addClassOnOver("x-scroller-btn-over");
52088 up.addClassOnClick("x-scroller-btn-click");
52089 down.addClassOnClick("x-scroller-btn-click");
52090 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52092 this.resizeEl = this.el;
52093 this.el = wrap; this.up = up; this.down = down;
52096 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52098 wheelIncrement : 5,
52099 scrollUp : function(){
52100 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52103 scrollDown : function(){
52104 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52107 afterScroll : function(){
52108 var el = this.resizeEl;
52109 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52110 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52111 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52114 setSize : function(){
52115 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52116 this.afterScroll();
52119 onWheel : function(e){
52120 var d = e.getWheelDelta();
52121 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52122 this.afterScroll();
52126 setContent : function(content, loadScripts){
52127 this.resizeEl.update(content, loadScripts);
52141 * @class Roo.TreePanel
52142 * @extends Roo.ContentPanel
52144 * Create a new TreePanel. - defaults to fit/scoll contents.
52145 * @param {String/Object} config A string to set only the panel's title, or a config object
52146 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52148 Roo.TreePanel = function(config){
52149 var el = config.el;
52150 var tree = config.tree;
52151 delete config.tree;
52152 delete config.el; // hopefull!
52154 // wrapper for IE7 strict & safari scroll issue
52156 var treeEl = el.createChild();
52157 config.resizeEl = treeEl;
52161 Roo.TreePanel.superclass.constructor.call(this, el, config);
52164 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52165 //console.log(tree);
52166 this.on('activate', function()
52168 if (this.tree.rendered) {
52171 //console.log('render tree');
52172 this.tree.render();
52174 // this should not be needed.. - it's actually the 'el' that resizes?
52175 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52177 //this.on('resize', function (cp, w, h) {
52178 // this.tree.innerCt.setWidth(w);
52179 // this.tree.innerCt.setHeight(h);
52180 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52187 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52204 * Ext JS Library 1.1.1
52205 * Copyright(c) 2006-2007, Ext JS, LLC.
52207 * Originally Released Under LGPL - original licence link has changed is not relivant.
52210 * <script type="text/javascript">
52215 * @class Roo.ReaderLayout
52216 * @extends Roo.BorderLayout
52217 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52218 * center region containing two nested regions (a top one for a list view and one for item preview below),
52219 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52220 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52221 * expedites the setup of the overall layout and regions for this common application style.
52224 var reader = new Roo.ReaderLayout();
52225 var CP = Roo.ContentPanel; // shortcut for adding
52227 reader.beginUpdate();
52228 reader.add("north", new CP("north", "North"));
52229 reader.add("west", new CP("west", {title: "West"}));
52230 reader.add("east", new CP("east", {title: "East"}));
52232 reader.regions.listView.add(new CP("listView", "List"));
52233 reader.regions.preview.add(new CP("preview", "Preview"));
52234 reader.endUpdate();
52237 * Create a new ReaderLayout
52238 * @param {Object} config Configuration options
52239 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52240 * document.body if omitted)
52242 Roo.ReaderLayout = function(config, renderTo){
52243 var c = config || {size:{}};
52244 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52245 north: c.north !== false ? Roo.apply({
52249 }, c.north) : false,
52250 west: c.west !== false ? Roo.apply({
52258 margins:{left:5,right:0,bottom:5,top:5},
52259 cmargins:{left:5,right:5,bottom:5,top:5}
52260 }, c.west) : false,
52261 east: c.east !== false ? Roo.apply({
52269 margins:{left:0,right:5,bottom:5,top:5},
52270 cmargins:{left:5,right:5,bottom:5,top:5}
52271 }, c.east) : false,
52272 center: Roo.apply({
52273 tabPosition: 'top',
52277 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52281 this.el.addClass('x-reader');
52283 this.beginUpdate();
52285 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52286 south: c.preview !== false ? Roo.apply({
52293 cmargins:{top:5,left:0, right:0, bottom:0}
52294 }, c.preview) : false,
52295 center: Roo.apply({
52301 this.add('center', new Roo.NestedLayoutPanel(inner,
52302 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52306 this.regions.preview = inner.getRegion('south');
52307 this.regions.listView = inner.getRegion('center');
52310 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52312 * Ext JS Library 1.1.1
52313 * Copyright(c) 2006-2007, Ext JS, LLC.
52315 * Originally Released Under LGPL - original licence link has changed is not relivant.
52318 * <script type="text/javascript">
52322 * @class Roo.grid.Grid
52323 * @extends Roo.util.Observable
52324 * This class represents the primary interface of a component based grid control.
52325 * <br><br>Usage:<pre><code>
52326 var grid = new Roo.grid.Grid("my-container-id", {
52329 selModel: mySelectionModel,
52330 autoSizeColumns: true,
52331 monitorWindowResize: false,
52332 trackMouseOver: true
52337 * <b>Common Problems:</b><br/>
52338 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52339 * element will correct this<br/>
52340 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52341 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52342 * are unpredictable.<br/>
52343 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52344 * grid to calculate dimensions/offsets.<br/>
52346 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52347 * The container MUST have some type of size defined for the grid to fill. The container will be
52348 * automatically set to position relative if it isn't already.
52349 * @param {Object} config A config object that sets properties on this grid.
52351 Roo.grid.Grid = function(container, config){
52352 // initialize the container
52353 this.container = Roo.get(container);
52354 this.container.update("");
52355 this.container.setStyle("overflow", "hidden");
52356 this.container.addClass('x-grid-container');
52358 this.id = this.container.id;
52360 Roo.apply(this, config);
52361 // check and correct shorthanded configs
52363 this.dataSource = this.ds;
52367 this.colModel = this.cm;
52371 this.selModel = this.sm;
52375 if (this.selModel) {
52376 this.selModel = Roo.factory(this.selModel, Roo.grid);
52377 this.sm = this.selModel;
52378 this.sm.xmodule = this.xmodule || false;
52380 if (typeof(this.colModel.config) == 'undefined') {
52381 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52382 this.cm = this.colModel;
52383 this.cm.xmodule = this.xmodule || false;
52385 if (this.dataSource) {
52386 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52387 this.ds = this.dataSource;
52388 this.ds.xmodule = this.xmodule || false;
52395 this.container.setWidth(this.width);
52399 this.container.setHeight(this.height);
52406 * The raw click event for the entire grid.
52407 * @param {Roo.EventObject} e
52412 * The raw dblclick event for the entire grid.
52413 * @param {Roo.EventObject} e
52417 * @event contextmenu
52418 * The raw contextmenu event for the entire grid.
52419 * @param {Roo.EventObject} e
52421 "contextmenu" : true,
52424 * The raw mousedown event for the entire grid.
52425 * @param {Roo.EventObject} e
52427 "mousedown" : true,
52430 * The raw mouseup event for the entire grid.
52431 * @param {Roo.EventObject} e
52436 * The raw mouseover event for the entire grid.
52437 * @param {Roo.EventObject} e
52439 "mouseover" : true,
52442 * The raw mouseout event for the entire grid.
52443 * @param {Roo.EventObject} e
52448 * The raw keypress event for the entire grid.
52449 * @param {Roo.EventObject} e
52454 * The raw keydown event for the entire grid.
52455 * @param {Roo.EventObject} e
52463 * Fires when a cell is clicked
52464 * @param {Grid} this
52465 * @param {Number} rowIndex
52466 * @param {Number} columnIndex
52467 * @param {Roo.EventObject} e
52469 "cellclick" : true,
52471 * @event celldblclick
52472 * Fires when a cell is double clicked
52473 * @param {Grid} this
52474 * @param {Number} rowIndex
52475 * @param {Number} columnIndex
52476 * @param {Roo.EventObject} e
52478 "celldblclick" : true,
52481 * Fires when a row is clicked
52482 * @param {Grid} this
52483 * @param {Number} rowIndex
52484 * @param {Roo.EventObject} e
52488 * @event rowdblclick
52489 * Fires when a row is double clicked
52490 * @param {Grid} this
52491 * @param {Number} rowIndex
52492 * @param {Roo.EventObject} e
52494 "rowdblclick" : true,
52496 * @event headerclick
52497 * Fires when a header is clicked
52498 * @param {Grid} this
52499 * @param {Number} columnIndex
52500 * @param {Roo.EventObject} e
52502 "headerclick" : true,
52504 * @event headerdblclick
52505 * Fires when a header cell is double clicked
52506 * @param {Grid} this
52507 * @param {Number} columnIndex
52508 * @param {Roo.EventObject} e
52510 "headerdblclick" : true,
52512 * @event rowcontextmenu
52513 * Fires when a row is right clicked
52514 * @param {Grid} this
52515 * @param {Number} rowIndex
52516 * @param {Roo.EventObject} e
52518 "rowcontextmenu" : true,
52520 * @event cellcontextmenu
52521 * Fires when a cell is right clicked
52522 * @param {Grid} this
52523 * @param {Number} rowIndex
52524 * @param {Number} cellIndex
52525 * @param {Roo.EventObject} e
52527 "cellcontextmenu" : true,
52529 * @event headercontextmenu
52530 * Fires when a header is right clicked
52531 * @param {Grid} this
52532 * @param {Number} columnIndex
52533 * @param {Roo.EventObject} e
52535 "headercontextmenu" : true,
52537 * @event bodyscroll
52538 * Fires when the body element is scrolled
52539 * @param {Number} scrollLeft
52540 * @param {Number} scrollTop
52542 "bodyscroll" : true,
52544 * @event columnresize
52545 * Fires when the user resizes a column
52546 * @param {Number} columnIndex
52547 * @param {Number} newSize
52549 "columnresize" : true,
52551 * @event columnmove
52552 * Fires when the user moves a column
52553 * @param {Number} oldIndex
52554 * @param {Number} newIndex
52556 "columnmove" : true,
52559 * Fires when row(s) start being dragged
52560 * @param {Grid} this
52561 * @param {Roo.GridDD} dd The drag drop object
52562 * @param {event} e The raw browser event
52564 "startdrag" : true,
52567 * Fires when a drag operation is complete
52568 * @param {Grid} this
52569 * @param {Roo.GridDD} dd The drag drop object
52570 * @param {event} e The raw browser event
52575 * Fires when dragged row(s) are dropped on a valid DD target
52576 * @param {Grid} this
52577 * @param {Roo.GridDD} dd The drag drop object
52578 * @param {String} targetId The target drag drop object
52579 * @param {event} e The raw browser event
52584 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52585 * @param {Grid} this
52586 * @param {Roo.GridDD} dd The drag drop object
52587 * @param {String} targetId The target drag drop object
52588 * @param {event} e The raw browser event
52593 * Fires when the dragged row(s) first cross another DD target while being dragged
52594 * @param {Grid} this
52595 * @param {Roo.GridDD} dd The drag drop object
52596 * @param {String} targetId The target drag drop object
52597 * @param {event} e The raw browser event
52599 "dragenter" : true,
52602 * Fires when the dragged row(s) leave another DD target while being dragged
52603 * @param {Grid} this
52604 * @param {Roo.GridDD} dd The drag drop object
52605 * @param {String} targetId The target drag drop object
52606 * @param {event} e The raw browser event
52611 * Fires when a row is rendered, so you can change add a style to it.
52612 * @param {GridView} gridview The grid view
52613 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52619 * Fires when the grid is rendered
52620 * @param {Grid} grid
52625 Roo.grid.Grid.superclass.constructor.call(this);
52627 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52630 * @cfg {String} ddGroup - drag drop group.
52634 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52636 minColumnWidth : 25,
52639 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52640 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52641 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52643 autoSizeColumns : false,
52646 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52648 autoSizeHeaders : true,
52651 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52653 monitorWindowResize : true,
52656 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52657 * rows measured to get a columns size. Default is 0 (all rows).
52659 maxRowsToMeasure : 0,
52662 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52664 trackMouseOver : true,
52667 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52671 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52673 enableDragDrop : false,
52676 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52678 enableColumnMove : true,
52681 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52683 enableColumnHide : true,
52686 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52688 enableRowHeightSync : false,
52691 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52696 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52698 autoHeight : false,
52701 * @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.
52703 autoExpandColumn : false,
52706 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52709 autoExpandMin : 50,
52712 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52714 autoExpandMax : 1000,
52717 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52722 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52726 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52736 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52737 * of a fixed width. Default is false.
52740 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52743 * Called once after all setup has been completed and the grid is ready to be rendered.
52744 * @return {Roo.grid.Grid} this
52746 render : function()
52748 var c = this.container;
52749 // try to detect autoHeight/width mode
52750 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52751 this.autoHeight = true;
52753 var view = this.getView();
52756 c.on("click", this.onClick, this);
52757 c.on("dblclick", this.onDblClick, this);
52758 c.on("contextmenu", this.onContextMenu, this);
52759 c.on("keydown", this.onKeyDown, this);
52761 c.on("touchstart", this.onTouchStart, this);
52764 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52766 this.getSelectionModel().init(this);
52771 this.loadMask = new Roo.LoadMask(this.container,
52772 Roo.apply({store:this.dataSource}, this.loadMask));
52776 if (this.toolbar && this.toolbar.xtype) {
52777 this.toolbar.container = this.getView().getHeaderPanel(true);
52778 this.toolbar = new Roo.Toolbar(this.toolbar);
52780 if (this.footer && this.footer.xtype) {
52781 this.footer.dataSource = this.getDataSource();
52782 this.footer.container = this.getView().getFooterPanel(true);
52783 this.footer = Roo.factory(this.footer, Roo);
52785 if (this.dropTarget && this.dropTarget.xtype) {
52786 delete this.dropTarget.xtype;
52787 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52791 this.rendered = true;
52792 this.fireEvent('render', this);
52797 * Reconfigures the grid to use a different Store and Column Model.
52798 * The View will be bound to the new objects and refreshed.
52799 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52800 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52802 reconfigure : function(dataSource, colModel){
52804 this.loadMask.destroy();
52805 this.loadMask = new Roo.LoadMask(this.container,
52806 Roo.apply({store:dataSource}, this.loadMask));
52808 this.view.bind(dataSource, colModel);
52809 this.dataSource = dataSource;
52810 this.colModel = colModel;
52811 this.view.refresh(true);
52815 onKeyDown : function(e){
52816 this.fireEvent("keydown", e);
52820 * Destroy this grid.
52821 * @param {Boolean} removeEl True to remove the element
52823 destroy : function(removeEl, keepListeners){
52825 this.loadMask.destroy();
52827 var c = this.container;
52828 c.removeAllListeners();
52829 this.view.destroy();
52830 this.colModel.purgeListeners();
52831 if(!keepListeners){
52832 this.purgeListeners();
52835 if(removeEl === true){
52841 processEvent : function(name, e){
52842 // does this fire select???
52843 //Roo.log('grid:processEvent ' + name);
52845 if (name != 'touchstart' ) {
52846 this.fireEvent(name, e);
52849 var t = e.getTarget();
52851 var header = v.findHeaderIndex(t);
52852 if(header !== false){
52853 var ename = name == 'touchstart' ? 'click' : name;
52855 this.fireEvent("header" + ename, this, header, e);
52857 var row = v.findRowIndex(t);
52858 var cell = v.findCellIndex(t);
52859 if (name == 'touchstart') {
52860 // first touch is always a click.
52861 // hopefull this happens after selection is updated.?
52864 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52865 var cs = this.selModel.getSelectedCell();
52866 if (row == cs[0] && cell == cs[1]){
52870 if (typeof(this.selModel.getSelections) != 'undefined') {
52871 var cs = this.selModel.getSelections();
52872 var ds = this.dataSource;
52873 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52884 this.fireEvent("row" + name, this, row, e);
52885 if(cell !== false){
52886 this.fireEvent("cell" + name, this, row, cell, e);
52893 onClick : function(e){
52894 this.processEvent("click", e);
52897 onTouchStart : function(e){
52898 this.processEvent("touchstart", e);
52902 onContextMenu : function(e, t){
52903 this.processEvent("contextmenu", e);
52907 onDblClick : function(e){
52908 this.processEvent("dblclick", e);
52912 walkCells : function(row, col, step, fn, scope){
52913 var cm = this.colModel, clen = cm.getColumnCount();
52914 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52926 if(fn.call(scope || this, row, col, cm) === true){
52944 if(fn.call(scope || this, row, col, cm) === true){
52956 getSelections : function(){
52957 return this.selModel.getSelections();
52961 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52962 * but if manual update is required this method will initiate it.
52964 autoSize : function(){
52966 this.view.layout();
52967 if(this.view.adjustForScroll){
52968 this.view.adjustForScroll();
52974 * Returns the grid's underlying element.
52975 * @return {Element} The element
52977 getGridEl : function(){
52978 return this.container;
52981 // private for compatibility, overridden by editor grid
52982 stopEditing : function(){},
52985 * Returns the grid's SelectionModel.
52986 * @return {SelectionModel}
52988 getSelectionModel : function(){
52989 if(!this.selModel){
52990 this.selModel = new Roo.grid.RowSelectionModel();
52992 return this.selModel;
52996 * Returns the grid's DataSource.
52997 * @return {DataSource}
52999 getDataSource : function(){
53000 return this.dataSource;
53004 * Returns the grid's ColumnModel.
53005 * @return {ColumnModel}
53007 getColumnModel : function(){
53008 return this.colModel;
53012 * Returns the grid's GridView object.
53013 * @return {GridView}
53015 getView : function(){
53017 this.view = new Roo.grid.GridView(this.viewConfig);
53022 * Called to get grid's drag proxy text, by default returns this.ddText.
53025 getDragDropText : function(){
53026 var count = this.selModel.getCount();
53027 return String.format(this.ddText, count, count == 1 ? '' : 's');
53031 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53032 * %0 is replaced with the number of selected rows.
53035 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53037 * Ext JS Library 1.1.1
53038 * Copyright(c) 2006-2007, Ext JS, LLC.
53040 * Originally Released Under LGPL - original licence link has changed is not relivant.
53043 * <script type="text/javascript">
53046 Roo.grid.AbstractGridView = function(){
53050 "beforerowremoved" : true,
53051 "beforerowsinserted" : true,
53052 "beforerefresh" : true,
53053 "rowremoved" : true,
53054 "rowsinserted" : true,
53055 "rowupdated" : true,
53058 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53061 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53062 rowClass : "x-grid-row",
53063 cellClass : "x-grid-cell",
53064 tdClass : "x-grid-td",
53065 hdClass : "x-grid-hd",
53066 splitClass : "x-grid-hd-split",
53068 init: function(grid){
53070 var cid = this.grid.getGridEl().id;
53071 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53072 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53073 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53074 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53077 getColumnRenderers : function(){
53078 var renderers = [];
53079 var cm = this.grid.colModel;
53080 var colCount = cm.getColumnCount();
53081 for(var i = 0; i < colCount; i++){
53082 renderers[i] = cm.getRenderer(i);
53087 getColumnIds : function(){
53089 var cm = this.grid.colModel;
53090 var colCount = cm.getColumnCount();
53091 for(var i = 0; i < colCount; i++){
53092 ids[i] = cm.getColumnId(i);
53097 getDataIndexes : function(){
53098 if(!this.indexMap){
53099 this.indexMap = this.buildIndexMap();
53101 return this.indexMap.colToData;
53104 getColumnIndexByDataIndex : function(dataIndex){
53105 if(!this.indexMap){
53106 this.indexMap = this.buildIndexMap();
53108 return this.indexMap.dataToCol[dataIndex];
53112 * Set a css style for a column dynamically.
53113 * @param {Number} colIndex The index of the column
53114 * @param {String} name The css property name
53115 * @param {String} value The css value
53117 setCSSStyle : function(colIndex, name, value){
53118 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53119 Roo.util.CSS.updateRule(selector, name, value);
53122 generateRules : function(cm){
53123 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53124 Roo.util.CSS.removeStyleSheet(rulesId);
53125 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53126 var cid = cm.getColumnId(i);
53127 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53128 this.tdSelector, cid, " {\n}\n",
53129 this.hdSelector, cid, " {\n}\n",
53130 this.splitSelector, cid, " {\n}\n");
53132 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53136 * Ext JS Library 1.1.1
53137 * Copyright(c) 2006-2007, Ext JS, LLC.
53139 * Originally Released Under LGPL - original licence link has changed is not relivant.
53142 * <script type="text/javascript">
53146 // This is a support class used internally by the Grid components
53147 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53149 this.view = grid.getView();
53150 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53151 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53153 this.setHandleElId(Roo.id(hd));
53154 this.setOuterHandleElId(Roo.id(hd2));
53156 this.scroll = false;
53158 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53160 getDragData : function(e){
53161 var t = Roo.lib.Event.getTarget(e);
53162 var h = this.view.findHeaderCell(t);
53164 return {ddel: h.firstChild, header:h};
53169 onInitDrag : function(e){
53170 this.view.headersDisabled = true;
53171 var clone = this.dragData.ddel.cloneNode(true);
53172 clone.id = Roo.id();
53173 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53174 this.proxy.update(clone);
53178 afterValidDrop : function(){
53180 setTimeout(function(){
53181 v.headersDisabled = false;
53185 afterInvalidDrop : function(){
53187 setTimeout(function(){
53188 v.headersDisabled = false;
53194 * Ext JS Library 1.1.1
53195 * Copyright(c) 2006-2007, Ext JS, LLC.
53197 * Originally Released Under LGPL - original licence link has changed is not relivant.
53200 * <script type="text/javascript">
53203 // This is a support class used internally by the Grid components
53204 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53206 this.view = grid.getView();
53207 // split the proxies so they don't interfere with mouse events
53208 this.proxyTop = Roo.DomHelper.append(document.body, {
53209 cls:"col-move-top", html:" "
53211 this.proxyBottom = Roo.DomHelper.append(document.body, {
53212 cls:"col-move-bottom", html:" "
53214 this.proxyTop.hide = this.proxyBottom.hide = function(){
53215 this.setLeftTop(-100,-100);
53216 this.setStyle("visibility", "hidden");
53218 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53219 // temporarily disabled
53220 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53221 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53223 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53224 proxyOffsets : [-4, -9],
53225 fly: Roo.Element.fly,
53227 getTargetFromEvent : function(e){
53228 var t = Roo.lib.Event.getTarget(e);
53229 var cindex = this.view.findCellIndex(t);
53230 if(cindex !== false){
53231 return this.view.getHeaderCell(cindex);
53236 nextVisible : function(h){
53237 var v = this.view, cm = this.grid.colModel;
53240 if(!cm.isHidden(v.getCellIndex(h))){
53248 prevVisible : function(h){
53249 var v = this.view, cm = this.grid.colModel;
53252 if(!cm.isHidden(v.getCellIndex(h))){
53260 positionIndicator : function(h, n, e){
53261 var x = Roo.lib.Event.getPageX(e);
53262 var r = Roo.lib.Dom.getRegion(n.firstChild);
53263 var px, pt, py = r.top + this.proxyOffsets[1];
53264 if((r.right - x) <= (r.right-r.left)/2){
53265 px = r.right+this.view.borderWidth;
53271 var oldIndex = this.view.getCellIndex(h);
53272 var newIndex = this.view.getCellIndex(n);
53274 if(this.grid.colModel.isFixed(newIndex)){
53278 var locked = this.grid.colModel.isLocked(newIndex);
53283 if(oldIndex < newIndex){
53286 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53289 px += this.proxyOffsets[0];
53290 this.proxyTop.setLeftTop(px, py);
53291 this.proxyTop.show();
53292 if(!this.bottomOffset){
53293 this.bottomOffset = this.view.mainHd.getHeight();
53295 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53296 this.proxyBottom.show();
53300 onNodeEnter : function(n, dd, e, data){
53301 if(data.header != n){
53302 this.positionIndicator(data.header, n, e);
53306 onNodeOver : function(n, dd, e, data){
53307 var result = false;
53308 if(data.header != n){
53309 result = this.positionIndicator(data.header, n, e);
53312 this.proxyTop.hide();
53313 this.proxyBottom.hide();
53315 return result ? this.dropAllowed : this.dropNotAllowed;
53318 onNodeOut : function(n, dd, e, data){
53319 this.proxyTop.hide();
53320 this.proxyBottom.hide();
53323 onNodeDrop : function(n, dd, e, data){
53324 var h = data.header;
53326 var cm = this.grid.colModel;
53327 var x = Roo.lib.Event.getPageX(e);
53328 var r = Roo.lib.Dom.getRegion(n.firstChild);
53329 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53330 var oldIndex = this.view.getCellIndex(h);
53331 var newIndex = this.view.getCellIndex(n);
53332 var locked = cm.isLocked(newIndex);
53336 if(oldIndex < newIndex){
53339 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53342 cm.setLocked(oldIndex, locked, true);
53343 cm.moveColumn(oldIndex, newIndex);
53344 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53352 * Ext JS Library 1.1.1
53353 * Copyright(c) 2006-2007, Ext JS, LLC.
53355 * Originally Released Under LGPL - original licence link has changed is not relivant.
53358 * <script type="text/javascript">
53362 * @class Roo.grid.GridView
53363 * @extends Roo.util.Observable
53366 * @param {Object} config
53368 Roo.grid.GridView = function(config){
53369 Roo.grid.GridView.superclass.constructor.call(this);
53372 Roo.apply(this, config);
53375 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53377 unselectable : 'unselectable="on"',
53378 unselectableCls : 'x-unselectable',
53381 rowClass : "x-grid-row",
53383 cellClass : "x-grid-col",
53385 tdClass : "x-grid-td",
53387 hdClass : "x-grid-hd",
53389 splitClass : "x-grid-split",
53391 sortClasses : ["sort-asc", "sort-desc"],
53393 enableMoveAnim : false,
53397 dh : Roo.DomHelper,
53399 fly : Roo.Element.fly,
53401 css : Roo.util.CSS,
53407 scrollIncrement : 22,
53409 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53411 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53413 bind : function(ds, cm){
53415 this.ds.un("load", this.onLoad, this);
53416 this.ds.un("datachanged", this.onDataChange, this);
53417 this.ds.un("add", this.onAdd, this);
53418 this.ds.un("remove", this.onRemove, this);
53419 this.ds.un("update", this.onUpdate, this);
53420 this.ds.un("clear", this.onClear, this);
53423 ds.on("load", this.onLoad, this);
53424 ds.on("datachanged", this.onDataChange, this);
53425 ds.on("add", this.onAdd, this);
53426 ds.on("remove", this.onRemove, this);
53427 ds.on("update", this.onUpdate, this);
53428 ds.on("clear", this.onClear, this);
53433 this.cm.un("widthchange", this.onColWidthChange, this);
53434 this.cm.un("headerchange", this.onHeaderChange, this);
53435 this.cm.un("hiddenchange", this.onHiddenChange, this);
53436 this.cm.un("columnmoved", this.onColumnMove, this);
53437 this.cm.un("columnlockchange", this.onColumnLock, this);
53440 this.generateRules(cm);
53441 cm.on("widthchange", this.onColWidthChange, this);
53442 cm.on("headerchange", this.onHeaderChange, this);
53443 cm.on("hiddenchange", this.onHiddenChange, this);
53444 cm.on("columnmoved", this.onColumnMove, this);
53445 cm.on("columnlockchange", this.onColumnLock, this);
53450 init: function(grid){
53451 Roo.grid.GridView.superclass.init.call(this, grid);
53453 this.bind(grid.dataSource, grid.colModel);
53455 grid.on("headerclick", this.handleHeaderClick, this);
53457 if(grid.trackMouseOver){
53458 grid.on("mouseover", this.onRowOver, this);
53459 grid.on("mouseout", this.onRowOut, this);
53461 grid.cancelTextSelection = function(){};
53462 this.gridId = grid.id;
53464 var tpls = this.templates || {};
53467 tpls.master = new Roo.Template(
53468 '<div class="x-grid" hidefocus="true">',
53469 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53470 '<div class="x-grid-topbar"></div>',
53471 '<div class="x-grid-scroller"><div></div></div>',
53472 '<div class="x-grid-locked">',
53473 '<div class="x-grid-header">{lockedHeader}</div>',
53474 '<div class="x-grid-body">{lockedBody}</div>',
53476 '<div class="x-grid-viewport">',
53477 '<div class="x-grid-header">{header}</div>',
53478 '<div class="x-grid-body">{body}</div>',
53480 '<div class="x-grid-bottombar"></div>',
53482 '<div class="x-grid-resize-proxy"> </div>',
53485 tpls.master.disableformats = true;
53489 tpls.header = new Roo.Template(
53490 '<table border="0" cellspacing="0" cellpadding="0">',
53491 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53494 tpls.header.disableformats = true;
53496 tpls.header.compile();
53499 tpls.hcell = new Roo.Template(
53500 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53501 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53504 tpls.hcell.disableFormats = true;
53506 tpls.hcell.compile();
53509 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53510 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53511 tpls.hsplit.disableFormats = true;
53513 tpls.hsplit.compile();
53516 tpls.body = new Roo.Template(
53517 '<table border="0" cellspacing="0" cellpadding="0">',
53518 "<tbody>{rows}</tbody>",
53521 tpls.body.disableFormats = true;
53523 tpls.body.compile();
53526 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53527 tpls.row.disableFormats = true;
53529 tpls.row.compile();
53532 tpls.cell = new Roo.Template(
53533 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53534 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53535 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53538 tpls.cell.disableFormats = true;
53540 tpls.cell.compile();
53542 this.templates = tpls;
53545 // remap these for backwards compat
53546 onColWidthChange : function(){
53547 this.updateColumns.apply(this, arguments);
53549 onHeaderChange : function(){
53550 this.updateHeaders.apply(this, arguments);
53552 onHiddenChange : function(){
53553 this.handleHiddenChange.apply(this, arguments);
53555 onColumnMove : function(){
53556 this.handleColumnMove.apply(this, arguments);
53558 onColumnLock : function(){
53559 this.handleLockChange.apply(this, arguments);
53562 onDataChange : function(){
53564 this.updateHeaderSortState();
53567 onClear : function(){
53571 onUpdate : function(ds, record){
53572 this.refreshRow(record);
53575 refreshRow : function(record){
53576 var ds = this.ds, index;
53577 if(typeof record == 'number'){
53579 record = ds.getAt(index);
53581 index = ds.indexOf(record);
53583 this.insertRows(ds, index, index, true);
53584 this.onRemove(ds, record, index+1, true);
53585 this.syncRowHeights(index, index);
53587 this.fireEvent("rowupdated", this, index, record);
53590 onAdd : function(ds, records, index){
53591 this.insertRows(ds, index, index + (records.length-1));
53594 onRemove : function(ds, record, index, isUpdate){
53595 if(isUpdate !== true){
53596 this.fireEvent("beforerowremoved", this, index, record);
53598 var bt = this.getBodyTable(), lt = this.getLockedTable();
53599 if(bt.rows[index]){
53600 bt.firstChild.removeChild(bt.rows[index]);
53602 if(lt.rows[index]){
53603 lt.firstChild.removeChild(lt.rows[index]);
53605 if(isUpdate !== true){
53606 this.stripeRows(index);
53607 this.syncRowHeights(index, index);
53609 this.fireEvent("rowremoved", this, index, record);
53613 onLoad : function(){
53614 this.scrollToTop();
53618 * Scrolls the grid to the top
53620 scrollToTop : function(){
53622 this.scroller.dom.scrollTop = 0;
53628 * Gets a panel in the header of the grid that can be used for toolbars etc.
53629 * After modifying the contents of this panel a call to grid.autoSize() may be
53630 * required to register any changes in size.
53631 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53632 * @return Roo.Element
53634 getHeaderPanel : function(doShow){
53636 this.headerPanel.show();
53638 return this.headerPanel;
53642 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53643 * After modifying the contents of this panel a call to grid.autoSize() may be
53644 * required to register any changes in size.
53645 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53646 * @return Roo.Element
53648 getFooterPanel : function(doShow){
53650 this.footerPanel.show();
53652 return this.footerPanel;
53655 initElements : function(){
53656 var E = Roo.Element;
53657 var el = this.grid.getGridEl().dom.firstChild;
53658 var cs = el.childNodes;
53660 this.el = new E(el);
53662 this.focusEl = new E(el.firstChild);
53663 this.focusEl.swallowEvent("click", true);
53665 this.headerPanel = new E(cs[1]);
53666 this.headerPanel.enableDisplayMode("block");
53668 this.scroller = new E(cs[2]);
53669 this.scrollSizer = new E(this.scroller.dom.firstChild);
53671 this.lockedWrap = new E(cs[3]);
53672 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53673 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53675 this.mainWrap = new E(cs[4]);
53676 this.mainHd = new E(this.mainWrap.dom.firstChild);
53677 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53679 this.footerPanel = new E(cs[5]);
53680 this.footerPanel.enableDisplayMode("block");
53682 this.resizeProxy = new E(cs[6]);
53684 this.headerSelector = String.format(
53685 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53686 this.lockedHd.id, this.mainHd.id
53689 this.splitterSelector = String.format(
53690 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53691 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53694 idToCssName : function(s)
53696 return s.replace(/[^a-z0-9]+/ig, '-');
53699 getHeaderCell : function(index){
53700 return Roo.DomQuery.select(this.headerSelector)[index];
53703 getHeaderCellMeasure : function(index){
53704 return this.getHeaderCell(index).firstChild;
53707 getHeaderCellText : function(index){
53708 return this.getHeaderCell(index).firstChild.firstChild;
53711 getLockedTable : function(){
53712 return this.lockedBody.dom.firstChild;
53715 getBodyTable : function(){
53716 return this.mainBody.dom.firstChild;
53719 getLockedRow : function(index){
53720 return this.getLockedTable().rows[index];
53723 getRow : function(index){
53724 return this.getBodyTable().rows[index];
53727 getRowComposite : function(index){
53729 this.rowEl = new Roo.CompositeElementLite();
53731 var els = [], lrow, mrow;
53732 if(lrow = this.getLockedRow(index)){
53735 if(mrow = this.getRow(index)){
53738 this.rowEl.elements = els;
53742 * Gets the 'td' of the cell
53744 * @param {Integer} rowIndex row to select
53745 * @param {Integer} colIndex column to select
53749 getCell : function(rowIndex, colIndex){
53750 var locked = this.cm.getLockedCount();
53752 if(colIndex < locked){
53753 source = this.lockedBody.dom.firstChild;
53755 source = this.mainBody.dom.firstChild;
53756 colIndex -= locked;
53758 return source.rows[rowIndex].childNodes[colIndex];
53761 getCellText : function(rowIndex, colIndex){
53762 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53765 getCellBox : function(cell){
53766 var b = this.fly(cell).getBox();
53767 if(Roo.isOpera){ // opera fails to report the Y
53768 b.y = cell.offsetTop + this.mainBody.getY();
53773 getCellIndex : function(cell){
53774 var id = String(cell.className).match(this.cellRE);
53776 return parseInt(id[1], 10);
53781 findHeaderIndex : function(n){
53782 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53783 return r ? this.getCellIndex(r) : false;
53786 findHeaderCell : function(n){
53787 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53788 return r ? r : false;
53791 findRowIndex : function(n){
53795 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53796 return r ? r.rowIndex : false;
53799 findCellIndex : function(node){
53800 var stop = this.el.dom;
53801 while(node && node != stop){
53802 if(this.findRE.test(node.className)){
53803 return this.getCellIndex(node);
53805 node = node.parentNode;
53810 getColumnId : function(index){
53811 return this.cm.getColumnId(index);
53814 getSplitters : function()
53816 if(this.splitterSelector){
53817 return Roo.DomQuery.select(this.splitterSelector);
53823 getSplitter : function(index){
53824 return this.getSplitters()[index];
53827 onRowOver : function(e, t){
53829 if((row = this.findRowIndex(t)) !== false){
53830 this.getRowComposite(row).addClass("x-grid-row-over");
53834 onRowOut : function(e, t){
53836 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53837 this.getRowComposite(row).removeClass("x-grid-row-over");
53841 renderHeaders : function(){
53843 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53844 var cb = [], lb = [], sb = [], lsb = [], p = {};
53845 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53846 p.cellId = "x-grid-hd-0-" + i;
53847 p.splitId = "x-grid-csplit-0-" + i;
53848 p.id = cm.getColumnId(i);
53849 p.title = cm.getColumnTooltip(i) || "";
53850 p.value = cm.getColumnHeader(i) || "";
53851 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53852 if(!cm.isLocked(i)){
53853 cb[cb.length] = ct.apply(p);
53854 sb[sb.length] = st.apply(p);
53856 lb[lb.length] = ct.apply(p);
53857 lsb[lsb.length] = st.apply(p);
53860 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53861 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53864 updateHeaders : function(){
53865 var html = this.renderHeaders();
53866 this.lockedHd.update(html[0]);
53867 this.mainHd.update(html[1]);
53871 * Focuses the specified row.
53872 * @param {Number} row The row index
53874 focusRow : function(row)
53876 //Roo.log('GridView.focusRow');
53877 var x = this.scroller.dom.scrollLeft;
53878 this.focusCell(row, 0, false);
53879 this.scroller.dom.scrollLeft = x;
53883 * Focuses the specified cell.
53884 * @param {Number} row The row index
53885 * @param {Number} col The column index
53886 * @param {Boolean} hscroll false to disable horizontal scrolling
53888 focusCell : function(row, col, hscroll)
53890 //Roo.log('GridView.focusCell');
53891 var el = this.ensureVisible(row, col, hscroll);
53892 this.focusEl.alignTo(el, "tl-tl");
53894 this.focusEl.focus();
53896 this.focusEl.focus.defer(1, this.focusEl);
53901 * Scrolls the specified cell into view
53902 * @param {Number} row The row index
53903 * @param {Number} col The column index
53904 * @param {Boolean} hscroll false to disable horizontal scrolling
53906 ensureVisible : function(row, col, hscroll)
53908 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53909 //return null; //disable for testing.
53910 if(typeof row != "number"){
53911 row = row.rowIndex;
53913 if(row < 0 && row >= this.ds.getCount()){
53916 col = (col !== undefined ? col : 0);
53917 var cm = this.grid.colModel;
53918 while(cm.isHidden(col)){
53922 var el = this.getCell(row, col);
53926 var c = this.scroller.dom;
53928 var ctop = parseInt(el.offsetTop, 10);
53929 var cleft = parseInt(el.offsetLeft, 10);
53930 var cbot = ctop + el.offsetHeight;
53931 var cright = cleft + el.offsetWidth;
53933 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53934 var stop = parseInt(c.scrollTop, 10);
53935 var sleft = parseInt(c.scrollLeft, 10);
53936 var sbot = stop + ch;
53937 var sright = sleft + c.clientWidth;
53939 Roo.log('GridView.ensureVisible:' +
53941 ' c.clientHeight:' + c.clientHeight +
53942 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53950 c.scrollTop = ctop;
53951 //Roo.log("set scrolltop to ctop DISABLE?");
53952 }else if(cbot > sbot){
53953 //Roo.log("set scrolltop to cbot-ch");
53954 c.scrollTop = cbot-ch;
53957 if(hscroll !== false){
53959 c.scrollLeft = cleft;
53960 }else if(cright > sright){
53961 c.scrollLeft = cright-c.clientWidth;
53968 updateColumns : function(){
53969 this.grid.stopEditing();
53970 var cm = this.grid.colModel, colIds = this.getColumnIds();
53971 //var totalWidth = cm.getTotalWidth();
53973 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53974 //if(cm.isHidden(i)) continue;
53975 var w = cm.getColumnWidth(i);
53976 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53977 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53979 this.updateSplitters();
53982 generateRules : function(cm){
53983 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53984 Roo.util.CSS.removeStyleSheet(rulesId);
53985 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53986 var cid = cm.getColumnId(i);
53988 if(cm.config[i].align){
53989 align = 'text-align:'+cm.config[i].align+';';
53992 if(cm.isHidden(i)){
53993 hidden = 'display:none;';
53995 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53997 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53998 this.hdSelector, cid, " {\n", align, width, "}\n",
53999 this.tdSelector, cid, " {\n",hidden,"\n}\n",
54000 this.splitSelector, cid, " {\n", hidden , "\n}\n");
54002 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54005 updateSplitters : function(){
54006 var cm = this.cm, s = this.getSplitters();
54007 if(s){ // splitters not created yet
54008 var pos = 0, locked = true;
54009 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54010 if(cm.isHidden(i)) continue;
54011 var w = cm.getColumnWidth(i); // make sure it's a number
54012 if(!cm.isLocked(i) && locked){
54017 s[i].style.left = (pos-this.splitOffset) + "px";
54022 handleHiddenChange : function(colModel, colIndex, hidden){
54024 this.hideColumn(colIndex);
54026 this.unhideColumn(colIndex);
54030 hideColumn : function(colIndex){
54031 var cid = this.getColumnId(colIndex);
54032 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54033 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54035 this.updateHeaders();
54037 this.updateSplitters();
54041 unhideColumn : function(colIndex){
54042 var cid = this.getColumnId(colIndex);
54043 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54044 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54047 this.updateHeaders();
54049 this.updateSplitters();
54053 insertRows : function(dm, firstRow, lastRow, isUpdate){
54054 if(firstRow == 0 && lastRow == dm.getCount()-1){
54058 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54060 var s = this.getScrollState();
54061 var markup = this.renderRows(firstRow, lastRow);
54062 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54063 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54064 this.restoreScroll(s);
54066 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54067 this.syncRowHeights(firstRow, lastRow);
54068 this.stripeRows(firstRow);
54074 bufferRows : function(markup, target, index){
54075 var before = null, trows = target.rows, tbody = target.tBodies[0];
54076 if(index < trows.length){
54077 before = trows[index];
54079 var b = document.createElement("div");
54080 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54081 var rows = b.firstChild.rows;
54082 for(var i = 0, len = rows.length; i < len; i++){
54084 tbody.insertBefore(rows[0], before);
54086 tbody.appendChild(rows[0]);
54093 deleteRows : function(dm, firstRow, lastRow){
54094 if(dm.getRowCount()<1){
54095 this.fireEvent("beforerefresh", this);
54096 this.mainBody.update("");
54097 this.lockedBody.update("");
54098 this.fireEvent("refresh", this);
54100 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54101 var bt = this.getBodyTable();
54102 var tbody = bt.firstChild;
54103 var rows = bt.rows;
54104 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54105 tbody.removeChild(rows[firstRow]);
54107 this.stripeRows(firstRow);
54108 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54112 updateRows : function(dataSource, firstRow, lastRow){
54113 var s = this.getScrollState();
54115 this.restoreScroll(s);
54118 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54122 this.updateHeaderSortState();
54125 getScrollState : function(){
54127 var sb = this.scroller.dom;
54128 return {left: sb.scrollLeft, top: sb.scrollTop};
54131 stripeRows : function(startRow){
54132 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54135 startRow = startRow || 0;
54136 var rows = this.getBodyTable().rows;
54137 var lrows = this.getLockedTable().rows;
54138 var cls = ' x-grid-row-alt ';
54139 for(var i = startRow, len = rows.length; i < len; i++){
54140 var row = rows[i], lrow = lrows[i];
54141 var isAlt = ((i+1) % 2 == 0);
54142 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54143 if(isAlt == hasAlt){
54147 row.className += " x-grid-row-alt";
54149 row.className = row.className.replace("x-grid-row-alt", "");
54152 lrow.className = row.className;
54157 restoreScroll : function(state){
54158 //Roo.log('GridView.restoreScroll');
54159 var sb = this.scroller.dom;
54160 sb.scrollLeft = state.left;
54161 sb.scrollTop = state.top;
54165 syncScroll : function(){
54166 //Roo.log('GridView.syncScroll');
54167 var sb = this.scroller.dom;
54168 var sh = this.mainHd.dom;
54169 var bs = this.mainBody.dom;
54170 var lv = this.lockedBody.dom;
54171 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54172 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54175 handleScroll : function(e){
54177 var sb = this.scroller.dom;
54178 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54182 handleWheel : function(e){
54183 var d = e.getWheelDelta();
54184 this.scroller.dom.scrollTop -= d*22;
54185 // set this here to prevent jumpy scrolling on large tables
54186 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54190 renderRows : function(startRow, endRow){
54191 // pull in all the crap needed to render rows
54192 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54193 var colCount = cm.getColumnCount();
54195 if(ds.getCount() < 1){
54199 // build a map for all the columns
54201 for(var i = 0; i < colCount; i++){
54202 var name = cm.getDataIndex(i);
54204 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54205 renderer : cm.getRenderer(i),
54206 id : cm.getColumnId(i),
54207 locked : cm.isLocked(i)
54211 startRow = startRow || 0;
54212 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54214 // records to render
54215 var rs = ds.getRange(startRow, endRow);
54217 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54220 // As much as I hate to duplicate code, this was branched because FireFox really hates
54221 // [].join("") on strings. The performance difference was substantial enough to
54222 // branch this function
54223 doRender : Roo.isGecko ?
54224 function(cs, rs, ds, startRow, colCount, stripe){
54225 var ts = this.templates, ct = ts.cell, rt = ts.row;
54227 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54229 var hasListener = this.grid.hasListener('rowclass');
54231 for(var j = 0, len = rs.length; j < len; j++){
54232 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54233 for(var i = 0; i < colCount; i++){
54235 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54237 p.css = p.attr = "";
54238 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54239 if(p.value == undefined || p.value === "") p.value = " ";
54240 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54241 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54243 var markup = ct.apply(p);
54251 if(stripe && ((rowIndex+1) % 2 == 0)){
54252 alt.push("x-grid-row-alt")
54255 alt.push( " x-grid-dirty-row");
54258 if(this.getRowClass){
54259 alt.push(this.getRowClass(r, rowIndex));
54265 rowIndex : rowIndex,
54268 this.grid.fireEvent('rowclass', this, rowcfg);
54269 alt.push(rowcfg.rowClass);
54271 rp.alt = alt.join(" ");
54272 lbuf+= rt.apply(rp);
54274 buf+= rt.apply(rp);
54276 return [lbuf, buf];
54278 function(cs, rs, ds, startRow, colCount, stripe){
54279 var ts = this.templates, ct = ts.cell, rt = ts.row;
54281 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54282 var hasListener = this.grid.hasListener('rowclass');
54285 for(var j = 0, len = rs.length; j < len; j++){
54286 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54287 for(var i = 0; i < colCount; i++){
54289 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54291 p.css = p.attr = "";
54292 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54293 if(p.value == undefined || p.value === "") p.value = " ";
54294 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54295 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54298 var markup = ct.apply(p);
54300 cb[cb.length] = markup;
54302 lcb[lcb.length] = markup;
54306 if(stripe && ((rowIndex+1) % 2 == 0)){
54307 alt.push( "x-grid-row-alt");
54310 alt.push(" x-grid-dirty-row");
54313 if(this.getRowClass){
54314 alt.push( this.getRowClass(r, rowIndex));
54320 rowIndex : rowIndex,
54323 this.grid.fireEvent('rowclass', this, rowcfg);
54324 alt.push(rowcfg.rowClass);
54326 rp.alt = alt.join(" ");
54327 rp.cells = lcb.join("");
54328 lbuf[lbuf.length] = rt.apply(rp);
54329 rp.cells = cb.join("");
54330 buf[buf.length] = rt.apply(rp);
54332 return [lbuf.join(""), buf.join("")];
54335 renderBody : function(){
54336 var markup = this.renderRows();
54337 var bt = this.templates.body;
54338 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54342 * Refreshes the grid
54343 * @param {Boolean} headersToo
54345 refresh : function(headersToo){
54346 this.fireEvent("beforerefresh", this);
54347 this.grid.stopEditing();
54348 var result = this.renderBody();
54349 this.lockedBody.update(result[0]);
54350 this.mainBody.update(result[1]);
54351 if(headersToo === true){
54352 this.updateHeaders();
54353 this.updateColumns();
54354 this.updateSplitters();
54355 this.updateHeaderSortState();
54357 this.syncRowHeights();
54359 this.fireEvent("refresh", this);
54362 handleColumnMove : function(cm, oldIndex, newIndex){
54363 this.indexMap = null;
54364 var s = this.getScrollState();
54365 this.refresh(true);
54366 this.restoreScroll(s);
54367 this.afterMove(newIndex);
54370 afterMove : function(colIndex){
54371 if(this.enableMoveAnim && Roo.enableFx){
54372 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54374 // if multisort - fix sortOrder, and reload..
54375 if (this.grid.dataSource.multiSort) {
54376 // the we can call sort again..
54377 var dm = this.grid.dataSource;
54378 var cm = this.grid.colModel;
54380 for(var i = 0; i < cm.config.length; i++ ) {
54382 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54383 continue; // dont' bother, it's not in sort list or being set.
54386 so.push(cm.config[i].dataIndex);
54389 dm.load(dm.lastOptions);
54396 updateCell : function(dm, rowIndex, dataIndex){
54397 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54398 if(typeof colIndex == "undefined"){ // not present in grid
54401 var cm = this.grid.colModel;
54402 var cell = this.getCell(rowIndex, colIndex);
54403 var cellText = this.getCellText(rowIndex, colIndex);
54406 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54407 id : cm.getColumnId(colIndex),
54408 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54410 var renderer = cm.getRenderer(colIndex);
54411 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54412 if(typeof val == "undefined" || val === "") val = " ";
54413 cellText.innerHTML = val;
54414 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54415 this.syncRowHeights(rowIndex, rowIndex);
54418 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54420 if(this.grid.autoSizeHeaders){
54421 var h = this.getHeaderCellMeasure(colIndex);
54422 maxWidth = Math.max(maxWidth, h.scrollWidth);
54425 if(this.cm.isLocked(colIndex)){
54426 tb = this.getLockedTable();
54429 tb = this.getBodyTable();
54430 index = colIndex - this.cm.getLockedCount();
54433 var rows = tb.rows;
54434 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54435 for(var i = 0; i < stopIndex; i++){
54436 var cell = rows[i].childNodes[index].firstChild;
54437 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54440 return maxWidth + /*margin for error in IE*/ 5;
54443 * Autofit a column to its content.
54444 * @param {Number} colIndex
54445 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54447 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54448 if(this.cm.isHidden(colIndex)){
54449 return; // can't calc a hidden column
54452 var cid = this.cm.getColumnId(colIndex);
54453 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54454 if(this.grid.autoSizeHeaders){
54455 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54458 var newWidth = this.calcColumnWidth(colIndex);
54459 this.cm.setColumnWidth(colIndex,
54460 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54461 if(!suppressEvent){
54462 this.grid.fireEvent("columnresize", colIndex, newWidth);
54467 * Autofits all columns to their content and then expands to fit any extra space in the grid
54469 autoSizeColumns : function(){
54470 var cm = this.grid.colModel;
54471 var colCount = cm.getColumnCount();
54472 for(var i = 0; i < colCount; i++){
54473 this.autoSizeColumn(i, true, true);
54475 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54478 this.updateColumns();
54484 * Autofits all columns to the grid's width proportionate with their current size
54485 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54487 fitColumns : function(reserveScrollSpace){
54488 var cm = this.grid.colModel;
54489 var colCount = cm.getColumnCount();
54493 for (i = 0; i < colCount; i++){
54494 if(!cm.isHidden(i) && !cm.isFixed(i)){
54495 w = cm.getColumnWidth(i);
54501 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54502 if(reserveScrollSpace){
54505 var frac = (avail - cm.getTotalWidth())/width;
54506 while (cols.length){
54509 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54511 this.updateColumns();
54515 onRowSelect : function(rowIndex){
54516 var row = this.getRowComposite(rowIndex);
54517 row.addClass("x-grid-row-selected");
54520 onRowDeselect : function(rowIndex){
54521 var row = this.getRowComposite(rowIndex);
54522 row.removeClass("x-grid-row-selected");
54525 onCellSelect : function(row, col){
54526 var cell = this.getCell(row, col);
54528 Roo.fly(cell).addClass("x-grid-cell-selected");
54532 onCellDeselect : function(row, col){
54533 var cell = this.getCell(row, col);
54535 Roo.fly(cell).removeClass("x-grid-cell-selected");
54539 updateHeaderSortState : function(){
54541 // sort state can be single { field: xxx, direction : yyy}
54542 // or { xxx=>ASC , yyy : DESC ..... }
54545 if (!this.ds.multiSort) {
54546 var state = this.ds.getSortState();
54550 mstate[state.field] = state.direction;
54551 // FIXME... - this is not used here.. but might be elsewhere..
54552 this.sortState = state;
54555 mstate = this.ds.sortToggle;
54557 //remove existing sort classes..
54559 var sc = this.sortClasses;
54560 var hds = this.el.select(this.headerSelector).removeClass(sc);
54562 for(var f in mstate) {
54564 var sortColumn = this.cm.findColumnIndex(f);
54566 if(sortColumn != -1){
54567 var sortDir = mstate[f];
54568 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54577 handleHeaderClick : function(g, index,e){
54579 Roo.log("header click");
54582 // touch events on header are handled by context
54583 this.handleHdCtx(g,index,e);
54588 if(this.headersDisabled){
54591 var dm = g.dataSource, cm = g.colModel;
54592 if(!cm.isSortable(index)){
54597 if (dm.multiSort) {
54598 // update the sortOrder
54600 for(var i = 0; i < cm.config.length; i++ ) {
54602 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54603 continue; // dont' bother, it's not in sort list or being set.
54606 so.push(cm.config[i].dataIndex);
54612 dm.sort(cm.getDataIndex(index));
54616 destroy : function(){
54618 this.colMenu.removeAll();
54619 Roo.menu.MenuMgr.unregister(this.colMenu);
54620 this.colMenu.getEl().remove();
54621 delete this.colMenu;
54624 this.hmenu.removeAll();
54625 Roo.menu.MenuMgr.unregister(this.hmenu);
54626 this.hmenu.getEl().remove();
54629 if(this.grid.enableColumnMove){
54630 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54632 for(var dd in dds){
54633 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54634 var elid = dds[dd].dragElId;
54636 Roo.get(elid).remove();
54637 } else if(dds[dd].config.isTarget){
54638 dds[dd].proxyTop.remove();
54639 dds[dd].proxyBottom.remove();
54642 if(Roo.dd.DDM.locationCache[dd]){
54643 delete Roo.dd.DDM.locationCache[dd];
54646 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54649 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54650 this.bind(null, null);
54651 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54654 handleLockChange : function(){
54655 this.refresh(true);
54658 onDenyColumnLock : function(){
54662 onDenyColumnHide : function(){
54666 handleHdMenuClick : function(item){
54667 var index = this.hdCtxIndex;
54668 var cm = this.cm, ds = this.ds;
54671 ds.sort(cm.getDataIndex(index), "ASC");
54674 ds.sort(cm.getDataIndex(index), "DESC");
54677 var lc = cm.getLockedCount();
54678 if(cm.getColumnCount(true) <= lc+1){
54679 this.onDenyColumnLock();
54683 cm.setLocked(index, true, true);
54684 cm.moveColumn(index, lc);
54685 this.grid.fireEvent("columnmove", index, lc);
54687 cm.setLocked(index, true);
54691 var lc = cm.getLockedCount();
54692 if((lc-1) != index){
54693 cm.setLocked(index, false, true);
54694 cm.moveColumn(index, lc-1);
54695 this.grid.fireEvent("columnmove", index, lc-1);
54697 cm.setLocked(index, false);
54700 case 'wider': // used to expand cols on touch..
54702 var cw = cm.getColumnWidth(index);
54703 cw += (item.id == 'wider' ? 1 : -1) * 50;
54704 cw = Math.max(0, cw);
54705 cw = Math.min(cw,4000);
54706 cm.setColumnWidth(index, cw);
54710 index = cm.getIndexById(item.id.substr(4));
54712 if(item.checked && cm.getColumnCount(true) <= 1){
54713 this.onDenyColumnHide();
54716 cm.setHidden(index, item.checked);
54722 beforeColMenuShow : function(){
54723 var cm = this.cm, colCount = cm.getColumnCount();
54724 this.colMenu.removeAll();
54725 for(var i = 0; i < colCount; i++){
54726 this.colMenu.add(new Roo.menu.CheckItem({
54727 id: "col-"+cm.getColumnId(i),
54728 text: cm.getColumnHeader(i),
54729 checked: !cm.isHidden(i),
54735 handleHdCtx : function(g, index, e){
54737 var hd = this.getHeaderCell(index);
54738 this.hdCtxIndex = index;
54739 var ms = this.hmenu.items, cm = this.cm;
54740 ms.get("asc").setDisabled(!cm.isSortable(index));
54741 ms.get("desc").setDisabled(!cm.isSortable(index));
54742 if(this.grid.enableColLock !== false){
54743 ms.get("lock").setDisabled(cm.isLocked(index));
54744 ms.get("unlock").setDisabled(!cm.isLocked(index));
54746 this.hmenu.show(hd, "tl-bl");
54749 handleHdOver : function(e){
54750 var hd = this.findHeaderCell(e.getTarget());
54751 if(hd && !this.headersDisabled){
54752 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54753 this.fly(hd).addClass("x-grid-hd-over");
54758 handleHdOut : function(e){
54759 var hd = this.findHeaderCell(e.getTarget());
54761 this.fly(hd).removeClass("x-grid-hd-over");
54765 handleSplitDblClick : function(e, t){
54766 var i = this.getCellIndex(t);
54767 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54768 this.autoSizeColumn(i, true);
54773 render : function(){
54776 var colCount = cm.getColumnCount();
54778 if(this.grid.monitorWindowResize === true){
54779 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54781 var header = this.renderHeaders();
54782 var body = this.templates.body.apply({rows:""});
54783 var html = this.templates.master.apply({
54786 lockedHeader: header[0],
54790 //this.updateColumns();
54792 this.grid.getGridEl().dom.innerHTML = html;
54794 this.initElements();
54796 // a kludge to fix the random scolling effect in webkit
54797 this.el.on("scroll", function() {
54798 this.el.dom.scrollTop=0; // hopefully not recursive..
54801 this.scroller.on("scroll", this.handleScroll, this);
54802 this.lockedBody.on("mousewheel", this.handleWheel, this);
54803 this.mainBody.on("mousewheel", this.handleWheel, this);
54805 this.mainHd.on("mouseover", this.handleHdOver, this);
54806 this.mainHd.on("mouseout", this.handleHdOut, this);
54807 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54808 {delegate: "."+this.splitClass});
54810 this.lockedHd.on("mouseover", this.handleHdOver, this);
54811 this.lockedHd.on("mouseout", this.handleHdOut, this);
54812 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54813 {delegate: "."+this.splitClass});
54815 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54816 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54819 this.updateSplitters();
54821 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54822 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54823 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54826 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54827 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54829 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54830 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54832 if(this.grid.enableColLock !== false){
54833 this.hmenu.add('-',
54834 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54835 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54839 this.hmenu.add('-',
54840 {id:"wider", text: this.columnsWiderText},
54841 {id:"narrow", text: this.columnsNarrowText }
54847 if(this.grid.enableColumnHide !== false){
54849 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54850 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54851 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54853 this.hmenu.add('-',
54854 {id:"columns", text: this.columnsText, menu: this.colMenu}
54857 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54859 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54862 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54863 this.dd = new Roo.grid.GridDragZone(this.grid, {
54864 ddGroup : this.grid.ddGroup || 'GridDD'
54870 for(var i = 0; i < colCount; i++){
54871 if(cm.isHidden(i)){
54872 this.hideColumn(i);
54874 if(cm.config[i].align){
54875 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54876 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54880 this.updateHeaderSortState();
54882 this.beforeInitialResize();
54885 // two part rendering gives faster view to the user
54886 this.renderPhase2.defer(1, this);
54889 renderPhase2 : function(){
54890 // render the rows now
54892 if(this.grid.autoSizeColumns){
54893 this.autoSizeColumns();
54897 beforeInitialResize : function(){
54901 onColumnSplitterMoved : function(i, w){
54902 this.userResized = true;
54903 var cm = this.grid.colModel;
54904 cm.setColumnWidth(i, w, true);
54905 var cid = cm.getColumnId(i);
54906 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54907 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54908 this.updateSplitters();
54910 this.grid.fireEvent("columnresize", i, w);
54913 syncRowHeights : function(startIndex, endIndex){
54914 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54915 startIndex = startIndex || 0;
54916 var mrows = this.getBodyTable().rows;
54917 var lrows = this.getLockedTable().rows;
54918 var len = mrows.length-1;
54919 endIndex = Math.min(endIndex || len, len);
54920 for(var i = startIndex; i <= endIndex; i++){
54921 var m = mrows[i], l = lrows[i];
54922 var h = Math.max(m.offsetHeight, l.offsetHeight);
54923 m.style.height = l.style.height = h + "px";
54928 layout : function(initialRender, is2ndPass){
54930 var auto = g.autoHeight;
54931 var scrollOffset = 16;
54932 var c = g.getGridEl(), cm = this.cm,
54933 expandCol = g.autoExpandColumn,
54935 //c.beginMeasure();
54937 if(!c.dom.offsetWidth){ // display:none?
54939 this.lockedWrap.show();
54940 this.mainWrap.show();
54945 var hasLock = this.cm.isLocked(0);
54947 var tbh = this.headerPanel.getHeight();
54948 var bbh = this.footerPanel.getHeight();
54951 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54952 var newHeight = ch + c.getBorderWidth("tb");
54954 newHeight = Math.min(g.maxHeight, newHeight);
54956 c.setHeight(newHeight);
54960 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54963 var s = this.scroller;
54965 var csize = c.getSize(true);
54967 this.el.setSize(csize.width, csize.height);
54969 this.headerPanel.setWidth(csize.width);
54970 this.footerPanel.setWidth(csize.width);
54972 var hdHeight = this.mainHd.getHeight();
54973 var vw = csize.width;
54974 var vh = csize.height - (tbh + bbh);
54978 var bt = this.getBodyTable();
54979 var ltWidth = hasLock ?
54980 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54982 var scrollHeight = bt.offsetHeight;
54983 var scrollWidth = ltWidth + bt.offsetWidth;
54984 var vscroll = false, hscroll = false;
54986 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54988 var lw = this.lockedWrap, mw = this.mainWrap;
54989 var lb = this.lockedBody, mb = this.mainBody;
54991 setTimeout(function(){
54992 var t = s.dom.offsetTop;
54993 var w = s.dom.clientWidth,
54994 h = s.dom.clientHeight;
54997 lw.setSize(ltWidth, h);
54999 mw.setLeftTop(ltWidth, t);
55000 mw.setSize(w-ltWidth, h);
55002 lb.setHeight(h-hdHeight);
55003 mb.setHeight(h-hdHeight);
55005 if(is2ndPass !== true && !gv.userResized && expandCol){
55006 // high speed resize without full column calculation
55008 var ci = cm.getIndexById(expandCol);
55010 ci = cm.findColumnIndex(expandCol);
55012 ci = Math.max(0, ci); // make sure it's got at least the first col.
55013 var expandId = cm.getColumnId(ci);
55014 var tw = cm.getTotalWidth(false);
55015 var currentWidth = cm.getColumnWidth(ci);
55016 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
55017 if(currentWidth != cw){
55018 cm.setColumnWidth(ci, cw, true);
55019 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55020 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
55021 gv.updateSplitters();
55022 gv.layout(false, true);
55034 onWindowResize : function(){
55035 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55041 appendFooter : function(parentEl){
55045 sortAscText : "Sort Ascending",
55046 sortDescText : "Sort Descending",
55047 lockText : "Lock Column",
55048 unlockText : "Unlock Column",
55049 columnsText : "Columns",
55051 columnsWiderText : "Wider",
55052 columnsNarrowText : "Thinner"
55056 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55057 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55058 this.proxy.el.addClass('x-grid3-col-dd');
55061 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55062 handleMouseDown : function(e){
55066 callHandleMouseDown : function(e){
55067 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55072 * Ext JS Library 1.1.1
55073 * Copyright(c) 2006-2007, Ext JS, LLC.
55075 * Originally Released Under LGPL - original licence link has changed is not relivant.
55078 * <script type="text/javascript">
55082 // This is a support class used internally by the Grid components
55083 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55085 this.view = grid.getView();
55086 this.proxy = this.view.resizeProxy;
55087 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55088 "gridSplitters" + this.grid.getGridEl().id, {
55089 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55091 this.setHandleElId(Roo.id(hd));
55092 this.setOuterHandleElId(Roo.id(hd2));
55093 this.scroll = false;
55095 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55096 fly: Roo.Element.fly,
55098 b4StartDrag : function(x, y){
55099 this.view.headersDisabled = true;
55100 this.proxy.setHeight(this.view.mainWrap.getHeight());
55101 var w = this.cm.getColumnWidth(this.cellIndex);
55102 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55103 this.resetConstraints();
55104 this.setXConstraint(minw, 1000);
55105 this.setYConstraint(0, 0);
55106 this.minX = x - minw;
55107 this.maxX = x + 1000;
55109 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55113 handleMouseDown : function(e){
55114 ev = Roo.EventObject.setEvent(e);
55115 var t = this.fly(ev.getTarget());
55116 if(t.hasClass("x-grid-split")){
55117 this.cellIndex = this.view.getCellIndex(t.dom);
55118 this.split = t.dom;
55119 this.cm = this.grid.colModel;
55120 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55121 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55126 endDrag : function(e){
55127 this.view.headersDisabled = false;
55128 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55129 var diff = endX - this.startPos;
55130 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55133 autoOffset : function(){
55134 this.setDelta(0,0);
55138 * Ext JS Library 1.1.1
55139 * Copyright(c) 2006-2007, Ext JS, LLC.
55141 * Originally Released Under LGPL - original licence link has changed is not relivant.
55144 * <script type="text/javascript">
55148 // This is a support class used internally by the Grid components
55149 Roo.grid.GridDragZone = function(grid, config){
55150 this.view = grid.getView();
55151 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55152 if(this.view.lockedBody){
55153 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55154 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55156 this.scroll = false;
55158 this.ddel = document.createElement('div');
55159 this.ddel.className = 'x-grid-dd-wrap';
55162 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55163 ddGroup : "GridDD",
55165 getDragData : function(e){
55166 var t = Roo.lib.Event.getTarget(e);
55167 var rowIndex = this.view.findRowIndex(t);
55168 var sm = this.grid.selModel;
55170 //Roo.log(rowIndex);
55172 if (sm.getSelectedCell) {
55173 // cell selection..
55174 if (!sm.getSelectedCell()) {
55177 if (rowIndex != sm.getSelectedCell()[0]) {
55183 if(rowIndex !== false){
55188 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55190 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55193 if (e.hasModifier()){
55194 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55197 Roo.log("getDragData");
55202 rowIndex: rowIndex,
55203 selections:sm.getSelections ? sm.getSelections() : (
55204 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55211 onInitDrag : function(e){
55212 var data = this.dragData;
55213 this.ddel.innerHTML = this.grid.getDragDropText();
55214 this.proxy.update(this.ddel);
55215 // fire start drag?
55218 afterRepair : function(){
55219 this.dragging = false;
55222 getRepairXY : function(e, data){
55226 onEndDrag : function(data, e){
55230 onValidDrop : function(dd, e, id){
55235 beforeInvalidDrop : function(e, id){
55240 * Ext JS Library 1.1.1
55241 * Copyright(c) 2006-2007, Ext JS, LLC.
55243 * Originally Released Under LGPL - original licence link has changed is not relivant.
55246 * <script type="text/javascript">
55251 * @class Roo.grid.ColumnModel
55252 * @extends Roo.util.Observable
55253 * This is the default implementation of a ColumnModel used by the Grid. It defines
55254 * the columns in the grid.
55257 var colModel = new Roo.grid.ColumnModel([
55258 {header: "Ticker", width: 60, sortable: true, locked: true},
55259 {header: "Company Name", width: 150, sortable: true},
55260 {header: "Market Cap.", width: 100, sortable: true},
55261 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55262 {header: "Employees", width: 100, sortable: true, resizable: false}
55267 * The config options listed for this class are options which may appear in each
55268 * individual column definition.
55269 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55271 * @param {Object} config An Array of column config objects. See this class's
55272 * config objects for details.
55274 Roo.grid.ColumnModel = function(config){
55276 * The config passed into the constructor
55278 this.config = config;
55281 // if no id, create one
55282 // if the column does not have a dataIndex mapping,
55283 // map it to the order it is in the config
55284 for(var i = 0, len = config.length; i < len; i++){
55286 if(typeof c.dataIndex == "undefined"){
55289 if(typeof c.renderer == "string"){
55290 c.renderer = Roo.util.Format[c.renderer];
55292 if(typeof c.id == "undefined"){
55295 if(c.editor && c.editor.xtype){
55296 c.editor = Roo.factory(c.editor, Roo.grid);
55298 if(c.editor && c.editor.isFormField){
55299 c.editor = new Roo.grid.GridEditor(c.editor);
55301 this.lookup[c.id] = c;
55305 * The width of columns which have no width specified (defaults to 100)
55308 this.defaultWidth = 100;
55311 * Default sortable of columns which have no sortable specified (defaults to false)
55314 this.defaultSortable = false;
55318 * @event widthchange
55319 * Fires when the width of a column changes.
55320 * @param {ColumnModel} this
55321 * @param {Number} columnIndex The column index
55322 * @param {Number} newWidth The new width
55324 "widthchange": true,
55326 * @event headerchange
55327 * Fires when the text of a header changes.
55328 * @param {ColumnModel} this
55329 * @param {Number} columnIndex The column index
55330 * @param {Number} newText The new header text
55332 "headerchange": true,
55334 * @event hiddenchange
55335 * Fires when a column is hidden or "unhidden".
55336 * @param {ColumnModel} this
55337 * @param {Number} columnIndex The column index
55338 * @param {Boolean} hidden true if hidden, false otherwise
55340 "hiddenchange": true,
55342 * @event columnmoved
55343 * Fires when a column is moved.
55344 * @param {ColumnModel} this
55345 * @param {Number} oldIndex
55346 * @param {Number} newIndex
55348 "columnmoved" : true,
55350 * @event columlockchange
55351 * Fires when a column's locked state is changed
55352 * @param {ColumnModel} this
55353 * @param {Number} colIndex
55354 * @param {Boolean} locked true if locked
55356 "columnlockchange" : true
55358 Roo.grid.ColumnModel.superclass.constructor.call(this);
55360 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55362 * @cfg {String} header The header text to display in the Grid view.
55365 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55366 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55367 * specified, the column's index is used as an index into the Record's data Array.
55370 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55371 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55374 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55375 * Defaults to the value of the {@link #defaultSortable} property.
55376 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55379 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55382 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55385 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55388 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55391 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55392 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55393 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55394 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55397 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55400 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55403 * @cfg {String} cursor (Optional)
55406 * @cfg {String} tooltip (Optional)
55409 * Returns the id of the column at the specified index.
55410 * @param {Number} index The column index
55411 * @return {String} the id
55413 getColumnId : function(index){
55414 return this.config[index].id;
55418 * Returns the column for a specified id.
55419 * @param {String} id The column id
55420 * @return {Object} the column
55422 getColumnById : function(id){
55423 return this.lookup[id];
55428 * Returns the column for a specified dataIndex.
55429 * @param {String} dataIndex The column dataIndex
55430 * @return {Object|Boolean} the column or false if not found
55432 getColumnByDataIndex: function(dataIndex){
55433 var index = this.findColumnIndex(dataIndex);
55434 return index > -1 ? this.config[index] : false;
55438 * Returns the index for a specified column id.
55439 * @param {String} id The column id
55440 * @return {Number} the index, or -1 if not found
55442 getIndexById : function(id){
55443 for(var i = 0, len = this.config.length; i < len; i++){
55444 if(this.config[i].id == id){
55452 * Returns the index for a specified column dataIndex.
55453 * @param {String} dataIndex The column dataIndex
55454 * @return {Number} the index, or -1 if not found
55457 findColumnIndex : function(dataIndex){
55458 for(var i = 0, len = this.config.length; i < len; i++){
55459 if(this.config[i].dataIndex == dataIndex){
55467 moveColumn : function(oldIndex, newIndex){
55468 var c = this.config[oldIndex];
55469 this.config.splice(oldIndex, 1);
55470 this.config.splice(newIndex, 0, c);
55471 this.dataMap = null;
55472 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55475 isLocked : function(colIndex){
55476 return this.config[colIndex].locked === true;
55479 setLocked : function(colIndex, value, suppressEvent){
55480 if(this.isLocked(colIndex) == value){
55483 this.config[colIndex].locked = value;
55484 if(!suppressEvent){
55485 this.fireEvent("columnlockchange", this, colIndex, value);
55489 getTotalLockedWidth : function(){
55490 var totalWidth = 0;
55491 for(var i = 0; i < this.config.length; i++){
55492 if(this.isLocked(i) && !this.isHidden(i)){
55493 this.totalWidth += this.getColumnWidth(i);
55499 getLockedCount : function(){
55500 for(var i = 0, len = this.config.length; i < len; i++){
55501 if(!this.isLocked(i)){
55508 * Returns the number of columns.
55511 getColumnCount : function(visibleOnly){
55512 if(visibleOnly === true){
55514 for(var i = 0, len = this.config.length; i < len; i++){
55515 if(!this.isHidden(i)){
55521 return this.config.length;
55525 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55526 * @param {Function} fn
55527 * @param {Object} scope (optional)
55528 * @return {Array} result
55530 getColumnsBy : function(fn, scope){
55532 for(var i = 0, len = this.config.length; i < len; i++){
55533 var c = this.config[i];
55534 if(fn.call(scope||this, c, i) === true){
55542 * Returns true if the specified column is sortable.
55543 * @param {Number} col The column index
55544 * @return {Boolean}
55546 isSortable : function(col){
55547 if(typeof this.config[col].sortable == "undefined"){
55548 return this.defaultSortable;
55550 return this.config[col].sortable;
55554 * Returns the rendering (formatting) function defined for the column.
55555 * @param {Number} col The column index.
55556 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55558 getRenderer : function(col){
55559 if(!this.config[col].renderer){
55560 return Roo.grid.ColumnModel.defaultRenderer;
55562 return this.config[col].renderer;
55566 * Sets the rendering (formatting) function for a column.
55567 * @param {Number} col The column index
55568 * @param {Function} fn The function to use to process the cell's raw data
55569 * to return HTML markup for the grid view. The render function is called with
55570 * the following parameters:<ul>
55571 * <li>Data value.</li>
55572 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55573 * <li>css A CSS style string to apply to the table cell.</li>
55574 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55575 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55576 * <li>Row index</li>
55577 * <li>Column index</li>
55578 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55580 setRenderer : function(col, fn){
55581 this.config[col].renderer = fn;
55585 * Returns the width for the specified column.
55586 * @param {Number} col The column index
55589 getColumnWidth : function(col){
55590 return this.config[col].width * 1 || this.defaultWidth;
55594 * Sets the width for a column.
55595 * @param {Number} col The column index
55596 * @param {Number} width The new width
55598 setColumnWidth : function(col, width, suppressEvent){
55599 this.config[col].width = width;
55600 this.totalWidth = null;
55601 if(!suppressEvent){
55602 this.fireEvent("widthchange", this, col, width);
55607 * Returns the total width of all columns.
55608 * @param {Boolean} includeHidden True to include hidden column widths
55611 getTotalWidth : function(includeHidden){
55612 if(!this.totalWidth){
55613 this.totalWidth = 0;
55614 for(var i = 0, len = this.config.length; i < len; i++){
55615 if(includeHidden || !this.isHidden(i)){
55616 this.totalWidth += this.getColumnWidth(i);
55620 return this.totalWidth;
55624 * Returns the header for the specified column.
55625 * @param {Number} col The column index
55628 getColumnHeader : function(col){
55629 return this.config[col].header;
55633 * Sets the header for a column.
55634 * @param {Number} col The column index
55635 * @param {String} header The new header
55637 setColumnHeader : function(col, header){
55638 this.config[col].header = header;
55639 this.fireEvent("headerchange", this, col, header);
55643 * Returns the tooltip for the specified column.
55644 * @param {Number} col The column index
55647 getColumnTooltip : function(col){
55648 return this.config[col].tooltip;
55651 * Sets the tooltip for a column.
55652 * @param {Number} col The column index
55653 * @param {String} tooltip The new tooltip
55655 setColumnTooltip : function(col, tooltip){
55656 this.config[col].tooltip = tooltip;
55660 * Returns the dataIndex for the specified column.
55661 * @param {Number} col The column index
55664 getDataIndex : function(col){
55665 return this.config[col].dataIndex;
55669 * Sets the dataIndex for a column.
55670 * @param {Number} col The column index
55671 * @param {Number} dataIndex The new dataIndex
55673 setDataIndex : function(col, dataIndex){
55674 this.config[col].dataIndex = dataIndex;
55680 * Returns true if the cell is editable.
55681 * @param {Number} colIndex The column index
55682 * @param {Number} rowIndex The row index
55683 * @return {Boolean}
55685 isCellEditable : function(colIndex, rowIndex){
55686 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55690 * Returns the editor defined for the cell/column.
55691 * return false or null to disable editing.
55692 * @param {Number} colIndex The column index
55693 * @param {Number} rowIndex The row index
55696 getCellEditor : function(colIndex, rowIndex){
55697 return this.config[colIndex].editor;
55701 * Sets if a column is editable.
55702 * @param {Number} col The column index
55703 * @param {Boolean} editable True if the column is editable
55705 setEditable : function(col, editable){
55706 this.config[col].editable = editable;
55711 * Returns true if the column is hidden.
55712 * @param {Number} colIndex The column index
55713 * @return {Boolean}
55715 isHidden : function(colIndex){
55716 return this.config[colIndex].hidden;
55721 * Returns true if the column width cannot be changed
55723 isFixed : function(colIndex){
55724 return this.config[colIndex].fixed;
55728 * Returns true if the column can be resized
55729 * @return {Boolean}
55731 isResizable : function(colIndex){
55732 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55735 * Sets if a column is hidden.
55736 * @param {Number} colIndex The column index
55737 * @param {Boolean} hidden True if the column is hidden
55739 setHidden : function(colIndex, hidden){
55740 this.config[colIndex].hidden = hidden;
55741 this.totalWidth = null;
55742 this.fireEvent("hiddenchange", this, colIndex, hidden);
55746 * Sets the editor for a column.
55747 * @param {Number} col The column index
55748 * @param {Object} editor The editor object
55750 setEditor : function(col, editor){
55751 this.config[col].editor = editor;
55755 Roo.grid.ColumnModel.defaultRenderer = function(value){
55756 if(typeof value == "string" && value.length < 1){
55762 // Alias for backwards compatibility
55763 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55766 * Ext JS Library 1.1.1
55767 * Copyright(c) 2006-2007, Ext JS, LLC.
55769 * Originally Released Under LGPL - original licence link has changed is not relivant.
55772 * <script type="text/javascript">
55776 * @class Roo.grid.AbstractSelectionModel
55777 * @extends Roo.util.Observable
55778 * Abstract base class for grid SelectionModels. It provides the interface that should be
55779 * implemented by descendant classes. This class should not be directly instantiated.
55782 Roo.grid.AbstractSelectionModel = function(){
55783 this.locked = false;
55784 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55787 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55788 /** @ignore Called by the grid automatically. Do not call directly. */
55789 init : function(grid){
55795 * Locks the selections.
55798 this.locked = true;
55802 * Unlocks the selections.
55804 unlock : function(){
55805 this.locked = false;
55809 * Returns true if the selections are locked.
55810 * @return {Boolean}
55812 isLocked : function(){
55813 return this.locked;
55817 * Ext JS Library 1.1.1
55818 * Copyright(c) 2006-2007, Ext JS, LLC.
55820 * Originally Released Under LGPL - original licence link has changed is not relivant.
55823 * <script type="text/javascript">
55826 * @extends Roo.grid.AbstractSelectionModel
55827 * @class Roo.grid.RowSelectionModel
55828 * The default SelectionModel used by {@link Roo.grid.Grid}.
55829 * It supports multiple selections and keyboard selection/navigation.
55831 * @param {Object} config
55833 Roo.grid.RowSelectionModel = function(config){
55834 Roo.apply(this, config);
55835 this.selections = new Roo.util.MixedCollection(false, function(o){
55840 this.lastActive = false;
55844 * @event selectionchange
55845 * Fires when the selection changes
55846 * @param {SelectionModel} this
55848 "selectionchange" : true,
55850 * @event afterselectionchange
55851 * Fires after the selection changes (eg. by key press or clicking)
55852 * @param {SelectionModel} this
55854 "afterselectionchange" : true,
55856 * @event beforerowselect
55857 * Fires when a row is selected being selected, return false to cancel.
55858 * @param {SelectionModel} this
55859 * @param {Number} rowIndex The selected index
55860 * @param {Boolean} keepExisting False if other selections will be cleared
55862 "beforerowselect" : true,
55865 * Fires when a row is selected.
55866 * @param {SelectionModel} this
55867 * @param {Number} rowIndex The selected index
55868 * @param {Roo.data.Record} r The record
55870 "rowselect" : true,
55872 * @event rowdeselect
55873 * Fires when a row is deselected.
55874 * @param {SelectionModel} this
55875 * @param {Number} rowIndex The selected index
55877 "rowdeselect" : true
55879 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55880 this.locked = false;
55883 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55885 * @cfg {Boolean} singleSelect
55886 * True to allow selection of only one row at a time (defaults to false)
55888 singleSelect : false,
55891 initEvents : function(){
55893 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55894 this.grid.on("mousedown", this.handleMouseDown, this);
55895 }else{ // allow click to work like normal
55896 this.grid.on("rowclick", this.handleDragableRowClick, this);
55899 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55900 "up" : function(e){
55902 this.selectPrevious(e.shiftKey);
55903 }else if(this.last !== false && this.lastActive !== false){
55904 var last = this.last;
55905 this.selectRange(this.last, this.lastActive-1);
55906 this.grid.getView().focusRow(this.lastActive);
55907 if(last !== false){
55911 this.selectFirstRow();
55913 this.fireEvent("afterselectionchange", this);
55915 "down" : function(e){
55917 this.selectNext(e.shiftKey);
55918 }else if(this.last !== false && this.lastActive !== false){
55919 var last = this.last;
55920 this.selectRange(this.last, this.lastActive+1);
55921 this.grid.getView().focusRow(this.lastActive);
55922 if(last !== false){
55926 this.selectFirstRow();
55928 this.fireEvent("afterselectionchange", this);
55933 var view = this.grid.view;
55934 view.on("refresh", this.onRefresh, this);
55935 view.on("rowupdated", this.onRowUpdated, this);
55936 view.on("rowremoved", this.onRemove, this);
55940 onRefresh : function(){
55941 var ds = this.grid.dataSource, i, v = this.grid.view;
55942 var s = this.selections;
55943 s.each(function(r){
55944 if((i = ds.indexOfId(r.id)) != -1){
55946 s.add(ds.getAt(i)); // updating the selection relate data
55954 onRemove : function(v, index, r){
55955 this.selections.remove(r);
55959 onRowUpdated : function(v, index, r){
55960 if(this.isSelected(r)){
55961 v.onRowSelect(index);
55967 * @param {Array} records The records to select
55968 * @param {Boolean} keepExisting (optional) True to keep existing selections
55970 selectRecords : function(records, keepExisting){
55972 this.clearSelections();
55974 var ds = this.grid.dataSource;
55975 for(var i = 0, len = records.length; i < len; i++){
55976 this.selectRow(ds.indexOf(records[i]), true);
55981 * Gets the number of selected rows.
55984 getCount : function(){
55985 return this.selections.length;
55989 * Selects the first row in the grid.
55991 selectFirstRow : function(){
55996 * Select the last row.
55997 * @param {Boolean} keepExisting (optional) True to keep existing selections
55999 selectLastRow : function(keepExisting){
56000 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
56004 * Selects the row immediately following the last selected row.
56005 * @param {Boolean} keepExisting (optional) True to keep existing selections
56007 selectNext : function(keepExisting){
56008 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
56009 this.selectRow(this.last+1, keepExisting);
56010 this.grid.getView().focusRow(this.last);
56015 * Selects the row that precedes the last selected row.
56016 * @param {Boolean} keepExisting (optional) True to keep existing selections
56018 selectPrevious : function(keepExisting){
56020 this.selectRow(this.last-1, keepExisting);
56021 this.grid.getView().focusRow(this.last);
56026 * Returns the selected records
56027 * @return {Array} Array of selected records
56029 getSelections : function(){
56030 return [].concat(this.selections.items);
56034 * Returns the first selected record.
56037 getSelected : function(){
56038 return this.selections.itemAt(0);
56043 * Clears all selections.
56045 clearSelections : function(fast){
56046 if(this.locked) return;
56048 var ds = this.grid.dataSource;
56049 var s = this.selections;
56050 s.each(function(r){
56051 this.deselectRow(ds.indexOfId(r.id));
56055 this.selections.clear();
56062 * Selects all rows.
56064 selectAll : function(){
56065 if(this.locked) return;
56066 this.selections.clear();
56067 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56068 this.selectRow(i, true);
56073 * Returns True if there is a selection.
56074 * @return {Boolean}
56076 hasSelection : function(){
56077 return this.selections.length > 0;
56081 * Returns True if the specified row is selected.
56082 * @param {Number/Record} record The record or index of the record to check
56083 * @return {Boolean}
56085 isSelected : function(index){
56086 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56087 return (r && this.selections.key(r.id) ? true : false);
56091 * Returns True if the specified record id is selected.
56092 * @param {String} id The id of record to check
56093 * @return {Boolean}
56095 isIdSelected : function(id){
56096 return (this.selections.key(id) ? true : false);
56100 handleMouseDown : function(e, t){
56101 var view = this.grid.getView(), rowIndex;
56102 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56105 if(e.shiftKey && this.last !== false){
56106 var last = this.last;
56107 this.selectRange(last, rowIndex, e.ctrlKey);
56108 this.last = last; // reset the last
56109 view.focusRow(rowIndex);
56111 var isSelected = this.isSelected(rowIndex);
56112 if(e.button !== 0 && isSelected){
56113 view.focusRow(rowIndex);
56114 }else if(e.ctrlKey && isSelected){
56115 this.deselectRow(rowIndex);
56116 }else if(!isSelected){
56117 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56118 view.focusRow(rowIndex);
56121 this.fireEvent("afterselectionchange", this);
56124 handleDragableRowClick : function(grid, rowIndex, e)
56126 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56127 this.selectRow(rowIndex, false);
56128 grid.view.focusRow(rowIndex);
56129 this.fireEvent("afterselectionchange", this);
56134 * Selects multiple rows.
56135 * @param {Array} rows Array of the indexes of the row to select
56136 * @param {Boolean} keepExisting (optional) True to keep existing selections
56138 selectRows : function(rows, keepExisting){
56140 this.clearSelections();
56142 for(var i = 0, len = rows.length; i < len; i++){
56143 this.selectRow(rows[i], true);
56148 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56149 * @param {Number} startRow The index of the first row in the range
56150 * @param {Number} endRow The index of the last row in the range
56151 * @param {Boolean} keepExisting (optional) True to retain existing selections
56153 selectRange : function(startRow, endRow, keepExisting){
56154 if(this.locked) return;
56156 this.clearSelections();
56158 if(startRow <= endRow){
56159 for(var i = startRow; i <= endRow; i++){
56160 this.selectRow(i, true);
56163 for(var i = startRow; i >= endRow; i--){
56164 this.selectRow(i, true);
56170 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56171 * @param {Number} startRow The index of the first row in the range
56172 * @param {Number} endRow The index of the last row in the range
56174 deselectRange : function(startRow, endRow, preventViewNotify){
56175 if(this.locked) return;
56176 for(var i = startRow; i <= endRow; i++){
56177 this.deselectRow(i, preventViewNotify);
56183 * @param {Number} row The index of the row to select
56184 * @param {Boolean} keepExisting (optional) True to keep existing selections
56186 selectRow : function(index, keepExisting, preventViewNotify){
56187 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56188 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56189 if(!keepExisting || this.singleSelect){
56190 this.clearSelections();
56192 var r = this.grid.dataSource.getAt(index);
56193 this.selections.add(r);
56194 this.last = this.lastActive = index;
56195 if(!preventViewNotify){
56196 this.grid.getView().onRowSelect(index);
56198 this.fireEvent("rowselect", this, index, r);
56199 this.fireEvent("selectionchange", this);
56205 * @param {Number} row The index of the row to deselect
56207 deselectRow : function(index, preventViewNotify){
56208 if(this.locked) return;
56209 if(this.last == index){
56212 if(this.lastActive == index){
56213 this.lastActive = false;
56215 var r = this.grid.dataSource.getAt(index);
56216 this.selections.remove(r);
56217 if(!preventViewNotify){
56218 this.grid.getView().onRowDeselect(index);
56220 this.fireEvent("rowdeselect", this, index);
56221 this.fireEvent("selectionchange", this);
56225 restoreLast : function(){
56227 this.last = this._last;
56232 acceptsNav : function(row, col, cm){
56233 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56237 onEditorKey : function(field, e){
56238 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56243 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56245 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56247 }else if(k == e.ENTER && !e.ctrlKey){
56251 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56253 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56255 }else if(k == e.ESC){
56259 g.startEditing(newCell[0], newCell[1]);
56264 * Ext JS Library 1.1.1
56265 * Copyright(c) 2006-2007, Ext JS, LLC.
56267 * Originally Released Under LGPL - original licence link has changed is not relivant.
56270 * <script type="text/javascript">
56273 * @class Roo.grid.CellSelectionModel
56274 * @extends Roo.grid.AbstractSelectionModel
56275 * This class provides the basic implementation for cell selection in a grid.
56277 * @param {Object} config The object containing the configuration of this model.
56278 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56280 Roo.grid.CellSelectionModel = function(config){
56281 Roo.apply(this, config);
56283 this.selection = null;
56287 * @event beforerowselect
56288 * Fires before a cell is selected.
56289 * @param {SelectionModel} this
56290 * @param {Number} rowIndex The selected row index
56291 * @param {Number} colIndex The selected cell index
56293 "beforecellselect" : true,
56295 * @event cellselect
56296 * Fires when a cell is selected.
56297 * @param {SelectionModel} this
56298 * @param {Number} rowIndex The selected row index
56299 * @param {Number} colIndex The selected cell index
56301 "cellselect" : true,
56303 * @event selectionchange
56304 * Fires when the active selection changes.
56305 * @param {SelectionModel} this
56306 * @param {Object} selection null for no selection or an object (o) with two properties
56308 <li>o.record: the record object for the row the selection is in</li>
56309 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56312 "selectionchange" : true,
56315 * Fires when the tab (or enter) was pressed on the last editable cell
56316 * You can use this to trigger add new row.
56317 * @param {SelectionModel} this
56321 * @event beforeeditnext
56322 * Fires before the next editable sell is made active
56323 * You can use this to skip to another cell or fire the tabend
56324 * if you set cell to false
56325 * @param {Object} eventdata object : { cell : [ row, col ] }
56327 "beforeeditnext" : true
56329 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56332 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56334 enter_is_tab: false,
56337 initEvents : function(){
56338 this.grid.on("mousedown", this.handleMouseDown, this);
56339 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56340 var view = this.grid.view;
56341 view.on("refresh", this.onViewChange, this);
56342 view.on("rowupdated", this.onRowUpdated, this);
56343 view.on("beforerowremoved", this.clearSelections, this);
56344 view.on("beforerowsinserted", this.clearSelections, this);
56345 if(this.grid.isEditor){
56346 this.grid.on("beforeedit", this.beforeEdit, this);
56351 beforeEdit : function(e){
56352 this.select(e.row, e.column, false, true, e.record);
56356 onRowUpdated : function(v, index, r){
56357 if(this.selection && this.selection.record == r){
56358 v.onCellSelect(index, this.selection.cell[1]);
56363 onViewChange : function(){
56364 this.clearSelections(true);
56368 * Returns the currently selected cell,.
56369 * @return {Array} The selected cell (row, column) or null if none selected.
56371 getSelectedCell : function(){
56372 return this.selection ? this.selection.cell : null;
56376 * Clears all selections.
56377 * @param {Boolean} true to prevent the gridview from being notified about the change.
56379 clearSelections : function(preventNotify){
56380 var s = this.selection;
56382 if(preventNotify !== true){
56383 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56385 this.selection = null;
56386 this.fireEvent("selectionchange", this, null);
56391 * Returns true if there is a selection.
56392 * @return {Boolean}
56394 hasSelection : function(){
56395 return this.selection ? true : false;
56399 handleMouseDown : function(e, t){
56400 var v = this.grid.getView();
56401 if(this.isLocked()){
56404 var row = v.findRowIndex(t);
56405 var cell = v.findCellIndex(t);
56406 if(row !== false && cell !== false){
56407 this.select(row, cell);
56413 * @param {Number} rowIndex
56414 * @param {Number} collIndex
56416 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56417 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56418 this.clearSelections();
56419 r = r || this.grid.dataSource.getAt(rowIndex);
56422 cell : [rowIndex, colIndex]
56424 if(!preventViewNotify){
56425 var v = this.grid.getView();
56426 v.onCellSelect(rowIndex, colIndex);
56427 if(preventFocus !== true){
56428 v.focusCell(rowIndex, colIndex);
56431 this.fireEvent("cellselect", this, rowIndex, colIndex);
56432 this.fireEvent("selectionchange", this, this.selection);
56437 isSelectable : function(rowIndex, colIndex, cm){
56438 return !cm.isHidden(colIndex);
56442 handleKeyDown : function(e){
56443 //Roo.log('Cell Sel Model handleKeyDown');
56444 if(!e.isNavKeyPress()){
56447 var g = this.grid, s = this.selection;
56450 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56452 this.select(cell[0], cell[1]);
56457 var walk = function(row, col, step){
56458 return g.walkCells(row, col, step, sm.isSelectable, sm);
56460 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56467 // handled by onEditorKey
56468 if (g.isEditor && g.editing) {
56472 newCell = walk(r, c-1, -1);
56474 newCell = walk(r, c+1, 1);
56479 newCell = walk(r+1, c, 1);
56483 newCell = walk(r-1, c, -1);
56487 newCell = walk(r, c+1, 1);
56491 newCell = walk(r, c-1, -1);
56496 if(g.isEditor && !g.editing){
56497 g.startEditing(r, c);
56506 this.select(newCell[0], newCell[1]);
56512 acceptsNav : function(row, col, cm){
56513 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56517 * @param {Number} field (not used) - as it's normally used as a listener
56518 * @param {Number} e - event - fake it by using
56520 * var e = Roo.EventObjectImpl.prototype;
56521 * e.keyCode = e.TAB
56525 onEditorKey : function(field, e){
56527 var k = e.getKey(),
56530 ed = g.activeEditor,
56532 ///Roo.log('onEditorKey' + k);
56535 if (this.enter_is_tab && k == e.ENTER) {
56541 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56543 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56549 } else if(k == e.ENTER && !e.ctrlKey){
56552 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56554 } else if(k == e.ESC){
56559 var ecall = { cell : newCell, forward : forward };
56560 this.fireEvent('beforeeditnext', ecall );
56561 newCell = ecall.cell;
56562 forward = ecall.forward;
56566 //Roo.log('next cell after edit');
56567 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56568 } else if (forward) {
56569 // tabbed past last
56570 this.fireEvent.defer(100, this, ['tabend',this]);
56575 * Ext JS Library 1.1.1
56576 * Copyright(c) 2006-2007, Ext JS, LLC.
56578 * Originally Released Under LGPL - original licence link has changed is not relivant.
56581 * <script type="text/javascript">
56585 * @class Roo.grid.EditorGrid
56586 * @extends Roo.grid.Grid
56587 * Class for creating and editable grid.
56588 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56589 * The container MUST have some type of size defined for the grid to fill. The container will be
56590 * automatically set to position relative if it isn't already.
56591 * @param {Object} dataSource The data model to bind to
56592 * @param {Object} colModel The column model with info about this grid's columns
56594 Roo.grid.EditorGrid = function(container, config){
56595 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56596 this.getGridEl().addClass("xedit-grid");
56598 if(!this.selModel){
56599 this.selModel = new Roo.grid.CellSelectionModel();
56602 this.activeEditor = null;
56606 * @event beforeedit
56607 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56608 * <ul style="padding:5px;padding-left:16px;">
56609 * <li>grid - This grid</li>
56610 * <li>record - The record being edited</li>
56611 * <li>field - The field name being edited</li>
56612 * <li>value - The value for the field being edited.</li>
56613 * <li>row - The grid row index</li>
56614 * <li>column - The grid column index</li>
56615 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56617 * @param {Object} e An edit event (see above for description)
56619 "beforeedit" : true,
56622 * Fires after a cell is edited. <br />
56623 * <ul style="padding:5px;padding-left:16px;">
56624 * <li>grid - This grid</li>
56625 * <li>record - The record being edited</li>
56626 * <li>field - The field name being edited</li>
56627 * <li>value - The value being set</li>
56628 * <li>originalValue - The original value for the field, before the edit.</li>
56629 * <li>row - The grid row index</li>
56630 * <li>column - The grid column index</li>
56632 * @param {Object} e An edit event (see above for description)
56634 "afteredit" : true,
56636 * @event validateedit
56637 * Fires after a cell is edited, but before the value is set in the record.
56638 * You can use this to modify the value being set in the field, Return false
56639 * to cancel the change. The edit event object has the following properties <br />
56640 * <ul style="padding:5px;padding-left:16px;">
56641 * <li>editor - This editor</li>
56642 * <li>grid - This grid</li>
56643 * <li>record - The record being edited</li>
56644 * <li>field - The field name being edited</li>
56645 * <li>value - The value being set</li>
56646 * <li>originalValue - The original value for the field, before the edit.</li>
56647 * <li>row - The grid row index</li>
56648 * <li>column - The grid column index</li>
56649 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56651 * @param {Object} e An edit event (see above for description)
56653 "validateedit" : true
56655 this.on("bodyscroll", this.stopEditing, this);
56656 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56659 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56661 * @cfg {Number} clicksToEdit
56662 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56669 trackMouseOver: false, // causes very odd FF errors
56671 onCellDblClick : function(g, row, col){
56672 this.startEditing(row, col);
56675 onEditComplete : function(ed, value, startValue){
56676 this.editing = false;
56677 this.activeEditor = null;
56678 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56680 var field = this.colModel.getDataIndex(ed.col);
56685 originalValue: startValue,
56692 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56695 if(String(value) !== String(startValue)){
56697 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56698 r.set(field, e.value);
56699 // if we are dealing with a combo box..
56700 // then we also set the 'name' colum to be the displayField
56701 if (ed.field.displayField && ed.field.name) {
56702 r.set(ed.field.name, ed.field.el.dom.value);
56705 delete e.cancel; //?? why!!!
56706 this.fireEvent("afteredit", e);
56709 this.fireEvent("afteredit", e); // always fire it!
56711 this.view.focusCell(ed.row, ed.col);
56715 * Starts editing the specified for the specified row/column
56716 * @param {Number} rowIndex
56717 * @param {Number} colIndex
56719 startEditing : function(row, col){
56720 this.stopEditing();
56721 if(this.colModel.isCellEditable(col, row)){
56722 this.view.ensureVisible(row, col, true);
56724 var r = this.dataSource.getAt(row);
56725 var field = this.colModel.getDataIndex(col);
56726 var cell = Roo.get(this.view.getCell(row,col));
56731 value: r.data[field],
56736 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56737 this.editing = true;
56738 var ed = this.colModel.getCellEditor(col, row);
56744 ed.render(ed.parentEl || document.body);
56750 (function(){ // complex but required for focus issues in safari, ie and opera
56754 ed.on("complete", this.onEditComplete, this, {single: true});
56755 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56756 this.activeEditor = ed;
56757 var v = r.data[field];
56758 ed.startEdit(this.view.getCell(row, col), v);
56759 // combo's with 'displayField and name set
56760 if (ed.field.displayField && ed.field.name) {
56761 ed.field.el.dom.value = r.data[ed.field.name];
56765 }).defer(50, this);
56771 * Stops any active editing
56773 stopEditing : function(){
56774 if(this.activeEditor){
56775 this.activeEditor.completeEdit();
56777 this.activeEditor = null;
56781 * Called to get grid's drag proxy text, by default returns this.ddText.
56784 getDragDropText : function(){
56785 var count = this.selModel.getSelectedCell() ? 1 : 0;
56786 return String.format(this.ddText, count, count == 1 ? '' : 's');
56791 * Ext JS Library 1.1.1
56792 * Copyright(c) 2006-2007, Ext JS, LLC.
56794 * Originally Released Under LGPL - original licence link has changed is not relivant.
56797 * <script type="text/javascript">
56800 // private - not really -- you end up using it !
56801 // This is a support class used internally by the Grid components
56804 * @class Roo.grid.GridEditor
56805 * @extends Roo.Editor
56806 * Class for creating and editable grid elements.
56807 * @param {Object} config any settings (must include field)
56809 Roo.grid.GridEditor = function(field, config){
56810 if (!config && field.field) {
56812 field = Roo.factory(config.field, Roo.form);
56814 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56815 field.monitorTab = false;
56818 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56821 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56824 alignment: "tl-tl",
56827 cls: "x-small-editor x-grid-editor",
56832 * Ext JS Library 1.1.1
56833 * Copyright(c) 2006-2007, Ext JS, LLC.
56835 * Originally Released Under LGPL - original licence link has changed is not relivant.
56838 * <script type="text/javascript">
56843 Roo.grid.PropertyRecord = Roo.data.Record.create([
56844 {name:'name',type:'string'}, 'value'
56848 Roo.grid.PropertyStore = function(grid, source){
56850 this.store = new Roo.data.Store({
56851 recordType : Roo.grid.PropertyRecord
56853 this.store.on('update', this.onUpdate, this);
56855 this.setSource(source);
56857 Roo.grid.PropertyStore.superclass.constructor.call(this);
56862 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56863 setSource : function(o){
56865 this.store.removeAll();
56868 if(this.isEditableValue(o[k])){
56869 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56872 this.store.loadRecords({records: data}, {}, true);
56875 onUpdate : function(ds, record, type){
56876 if(type == Roo.data.Record.EDIT){
56877 var v = record.data['value'];
56878 var oldValue = record.modified['value'];
56879 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56880 this.source[record.id] = v;
56882 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56889 getProperty : function(row){
56890 return this.store.getAt(row);
56893 isEditableValue: function(val){
56894 if(val && val instanceof Date){
56896 }else if(typeof val == 'object' || typeof val == 'function'){
56902 setValue : function(prop, value){
56903 this.source[prop] = value;
56904 this.store.getById(prop).set('value', value);
56907 getSource : function(){
56908 return this.source;
56912 Roo.grid.PropertyColumnModel = function(grid, store){
56915 g.PropertyColumnModel.superclass.constructor.call(this, [
56916 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56917 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56919 this.store = store;
56920 this.bselect = Roo.DomHelper.append(document.body, {
56921 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56922 {tag: 'option', value: 'true', html: 'true'},
56923 {tag: 'option', value: 'false', html: 'false'}
56926 Roo.id(this.bselect);
56929 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56930 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56931 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56932 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56933 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56935 this.renderCellDelegate = this.renderCell.createDelegate(this);
56936 this.renderPropDelegate = this.renderProp.createDelegate(this);
56939 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56943 valueText : 'Value',
56945 dateFormat : 'm/j/Y',
56948 renderDate : function(dateVal){
56949 return dateVal.dateFormat(this.dateFormat);
56952 renderBool : function(bVal){
56953 return bVal ? 'true' : 'false';
56956 isCellEditable : function(colIndex, rowIndex){
56957 return colIndex == 1;
56960 getRenderer : function(col){
56962 this.renderCellDelegate : this.renderPropDelegate;
56965 renderProp : function(v){
56966 return this.getPropertyName(v);
56969 renderCell : function(val){
56971 if(val instanceof Date){
56972 rv = this.renderDate(val);
56973 }else if(typeof val == 'boolean'){
56974 rv = this.renderBool(val);
56976 return Roo.util.Format.htmlEncode(rv);
56979 getPropertyName : function(name){
56980 var pn = this.grid.propertyNames;
56981 return pn && pn[name] ? pn[name] : name;
56984 getCellEditor : function(colIndex, rowIndex){
56985 var p = this.store.getProperty(rowIndex);
56986 var n = p.data['name'], val = p.data['value'];
56988 if(typeof(this.grid.customEditors[n]) == 'string'){
56989 return this.editors[this.grid.customEditors[n]];
56991 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56992 return this.grid.customEditors[n];
56994 if(val instanceof Date){
56995 return this.editors['date'];
56996 }else if(typeof val == 'number'){
56997 return this.editors['number'];
56998 }else if(typeof val == 'boolean'){
56999 return this.editors['boolean'];
57001 return this.editors['string'];
57007 * @class Roo.grid.PropertyGrid
57008 * @extends Roo.grid.EditorGrid
57009 * This class represents the interface of a component based property grid control.
57010 * <br><br>Usage:<pre><code>
57011 var grid = new Roo.grid.PropertyGrid("my-container-id", {
57019 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57020 * The container MUST have some type of size defined for the grid to fill. The container will be
57021 * automatically set to position relative if it isn't already.
57022 * @param {Object} config A config object that sets properties on this grid.
57024 Roo.grid.PropertyGrid = function(container, config){
57025 config = config || {};
57026 var store = new Roo.grid.PropertyStore(this);
57027 this.store = store;
57028 var cm = new Roo.grid.PropertyColumnModel(this, store);
57029 store.store.sort('name', 'ASC');
57030 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57033 enableColLock:false,
57034 enableColumnMove:false,
57036 trackMouseOver: false,
57039 this.getGridEl().addClass('x-props-grid');
57040 this.lastEditRow = null;
57041 this.on('columnresize', this.onColumnResize, this);
57044 * @event beforepropertychange
57045 * Fires before a property changes (return false to stop?)
57046 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57047 * @param {String} id Record Id
57048 * @param {String} newval New Value
57049 * @param {String} oldval Old Value
57051 "beforepropertychange": true,
57053 * @event propertychange
57054 * Fires after a property changes
57055 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57056 * @param {String} id Record Id
57057 * @param {String} newval New Value
57058 * @param {String} oldval Old Value
57060 "propertychange": true
57062 this.customEditors = this.customEditors || {};
57064 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57067 * @cfg {Object} customEditors map of colnames=> custom editors.
57068 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57069 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57070 * false disables editing of the field.
57074 * @cfg {Object} propertyNames map of property Names to their displayed value
57077 render : function(){
57078 Roo.grid.PropertyGrid.superclass.render.call(this);
57079 this.autoSize.defer(100, this);
57082 autoSize : function(){
57083 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57085 this.view.fitColumns();
57089 onColumnResize : function(){
57090 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57094 * Sets the data for the Grid
57095 * accepts a Key => Value object of all the elements avaiable.
57096 * @param {Object} data to appear in grid.
57098 setSource : function(source){
57099 this.store.setSource(source);
57103 * Gets all the data from the grid.
57104 * @return {Object} data data stored in grid
57106 getSource : function(){
57107 return this.store.getSource();
57116 * @class Roo.grid.Calendar
57117 * @extends Roo.util.Grid
57118 * This class extends the Grid to provide a calendar widget
57119 * <br><br>Usage:<pre><code>
57120 var grid = new Roo.grid.Calendar("my-container-id", {
57123 selModel: mySelectionModel,
57124 autoSizeColumns: true,
57125 monitorWindowResize: false,
57126 trackMouseOver: true
57127 eventstore : real data store..
57133 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57134 * The container MUST have some type of size defined for the grid to fill. The container will be
57135 * automatically set to position relative if it isn't already.
57136 * @param {Object} config A config object that sets properties on this grid.
57138 Roo.grid.Calendar = function(container, config){
57139 // initialize the container
57140 this.container = Roo.get(container);
57141 this.container.update("");
57142 this.container.setStyle("overflow", "hidden");
57143 this.container.addClass('x-grid-container');
57145 this.id = this.container.id;
57147 Roo.apply(this, config);
57148 // check and correct shorthanded configs
57152 for (var r = 0;r < 6;r++) {
57155 for (var c =0;c < 7;c++) {
57159 if (this.eventStore) {
57160 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57161 this.eventStore.on('load',this.onLoad, this);
57162 this.eventStore.on('beforeload',this.clearEvents, this);
57166 this.dataSource = new Roo.data.Store({
57167 proxy: new Roo.data.MemoryProxy(rows),
57168 reader: new Roo.data.ArrayReader({}, [
57169 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57172 this.dataSource.load();
57173 this.ds = this.dataSource;
57174 this.ds.xmodule = this.xmodule || false;
57177 var cellRender = function(v,x,r)
57179 return String.format(
57180 '<div class="fc-day fc-widget-content"><div>' +
57181 '<div class="fc-event-container"></div>' +
57182 '<div class="fc-day-number">{0}</div>'+
57184 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57185 '</div></div>', v);
57190 this.colModel = new Roo.grid.ColumnModel( [
57192 xtype: 'ColumnModel',
57194 dataIndex : 'weekday0',
57196 renderer : cellRender
57199 xtype: 'ColumnModel',
57201 dataIndex : 'weekday1',
57203 renderer : cellRender
57206 xtype: 'ColumnModel',
57208 dataIndex : 'weekday2',
57209 header : 'Tuesday',
57210 renderer : cellRender
57213 xtype: 'ColumnModel',
57215 dataIndex : 'weekday3',
57216 header : 'Wednesday',
57217 renderer : cellRender
57220 xtype: 'ColumnModel',
57222 dataIndex : 'weekday4',
57223 header : 'Thursday',
57224 renderer : cellRender
57227 xtype: 'ColumnModel',
57229 dataIndex : 'weekday5',
57231 renderer : cellRender
57234 xtype: 'ColumnModel',
57236 dataIndex : 'weekday6',
57237 header : 'Saturday',
57238 renderer : cellRender
57241 this.cm = this.colModel;
57242 this.cm.xmodule = this.xmodule || false;
57246 //this.selModel = new Roo.grid.CellSelectionModel();
57247 //this.sm = this.selModel;
57248 //this.selModel.init(this);
57252 this.container.setWidth(this.width);
57256 this.container.setHeight(this.height);
57263 * The raw click event for the entire grid.
57264 * @param {Roo.EventObject} e
57269 * The raw dblclick event for the entire grid.
57270 * @param {Roo.EventObject} e
57274 * @event contextmenu
57275 * The raw contextmenu event for the entire grid.
57276 * @param {Roo.EventObject} e
57278 "contextmenu" : true,
57281 * The raw mousedown event for the entire grid.
57282 * @param {Roo.EventObject} e
57284 "mousedown" : true,
57287 * The raw mouseup event for the entire grid.
57288 * @param {Roo.EventObject} e
57293 * The raw mouseover event for the entire grid.
57294 * @param {Roo.EventObject} e
57296 "mouseover" : true,
57299 * The raw mouseout event for the entire grid.
57300 * @param {Roo.EventObject} e
57305 * The raw keypress event for the entire grid.
57306 * @param {Roo.EventObject} e
57311 * The raw keydown event for the entire grid.
57312 * @param {Roo.EventObject} e
57320 * Fires when a cell is clicked
57321 * @param {Grid} this
57322 * @param {Number} rowIndex
57323 * @param {Number} columnIndex
57324 * @param {Roo.EventObject} e
57326 "cellclick" : true,
57328 * @event celldblclick
57329 * Fires when a cell is double clicked
57330 * @param {Grid} this
57331 * @param {Number} rowIndex
57332 * @param {Number} columnIndex
57333 * @param {Roo.EventObject} e
57335 "celldblclick" : true,
57338 * Fires when a row is clicked
57339 * @param {Grid} this
57340 * @param {Number} rowIndex
57341 * @param {Roo.EventObject} e
57345 * @event rowdblclick
57346 * Fires when a row is double clicked
57347 * @param {Grid} this
57348 * @param {Number} rowIndex
57349 * @param {Roo.EventObject} e
57351 "rowdblclick" : true,
57353 * @event headerclick
57354 * Fires when a header is clicked
57355 * @param {Grid} this
57356 * @param {Number} columnIndex
57357 * @param {Roo.EventObject} e
57359 "headerclick" : true,
57361 * @event headerdblclick
57362 * Fires when a header cell is double clicked
57363 * @param {Grid} this
57364 * @param {Number} columnIndex
57365 * @param {Roo.EventObject} e
57367 "headerdblclick" : true,
57369 * @event rowcontextmenu
57370 * Fires when a row is right clicked
57371 * @param {Grid} this
57372 * @param {Number} rowIndex
57373 * @param {Roo.EventObject} e
57375 "rowcontextmenu" : true,
57377 * @event cellcontextmenu
57378 * Fires when a cell is right clicked
57379 * @param {Grid} this
57380 * @param {Number} rowIndex
57381 * @param {Number} cellIndex
57382 * @param {Roo.EventObject} e
57384 "cellcontextmenu" : true,
57386 * @event headercontextmenu
57387 * Fires when a header is right clicked
57388 * @param {Grid} this
57389 * @param {Number} columnIndex
57390 * @param {Roo.EventObject} e
57392 "headercontextmenu" : true,
57394 * @event bodyscroll
57395 * Fires when the body element is scrolled
57396 * @param {Number} scrollLeft
57397 * @param {Number} scrollTop
57399 "bodyscroll" : true,
57401 * @event columnresize
57402 * Fires when the user resizes a column
57403 * @param {Number} columnIndex
57404 * @param {Number} newSize
57406 "columnresize" : true,
57408 * @event columnmove
57409 * Fires when the user moves a column
57410 * @param {Number} oldIndex
57411 * @param {Number} newIndex
57413 "columnmove" : true,
57416 * Fires when row(s) start being dragged
57417 * @param {Grid} this
57418 * @param {Roo.GridDD} dd The drag drop object
57419 * @param {event} e The raw browser event
57421 "startdrag" : true,
57424 * Fires when a drag operation is complete
57425 * @param {Grid} this
57426 * @param {Roo.GridDD} dd The drag drop object
57427 * @param {event} e The raw browser event
57432 * Fires when dragged row(s) are dropped on a valid DD target
57433 * @param {Grid} this
57434 * @param {Roo.GridDD} dd The drag drop object
57435 * @param {String} targetId The target drag drop object
57436 * @param {event} e The raw browser event
57441 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57442 * @param {Grid} this
57443 * @param {Roo.GridDD} dd The drag drop object
57444 * @param {String} targetId The target drag drop object
57445 * @param {event} e The raw browser event
57450 * Fires when the dragged row(s) first cross another DD target while being dragged
57451 * @param {Grid} this
57452 * @param {Roo.GridDD} dd The drag drop object
57453 * @param {String} targetId The target drag drop object
57454 * @param {event} e The raw browser event
57456 "dragenter" : true,
57459 * Fires when the dragged row(s) leave another DD target while being dragged
57460 * @param {Grid} this
57461 * @param {Roo.GridDD} dd The drag drop object
57462 * @param {String} targetId The target drag drop object
57463 * @param {event} e The raw browser event
57468 * Fires when a row is rendered, so you can change add a style to it.
57469 * @param {GridView} gridview The grid view
57470 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57476 * Fires when the grid is rendered
57477 * @param {Grid} grid
57482 * Fires when a date is selected
57483 * @param {DatePicker} this
57484 * @param {Date} date The selected date
57488 * @event monthchange
57489 * Fires when the displayed month changes
57490 * @param {DatePicker} this
57491 * @param {Date} date The selected month
57493 'monthchange': true,
57495 * @event evententer
57496 * Fires when mouse over an event
57497 * @param {Calendar} this
57498 * @param {event} Event
57500 'evententer': true,
57502 * @event eventleave
57503 * Fires when the mouse leaves an
57504 * @param {Calendar} this
57507 'eventleave': true,
57509 * @event eventclick
57510 * Fires when the mouse click an
57511 * @param {Calendar} this
57514 'eventclick': true,
57516 * @event eventrender
57517 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57518 * @param {Calendar} this
57519 * @param {data} data to be modified
57521 'eventrender': true
57525 Roo.grid.Grid.superclass.constructor.call(this);
57526 this.on('render', function() {
57527 this.view.el.addClass('x-grid-cal');
57529 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57533 if (!Roo.grid.Calendar.style) {
57534 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57537 '.x-grid-cal .x-grid-col' : {
57538 height: 'auto !important',
57539 'vertical-align': 'top'
57541 '.x-grid-cal .fc-event-hori' : {
57552 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57554 * @cfg {Store} eventStore The store that loads events.
57559 activeDate : false,
57562 monitorWindowResize : false,
57565 resizeColumns : function() {
57566 var col = (this.view.el.getWidth() / 7) - 3;
57567 // loop through cols, and setWidth
57568 for(var i =0 ; i < 7 ; i++){
57569 this.cm.setColumnWidth(i, col);
57572 setDate :function(date) {
57574 Roo.log('setDate?');
57576 this.resizeColumns();
57577 var vd = this.activeDate;
57578 this.activeDate = date;
57579 // if(vd && this.el){
57580 // var t = date.getTime();
57581 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57582 // Roo.log('using add remove');
57584 // this.fireEvent('monthchange', this, date);
57586 // this.cells.removeClass("fc-state-highlight");
57587 // this.cells.each(function(c){
57588 // if(c.dateValue == t){
57589 // c.addClass("fc-state-highlight");
57590 // setTimeout(function(){
57591 // try{c.dom.firstChild.focus();}catch(e){}
57601 var days = date.getDaysInMonth();
57603 var firstOfMonth = date.getFirstDateOfMonth();
57604 var startingPos = firstOfMonth.getDay()-this.startDay;
57606 if(startingPos < this.startDay){
57610 var pm = date.add(Date.MONTH, -1);
57611 var prevStart = pm.getDaysInMonth()-startingPos;
57615 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57617 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57618 //this.cells.addClassOnOver('fc-state-hover');
57620 var cells = this.cells.elements;
57621 var textEls = this.textNodes;
57623 //Roo.each(cells, function(cell){
57624 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57627 days += startingPos;
57629 // convert everything to numbers so it's fast
57630 var day = 86400000;
57631 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57634 //Roo.log(prevStart);
57636 var today = new Date().clearTime().getTime();
57637 var sel = date.clearTime().getTime();
57638 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57639 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57640 var ddMatch = this.disabledDatesRE;
57641 var ddText = this.disabledDatesText;
57642 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57643 var ddaysText = this.disabledDaysText;
57644 var format = this.format;
57646 var setCellClass = function(cal, cell){
57648 //Roo.log('set Cell Class');
57650 var t = d.getTime();
57655 cell.dateValue = t;
57657 cell.className += " fc-today";
57658 cell.className += " fc-state-highlight";
57659 cell.title = cal.todayText;
57662 // disable highlight in other month..
57663 cell.className += " fc-state-highlight";
57668 //cell.className = " fc-state-disabled";
57669 cell.title = cal.minText;
57673 //cell.className = " fc-state-disabled";
57674 cell.title = cal.maxText;
57678 if(ddays.indexOf(d.getDay()) != -1){
57679 // cell.title = ddaysText;
57680 // cell.className = " fc-state-disabled";
57683 if(ddMatch && format){
57684 var fvalue = d.dateFormat(format);
57685 if(ddMatch.test(fvalue)){
57686 cell.title = ddText.replace("%0", fvalue);
57687 cell.className = " fc-state-disabled";
57691 if (!cell.initialClassName) {
57692 cell.initialClassName = cell.dom.className;
57695 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57700 for(; i < startingPos; i++) {
57701 cells[i].dayName = (++prevStart);
57702 Roo.log(textEls[i]);
57703 d.setDate(d.getDate()+1);
57705 //cells[i].className = "fc-past fc-other-month";
57706 setCellClass(this, cells[i]);
57711 for(; i < days; i++){
57712 intDay = i - startingPos + 1;
57713 cells[i].dayName = (intDay);
57714 d.setDate(d.getDate()+1);
57716 cells[i].className = ''; // "x-date-active";
57717 setCellClass(this, cells[i]);
57721 for(; i < 42; i++) {
57722 //textEls[i].innerHTML = (++extraDays);
57724 d.setDate(d.getDate()+1);
57725 cells[i].dayName = (++extraDays);
57726 cells[i].className = "fc-future fc-other-month";
57727 setCellClass(this, cells[i]);
57730 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57732 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57734 // this will cause all the cells to mis
57737 for (var r = 0;r < 6;r++) {
57738 for (var c =0;c < 7;c++) {
57739 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57743 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57744 for(i=0;i<cells.length;i++) {
57746 this.cells.elements[i].dayName = cells[i].dayName ;
57747 this.cells.elements[i].className = cells[i].className;
57748 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57749 this.cells.elements[i].title = cells[i].title ;
57750 this.cells.elements[i].dateValue = cells[i].dateValue ;
57756 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57757 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57759 ////if(totalRows != 6){
57760 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57761 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57764 this.fireEvent('monthchange', this, date);
57769 * Returns the grid's SelectionModel.
57770 * @return {SelectionModel}
57772 getSelectionModel : function(){
57773 if(!this.selModel){
57774 this.selModel = new Roo.grid.CellSelectionModel();
57776 return this.selModel;
57780 this.eventStore.load()
57786 findCell : function(dt) {
57787 dt = dt.clearTime().getTime();
57789 this.cells.each(function(c){
57790 //Roo.log("check " +c.dateValue + '?=' + dt);
57791 if(c.dateValue == dt){
57801 findCells : function(rec) {
57802 var s = rec.data.start_dt.clone().clearTime().getTime();
57804 var e= rec.data.end_dt.clone().clearTime().getTime();
57807 this.cells.each(function(c){
57808 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57810 if(c.dateValue > e){
57813 if(c.dateValue < s){
57822 findBestRow: function(cells)
57826 for (var i =0 ; i < cells.length;i++) {
57827 ret = Math.max(cells[i].rows || 0,ret);
57834 addItem : function(rec)
57836 // look for vertical location slot in
57837 var cells = this.findCells(rec);
57839 rec.row = this.findBestRow(cells);
57841 // work out the location.
57845 for(var i =0; i < cells.length; i++) {
57853 if (crow.start.getY() == cells[i].getY()) {
57855 crow.end = cells[i];
57871 for (var i = 0; i < cells.length;i++) {
57872 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57879 clearEvents: function() {
57881 if (!this.eventStore.getCount()) {
57884 // reset number of rows in cells.
57885 Roo.each(this.cells.elements, function(c){
57889 this.eventStore.each(function(e) {
57890 this.clearEvent(e);
57895 clearEvent : function(ev)
57898 Roo.each(ev.els, function(el) {
57899 el.un('mouseenter' ,this.onEventEnter, this);
57900 el.un('mouseleave' ,this.onEventLeave, this);
57908 renderEvent : function(ev,ctr) {
57910 ctr = this.view.el.select('.fc-event-container',true).first();
57914 this.clearEvent(ev);
57920 var cells = ev.cells;
57921 var rows = ev.rows;
57922 this.fireEvent('eventrender', this, ev);
57924 for(var i =0; i < rows.length; i++) {
57928 cls += ' fc-event-start';
57930 if ((i+1) == rows.length) {
57931 cls += ' fc-event-end';
57934 //Roo.log(ev.data);
57935 // how many rows should it span..
57936 var cg = this.eventTmpl.append(ctr,Roo.apply({
57939 }, ev.data) , true);
57942 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57943 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57944 cg.on('click', this.onEventClick, this, ev);
57948 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57949 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57952 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57953 cg.setWidth(ebox.right - sbox.x -2);
57957 renderEvents: function()
57959 // first make sure there is enough space..
57961 if (!this.eventTmpl) {
57962 this.eventTmpl = new Roo.Template(
57963 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57964 '<div class="fc-event-inner">' +
57965 '<span class="fc-event-time">{time}</span>' +
57966 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57968 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57976 this.cells.each(function(c) {
57977 //Roo.log(c.select('.fc-day-content div',true).first());
57978 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57981 var ctr = this.view.el.select('.fc-event-container',true).first();
57984 this.eventStore.each(function(ev){
57986 this.renderEvent(ev);
57990 this.view.layout();
57994 onEventEnter: function (e, el,event,d) {
57995 this.fireEvent('evententer', this, el, event);
57998 onEventLeave: function (e, el,event,d) {
57999 this.fireEvent('eventleave', this, el, event);
58002 onEventClick: function (e, el,event,d) {
58003 this.fireEvent('eventclick', this, el, event);
58006 onMonthChange: function () {
58010 onLoad: function () {
58012 //Roo.log('calendar onload');
58014 if(this.eventStore.getCount() > 0){
58018 this.eventStore.each(function(d){
58023 if (typeof(add.end_dt) == 'undefined') {
58024 Roo.log("Missing End time in calendar data: ");
58028 if (typeof(add.start_dt) == 'undefined') {
58029 Roo.log("Missing Start time in calendar data: ");
58033 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58034 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58035 add.id = add.id || d.id;
58036 add.title = add.title || '??';
58044 this.renderEvents();
58054 render : function ()
58058 if (!this.view.el.hasClass('course-timesheet')) {
58059 this.view.el.addClass('course-timesheet');
58061 if (this.tsStyle) {
58066 Roo.log(_this.grid.view.el.getWidth());
58069 this.tsStyle = Roo.util.CSS.createStyleSheet({
58070 '.course-timesheet .x-grid-row' : {
58073 '.x-grid-row td' : {
58074 'vertical-align' : 0
58076 '.course-edit-link' : {
58078 'text-overflow' : 'ellipsis',
58079 'overflow' : 'hidden',
58080 'white-space' : 'nowrap',
58081 'cursor' : 'pointer'
58086 '.de-act-sup-link' : {
58087 'color' : 'purple',
58088 'text-decoration' : 'line-through'
58092 'text-decoration' : 'line-through'
58094 '.course-timesheet .course-highlight' : {
58095 'border-top-style': 'dashed !important',
58096 'border-bottom-bottom': 'dashed !important'
58098 '.course-timesheet .course-item' : {
58099 'font-family' : 'tahoma, arial, helvetica',
58100 'font-size' : '11px',
58101 'overflow' : 'hidden',
58102 'padding-left' : '10px',
58103 'padding-right' : '10px',
58104 'padding-top' : '10px'
58112 monitorWindowResize : false,
58113 cellrenderer : function(v,x,r)
58118 xtype: 'CellSelectionModel',
58125 beforeload : function (_self, options)
58127 options.params = options.params || {};
58128 options.params._month = _this.monthField.getValue();
58129 options.params.limit = 9999;
58130 options.params['sort'] = 'when_dt';
58131 options.params['dir'] = 'ASC';
58132 this.proxy.loadResponse = this.loadResponse;
58134 //this.addColumns();
58136 load : function (_self, records, options)
58138 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58139 // if you click on the translation.. you can edit it...
58140 var el = Roo.get(this);
58141 var id = el.dom.getAttribute('data-id');
58142 var d = el.dom.getAttribute('data-date');
58143 var t = el.dom.getAttribute('data-time');
58144 //var id = this.child('span').dom.textContent;
58147 Pman.Dialog.CourseCalendar.show({
58151 productitem_active : id ? 1 : 0
58153 _this.grid.ds.load({});
58158 _this.panel.fireEvent('resize', [ '', '' ]);
58161 loadResponse : function(o, success, response){
58162 // this is overridden on before load..
58164 Roo.log("our code?");
58165 //Roo.log(success);
58166 //Roo.log(response)
58167 delete this.activeRequest;
58169 this.fireEvent("loadexception", this, o, response);
58170 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58175 result = o.reader.read(response);
58177 Roo.log("load exception?");
58178 this.fireEvent("loadexception", this, o, response, e);
58179 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58182 Roo.log("ready...");
58183 // loop through result.records;
58184 // and set this.tdate[date] = [] << array of records..
58186 Roo.each(result.records, function(r){
58188 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58189 _this.tdata[r.data.when_dt.format('j')] = [];
58191 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58194 //Roo.log(_this.tdata);
58196 result.records = [];
58197 result.totalRecords = 6;
58199 // let's generate some duumy records for the rows.
58200 //var st = _this.dateField.getValue();
58202 // work out monday..
58203 //st = st.add(Date.DAY, -1 * st.format('w'));
58205 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58207 var firstOfMonth = date.getFirstDayOfMonth();
58208 var days = date.getDaysInMonth();
58210 var firstAdded = false;
58211 for (var i = 0; i < result.totalRecords ; i++) {
58212 //var d= st.add(Date.DAY, i);
58215 for(var w = 0 ; w < 7 ; w++){
58216 if(!firstAdded && firstOfMonth != w){
58223 var dd = (d > 0 && d < 10) ? "0"+d : d;
58224 row['weekday'+w] = String.format(
58225 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58226 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58228 date.format('Y-m-')+dd
58231 if(typeof(_this.tdata[d]) != 'undefined'){
58232 Roo.each(_this.tdata[d], function(r){
58236 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58237 if(r.parent_id*1>0){
58238 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58241 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58242 deactive = 'de-act-link';
58245 row['weekday'+w] += String.format(
58246 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58248 r.product_id_name, //1
58249 r.when_dt.format('h:ia'), //2
58259 // only do this if something added..
58261 result.records.push(_this.grid.dataSource.reader.newRow(row));
58265 // push it twice. (second one with an hour..
58269 this.fireEvent("load", this, o, o.request.arg);
58270 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58272 sortInfo : {field: 'when_dt', direction : 'ASC' },
58274 xtype: 'HttpProxy',
58277 url : baseURL + '/Roo/Shop_course.php'
58280 xtype: 'JsonReader',
58297 'name': 'parent_id',
58301 'name': 'product_id',
58305 'name': 'productitem_id',
58323 click : function (_self, e)
58325 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58326 sd.setMonth(sd.getMonth()-1);
58327 _this.monthField.setValue(sd.format('Y-m-d'));
58328 _this.grid.ds.load({});
58334 xtype: 'Separator',
58338 xtype: 'MonthField',
58341 render : function (_self)
58343 _this.monthField = _self;
58344 // _this.monthField.set today
58346 select : function (combo, date)
58348 _this.grid.ds.load({});
58351 value : (function() { return new Date(); })()
58354 xtype: 'Separator',
58360 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58370 click : function (_self, e)
58372 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58373 sd.setMonth(sd.getMonth()+1);
58374 _this.monthField.setValue(sd.format('Y-m-d'));
58375 _this.grid.ds.load({});
58388 * Ext JS Library 1.1.1
58389 * Copyright(c) 2006-2007, Ext JS, LLC.
58391 * Originally Released Under LGPL - original licence link has changed is not relivant.
58394 * <script type="text/javascript">
58398 * @class Roo.LoadMask
58399 * A simple utility class for generically masking elements while loading data. If the element being masked has
58400 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58401 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58402 * element's UpdateManager load indicator and will be destroyed after the initial load.
58404 * Create a new LoadMask
58405 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58406 * @param {Object} config The config object
58408 Roo.LoadMask = function(el, config){
58409 this.el = Roo.get(el);
58410 Roo.apply(this, config);
58412 this.store.on('beforeload', this.onBeforeLoad, this);
58413 this.store.on('load', this.onLoad, this);
58414 this.store.on('loadexception', this.onLoadException, this);
58415 this.removeMask = false;
58417 var um = this.el.getUpdateManager();
58418 um.showLoadIndicator = false; // disable the default indicator
58419 um.on('beforeupdate', this.onBeforeLoad, this);
58420 um.on('update', this.onLoad, this);
58421 um.on('failure', this.onLoad, this);
58422 this.removeMask = true;
58426 Roo.LoadMask.prototype = {
58428 * @cfg {Boolean} removeMask
58429 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58430 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58433 * @cfg {String} msg
58434 * The text to display in a centered loading message box (defaults to 'Loading...')
58436 msg : 'Loading...',
58438 * @cfg {String} msgCls
58439 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58441 msgCls : 'x-mask-loading',
58444 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58450 * Disables the mask to prevent it from being displayed
58452 disable : function(){
58453 this.disabled = true;
58457 * Enables the mask so that it can be displayed
58459 enable : function(){
58460 this.disabled = false;
58463 onLoadException : function()
58465 Roo.log(arguments);
58467 if (typeof(arguments[3]) != 'undefined') {
58468 Roo.MessageBox.alert("Error loading",arguments[3]);
58472 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58473 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58482 this.el.unmask(this.removeMask);
58485 onLoad : function()
58487 this.el.unmask(this.removeMask);
58491 onBeforeLoad : function(){
58492 if(!this.disabled){
58493 this.el.mask(this.msg, this.msgCls);
58498 destroy : function(){
58500 this.store.un('beforeload', this.onBeforeLoad, this);
58501 this.store.un('load', this.onLoad, this);
58502 this.store.un('loadexception', this.onLoadException, this);
58504 var um = this.el.getUpdateManager();
58505 um.un('beforeupdate', this.onBeforeLoad, this);
58506 um.un('update', this.onLoad, this);
58507 um.un('failure', this.onLoad, this);
58512 * Ext JS Library 1.1.1
58513 * Copyright(c) 2006-2007, Ext JS, LLC.
58515 * Originally Released Under LGPL - original licence link has changed is not relivant.
58518 * <script type="text/javascript">
58523 * @class Roo.XTemplate
58524 * @extends Roo.Template
58525 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58527 var t = new Roo.XTemplate(
58528 '<select name="{name}">',
58529 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58533 // then append, applying the master template values
58536 * Supported features:
58541 {a_variable} - output encoded.
58542 {a_variable.format:("Y-m-d")} - call a method on the variable
58543 {a_variable:raw} - unencoded output
58544 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58545 {a_variable:this.method_on_template(...)} - call a method on the template object.
58550 <tpl for="a_variable or condition.."></tpl>
58551 <tpl if="a_variable or condition"></tpl>
58552 <tpl exec="some javascript"></tpl>
58553 <tpl name="named_template"></tpl> (experimental)
58555 <tpl for="."></tpl> - just iterate the property..
58556 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58560 Roo.XTemplate = function()
58562 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58569 Roo.extend(Roo.XTemplate, Roo.Template, {
58572 * The various sub templates
58577 * basic tag replacing syntax
58580 * // you can fake an object call by doing this
58584 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58587 * compile the template
58589 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58592 compile: function()
58596 s = ['<tpl>', s, '</tpl>'].join('');
58598 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58599 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58600 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58601 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58602 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58607 while(true == !!(m = s.match(re))){
58608 var forMatch = m[0].match(nameRe),
58609 ifMatch = m[0].match(ifRe),
58610 execMatch = m[0].match(execRe),
58611 namedMatch = m[0].match(namedRe),
58616 name = forMatch && forMatch[1] ? forMatch[1] : '';
58619 // if - puts fn into test..
58620 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58622 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58627 // exec - calls a function... returns empty if true is returned.
58628 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58630 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58638 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58639 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58640 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58643 var uid = namedMatch ? namedMatch[1] : id;
58647 id: namedMatch ? namedMatch[1] : id,
58654 s = s.replace(m[0], '');
58656 s = s.replace(m[0], '{xtpl'+ id + '}');
58661 for(var i = tpls.length-1; i >= 0; --i){
58662 this.compileTpl(tpls[i]);
58663 this.tpls[tpls[i].id] = tpls[i];
58665 this.master = tpls[tpls.length-1];
58669 * same as applyTemplate, except it's done to one of the subTemplates
58670 * when using named templates, you can do:
58672 * var str = pl.applySubTemplate('your-name', values);
58675 * @param {Number} id of the template
58676 * @param {Object} values to apply to template
58677 * @param {Object} parent (normaly the instance of this object)
58679 applySubTemplate : function(id, values, parent)
58683 var t = this.tpls[id];
58687 if(t.test && !t.test.call(this, values, parent)){
58691 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58692 Roo.log(e.toString());
58698 if(t.exec && t.exec.call(this, values, parent)){
58702 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58703 Roo.log(e.toString());
58708 var vs = t.target ? t.target.call(this, values, parent) : values;
58709 parent = t.target ? values : parent;
58710 if(t.target && vs instanceof Array){
58712 for(var i = 0, len = vs.length; i < len; i++){
58713 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58715 return buf.join('');
58717 return t.compiled.call(this, vs, parent);
58719 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58720 Roo.log(e.toString());
58721 Roo.log(t.compiled);
58726 compileTpl : function(tpl)
58728 var fm = Roo.util.Format;
58729 var useF = this.disableFormats !== true;
58730 var sep = Roo.isGecko ? "+" : ",";
58731 var undef = function(str) {
58732 Roo.log("Property not found :" + str);
58736 var fn = function(m, name, format, args)
58738 //Roo.log(arguments);
58739 args = args ? args.replace(/\\'/g,"'") : args;
58740 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58741 if (typeof(format) == 'undefined') {
58742 format= 'htmlEncode';
58744 if (format == 'raw' ) {
58748 if(name.substr(0, 4) == 'xtpl'){
58749 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58752 // build an array of options to determine if value is undefined..
58754 // basically get 'xxxx.yyyy' then do
58755 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58756 // (function () { Roo.log("Property not found"); return ''; })() :
58761 Roo.each(name.split('.'), function(st) {
58762 lookfor += (lookfor.length ? '.': '') + st;
58763 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58766 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58769 if(format && useF){
58771 args = args ? ',' + args : "";
58773 if(format.substr(0, 5) != "this."){
58774 format = "fm." + format + '(';
58776 format = 'this.call("'+ format.substr(5) + '", ';
58780 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58784 // called with xxyx.yuu:(test,test)
58786 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58788 // raw.. - :raw modifier..
58789 return "'"+ sep + udef_st + name + ")"+sep+"'";
58793 // branched to use + in gecko and [].join() in others
58795 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58796 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58799 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58800 body.push(tpl.body.replace(/(\r\n|\n)/g,
58801 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58802 body.push("'].join('');};};");
58803 body = body.join('');
58806 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58808 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58814 applyTemplate : function(values){
58815 return this.master.compiled.call(this, values, {});
58816 //var s = this.subs;
58819 apply : function(){
58820 return this.applyTemplate.apply(this, arguments);
58825 Roo.XTemplate.from = function(el){
58826 el = Roo.getDom(el);
58827 return new Roo.XTemplate(el.value || el.innerHTML);